diff --git a/Cargo.lock b/Cargo.lock index 7eafd170..3d362600 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 4 [[package]] name = "ab_glyph" -version = "0.2.29" +version = "0.2.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3672c180e71eeaaac3a541fbbc5f5ad4def8b747c595ad30d674e43049f7b0" +checksum = "1e0f4f6fbdc5ee39f2ede9f5f3ec79477271a6d6a2baff22310d51736bda6cea" dependencies = [ "ab_glyph_rasterizer", "owned_ttf_parser", @@ -14,24 +14,24 @@ dependencies = [ [[package]] name = "ab_glyph_rasterizer" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" +checksum = "b2187590a23ab1e3df8681afdf0987c48504d80291f002fcdb651f0ef5e25169" [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "ahash" -version = "0.8.11" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", - "getrandom", + "getrandom 0.3.3", "once_cell", "version_check", "zerocopy", @@ -48,9 +48,12 @@ dependencies = [ [[package]] name = "aligned-vec" -version = "0.5.0" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1" +checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b" +dependencies = [ + "equator", +] [[package]] name = "android-activity" @@ -59,7 +62,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" dependencies = [ "android-properties", - "bitflags 2.8.0", + "bitflags 2.9.1", "cc", "cesu8", "jni", @@ -105,9 +108,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.18" +version = "0.6.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" dependencies = [ "anstyle", "anstyle-parse", @@ -120,44 +123,44 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" [[package]] name = "anstyle-parse" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" dependencies = [ "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.7" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" dependencies = [ "anstyle", - "once_cell", + "once_cell_polyfill", "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.95" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] name = "approx" @@ -191,7 +194,7 @@ checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.104", ] [[package]] @@ -240,9 +243,9 @@ dependencies = [ [[package]] name = "async-channel" -version = "2.3.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" dependencies = [ "concurrent-queue", "event-listener-strategy", @@ -257,7 +260,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06" dependencies = [ "async-lock", - "autocfg 1.4.0", + "autocfg 1.5.0", "blocking", "futures-lite 1.13.0", ] @@ -300,20 +303,20 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78" dependencies = [ - "autocfg 1.4.0", + "autocfg 1.5.0", ] [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "av1-grain" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6678909d8c5d46a42abcf571271e15fdbc0a225e3646cf23762cd415046c78bf" +checksum = "4f3efb2ca85bc610acfa917b5aaa36f3fcbebed5b3182d7f877b02531c4b80c8" dependencies = [ "anyhow", "arrayvec", @@ -325,9 +328,9 @@ dependencies = [ [[package]] name = "avif-serialize" -version = "0.8.2" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e335041290c43101ca215eed6f43ec437eb5a42125573f600fc3fa42b9bddd62" +checksum = "2ea8ef51aced2b9191c08197f55450d830876d9933f8f48a429b354f1d496b42" dependencies = [ "arrayvec", ] @@ -367,9 +370,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.8.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" dependencies = [ "serde", ] @@ -397,11 +400,11 @@ dependencies = [ [[package]] name = "blocking" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" dependencies = [ - "async-channel 2.3.1", + "async-channel 2.5.0", "async-task", "futures-io", "futures-lite 2.6.0", @@ -410,34 +413,34 @@ dependencies = [ [[package]] name = "built" -version = "0.7.5" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c360505aed52b7ec96a3636c3f039d99103c37d1d9b4f7a8c743d3ea9ffcd03b" +checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b" [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "bytemuck" -version = "1.22.0" +version = "1.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540" +checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.8.1" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a" +checksum = "7ecc273b49b3205b83d648f0690daa588925572cc5063745bfe547fe7ec8e1a1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.104", ] [[package]] @@ -454,9 +457,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.9.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "calloop" @@ -464,10 +467,10 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", "log", "polling", - "rustix", + "rustix 0.38.44", "slab", "thiserror 1.0.69", ] @@ -479,16 +482,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20" dependencies = [ "calloop", - "rustix", + "rustix 0.38.44", "wayland-backend", "wayland-client", ] [[package]] name = "cc" -version = "1.2.10" +version = "1.2.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229" +checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362" dependencies = [ "jobserver", "libc", @@ -513,9 +516,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "cfg_aliases" @@ -537,9 +540,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.40" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ "android-tzdata", "iana-time-zone", @@ -566,9 +569,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.26" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8eb5e908ef3a6efbe1ed62520fb7287959888c88485abe072543190ecc66783" +checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" dependencies = [ "clap_builder", "clap_derive", @@ -576,9 +579,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.26" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96b01801b5fc6a0a232407abc821660c9c6d25a1cafc0d4f85f29fb8d9afc121" +checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" dependencies = [ "anstream", "anstyle", @@ -588,21 +591,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.24" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c" +checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.104", ] [[package]] name = "clap_lex" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" [[package]] name = "cloudabi" @@ -631,9 +634,9 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "colorchoice" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "combine" @@ -729,20 +732,24 @@ dependencies = [ [[package]] name = "craballoc" version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a545335ac6c410d6dfa81b094e758c2a94b87fb8317a53fb7bb14ee8687062f" dependencies = [ "async-channel 1.9.0", "bytemuck", "crabslab", "log", "rustc-hash 1.1.0", - "snafu 0.8.5", + "snafu 0.8.6", "tracing", "wgpu", ] [[package]] name = "crabslab" -version = "0.6.4" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe77aba0fb1ad6ddb4d30744bfc61e1420a9cc1fa981b3556cc423506df9450" dependencies = [ "crabslab-derive", "futures-lite 1.13.0", @@ -753,10 +760,12 @@ dependencies = [ [[package]] name = "crabslab-derive" version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32554318ca91eb0c2c6a05659ec2cd1627fd44142d54547bb3d0aa7405a979b2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.104", ] [[package]] @@ -770,9 +779,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.14" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" dependencies = [ "crossbeam-utils", ] @@ -810,9 +819,9 @@ checksum = "0dc013e70da3bfe5b552de26a1f34ecf67d61ea811251d2bf75c1324a1ecb425" [[package]] name = "crunchy" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "ctor" @@ -821,14 +830,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" dependencies = [ "quote", - "syn 2.0.96", + "syn 2.0.104", ] [[package]] name = "cursor-icon" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" +checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f" [[package]] name = "dagga" @@ -850,23 +859,23 @@ checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" [[package]] name = "dirs" -version = "5.0.1" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" dependencies = [ "dirs-sys", ] [[package]] name = "dirs-sys" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.48.0", + "windows-sys 0.60.2", ] [[package]] @@ -892,9 +901,9 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" [[package]] name = "document-features" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6969eaabd2421f8a2775cfd2471a2b634372b4a25d41e3bd647b79912850a0" +checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" dependencies = [ "litrs", ] @@ -913,15 +922,15 @@ checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" [[package]] name = "dpi" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" +checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" [[package]] name = "dwrote" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70182709525a3632b2ba96b6569225467b18ecb4a77f46d255f713a6bebf05fd" +checksum = "bfe1f192fcce01590bd8d839aca53ce0d11d803bf291b2a6c4ad925a8f0024be" dependencies = [ "lazy_static", "libc", @@ -931,9 +940,9 @@ dependencies = [ [[package]] name = "either" -version = "1.13.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "env_logger" @@ -948,20 +957,40 @@ dependencies = [ "termcolor", ] +[[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.104", +] + [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.10" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -992,9 +1021,9 @@ dependencies = [ [[package]] name = "event-listener-strategy" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" dependencies = [ "event-listener 5.4.0", "pin-project-lite", @@ -1004,13 +1033,13 @@ dependencies = [ name = "example" version = "0.1.0" dependencies = [ - "clap 4.5.26", + "clap 4.5.40", "craballoc", "env_logger", "futures-lite 1.13.0", "gltf", "icosahedron", - "image 0.25.5", + "image 0.25.6", "img-diff", "lazy_static", "loading-bytes", @@ -1111,9 +1140,9 @@ checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" [[package]] name = "flate2" -version = "1.0.35" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" dependencies = [ "crc32fast", "miniz_oxide", @@ -1133,17 +1162,17 @@ checksum = "8bf7cc16383c4b8d58b9905a8509f02926ce3058053c056376248d958c9df1e8" [[package]] name = "foldhash" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "font-kit" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b64b34f4efd515f905952d91bc185039863705592c0c53ae6d979805dd154520" +checksum = "2c7e611d49285d4c4b2e1727b72cf05353558885cc5252f93707b845dfcaf3d3" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", "byteorder", "core-foundation", "core-graphics", @@ -1180,7 +1209,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.104", ] [[package]] @@ -1255,13 +1284,25 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "libc", - "wasi", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", ] [[package]] @@ -1276,9 +1317,9 @@ dependencies = [ [[package]] name = "gif" -version = "0.13.1" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2" +checksum = "4ae047235e33e2829703574b54fdec96bfbad892062d97fed2f76022287de61b" dependencies = [ "color_quant", "weezl", @@ -1297,9 +1338,9 @@ dependencies = [ [[package]] name = "glam" -version = "0.29.2" +version = "0.30.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc46dd3ec48fdd8e693a98d2b8bafae273a2d54c1de02a2a7e3d57d501f39677" +checksum = "50a99dbe56b72736564cfa4b85bf9a33079f16ae8b74983ab06af3b1a3696b11" dependencies = [ "libm", ] @@ -1325,7 +1366,7 @@ dependencies = [ "base64", "byteorder", "gltf-json", - "image 0.25.5", + "image 0.25.6", "lazy_static", "serde_json", "urlencoding", @@ -1340,7 +1381,7 @@ dependencies = [ "inflections", "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.104", ] [[package]] @@ -1366,14 +1407,14 @@ dependencies = [ [[package]] name = "glyph_brush" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225e5bd28cddb97578e31da78ae24eff4d6611523fb03b73f300d511461834c0" +checksum = "0060f4ed4ef64a5876d9836d7d6c9ed43a463f3ca431682bec1c326064c8c93e" dependencies = [ "glyph_brush_draw_cache", "glyph_brush_layout", - "ordered-float", - "rustc-hash 2.1.0", + "ordered-float 5.0.0", + "rustc-hash 2.1.1", "twox-hash", ] @@ -1388,7 +1429,7 @@ dependencies = [ "crossbeam-deque", "linked-hash-map", "rayon", - "rustc-hash 2.1.0", + "rustc-hash 2.1.1", ] [[package]] @@ -1408,7 +1449,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", "gpu-alloc-types", ] @@ -1418,7 +1459,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", ] [[package]] @@ -1435,11 +1476,11 @@ dependencies = [ [[package]] name = "gpu-descriptor" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf29e94d6d243368b7a56caa16bc213e4f9f8ed38c4d9557069527b5d5281ca" +checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", "gpu-descriptor-types", "hashbrown", ] @@ -1450,14 +1491,14 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", ] [[package]] name = "half" -version = "2.4.1" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" dependencies = [ "cfg-if", "crunchy", @@ -1465,9 +1506,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" dependencies = [ "foldhash", ] @@ -1495,9 +1536,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.4.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "hexf-parse" @@ -1507,9 +1548,9 @@ checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" [[package]] name = "humantime" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" [[package]] name = "iana-time-zone" @@ -1523,7 +1564,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core", + "windows-core 0.61.2", ] [[package]] @@ -1565,15 +1606,15 @@ dependencies = [ [[package]] name = "image" -version = "0.25.5" +version = "0.25.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd6f44aed642f18953a158afeb30206f4d50da59fbc66ecb53c66488de73563b" +checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a" dependencies = [ "bytemuck", "byteorder-lite", "color_quant", "exr", - "gif 0.13.1", + "gif 0.13.3", "image-webp", "num-traits", "png", @@ -1588,9 +1629,9 @@ dependencies = [ [[package]] name = "image-webp" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b77d01e822461baa8409e156015a1d91735549f0f2c17691bd2d996bef238f7f" +checksum = "f6970fe7a5300b4b42e62c52efa0187540a5bef546c60edaf554ef595d2e6f0b" dependencies = [ "byteorder-lite", "quick-error", @@ -1601,7 +1642,7 @@ name = "img-diff" version = "0.1.0" dependencies = [ "glam", - "image 0.25.5", + "image 0.25.6", "snafu 0.7.5", ] @@ -1613,9 +1654,9 @@ checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408" [[package]] name = "indexmap" -version = "2.7.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" dependencies = [ "equivalent", "hashbrown", @@ -1644,18 +1685,18 @@ checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.104", ] [[package]] name = "is-terminal" -version = "0.4.13" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" dependencies = [ - "hermit-abi 0.4.0", + "hermit-abi 0.5.2", "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1675,9 +1716,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jni" @@ -1703,18 +1744,19 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ + "getrandom 0.3.3", "libc", ] [[package]] name = "jpeg-decoder" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" +checksum = "00810f1d8b74be64b13dbf3db89ac67740615d6c891f0e7b6179326533011a07" [[package]] name = "js-sys" @@ -1757,15 +1799,15 @@ checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" [[package]] name = "libc" -version = "0.2.169" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "libfuzzer-sys" -version = "0.4.8" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b9569d2f74e257076d8c6bfa73fb505b46b851e51ddaecc825944aa3bed17fa" +checksum = "5037190e1f70cbeef565bd267599242926f724d3b8a9f510fd7e0b540cfa4404" dependencies = [ "arbitrary", "cc", @@ -1773,12 +1815,12 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.53.2", ] [[package]] @@ -1789,13 +1831,13 @@ checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "libredox" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +checksum = "1580801010e535496706ba011c15f8532df6b42297d2e471fec38ceadd8c0638" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", "libc", - "redox_syscall 0.5.8", + "redox_syscall 0.5.13", ] [[package]] @@ -1810,6 +1852,12 @@ version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" +[[package]] +name = "linux-raw-sys" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" + [[package]] name = "litrs" version = "0.4.1" @@ -1823,7 +1871,7 @@ dependencies = [ "async-fs", "js-sys", "send_wrapper", - "snafu 0.8.5", + "snafu 0.8.6", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -1831,19 +1879,19 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ - "autocfg 1.4.0", + "autocfg 1.5.0", "scopeguard", ] [[package]] name = "log" -version = "0.4.25" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "loop9" @@ -1887,9 +1935,9 @@ dependencies = [ [[package]] name = "lyon_path" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e0b8aec2f58586f6eef237985b9a9b7cb3a3aff4417c575075cf95bf925252e" +checksum = "0047f508cd7a85ad6bad9518f68cce7b1bf6b943fb71f6da0ee3bc1e8cb75f25" dependencies = [ "lyon_geom", "num-traits", @@ -1927,9 +1975,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "memmap2" @@ -1946,7 +1994,7 @@ version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f569fb946490b5743ad69813cb19629130ce9374034abe31614a36402d18f99e" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", "block", "core-graphics-types", "foreign-types", @@ -1973,9 +2021,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.8.3" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", "simd-adler32", @@ -1989,7 +2037,7 @@ checksum = "e380993072e52eef724eddfcde0ed013b0c023c3f0417336ed041aa9f076994e" dependencies = [ "arrayvec", "bit-set", - "bitflags 2.8.0", + "bitflags 2.9.1", "cfg_aliases", "codespan-reporting", "hexf-parse", @@ -2000,7 +2048,7 @@ dependencies = [ "spirv", "strum", "termcolor", - "thiserror 2.0.11", + "thiserror 2.0.12", "unicode-xid", ] @@ -2010,7 +2058,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", "jni-sys", "log", "ndk-sys 0.6.0+11769913", @@ -2083,7 +2131,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.104", ] [[package]] @@ -2112,29 +2160,30 @@ version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ - "autocfg 1.4.0", + "autocfg 1.5.0", "libm", ] [[package]] name = "num_enum" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" dependencies = [ "num_enum_derive", + "rustversion", ] [[package]] name = "num_enum_derive" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.104", ] [[package]] @@ -2168,7 +2217,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", "block2", "libc", "objc2", @@ -2184,7 +2233,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", "block2", "objc2", "objc2-core-location", @@ -2208,7 +2257,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", "block2", "objc2", "objc2-foundation", @@ -2240,9 +2289,9 @@ dependencies = [ [[package]] name = "objc2-encode" -version = "4.0.3" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7891e71393cd1f227313c9379a26a584ff3d7e6e7159e988851f0934c993f0f8" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" [[package]] name = "objc2-foundation" @@ -2250,7 +2299,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", "block2", "dispatch", "libc", @@ -2275,7 +2324,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", "block2", "objc2", "objc2-foundation", @@ -2287,7 +2336,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", "block2", "objc2", "objc2-foundation", @@ -2310,7 +2359,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", "block2", "objc2", "objc2-cloud-kit", @@ -2342,7 +2391,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", "block2", "objc2", "objc2-core-location", @@ -2351,9 +2400,15 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.2" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" [[package]] name = "option-ext" @@ -2379,6 +2434,15 @@ dependencies = [ "num-traits", ] +[[package]] +name = "ordered-float" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2c1f9f56e534ac6a9b8a4600bdf0f530fb393b5f393e7b4d03489c3cf0c3f01" +dependencies = [ + "num-traits", +] + [[package]] name = "owned_ttf_parser" version = "0.25.0" @@ -2396,9 +2460,9 @@ checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", "parking_lot_core", @@ -2406,13 +2470,13 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.8", + "redox_syscall 0.5.13", "smallvec", "windows-targets 0.52.6", ] @@ -2441,9 +2505,9 @@ dependencies = [ [[package]] name = "pathfinder_simd" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cf07ef4804cfa9aea3b04a7bbdd5a40031dbb6b4f2cbaf2b011666c80c5b4f2" +checksum = "bf9027960355bf3afff9841918474a81a5f972ac6d226d518060bba758b5ad57" dependencies = [ "rustc_version", ] @@ -2466,22 +2530,22 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.8" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e2ec53ad785f4d35dac0adea7f7dc6f1bb277ad84a680c7afefeae05d1f5916" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.8" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56a66c0c55993aa927429d0f8a0abfd74f084e4d9c192cffed01e418d83eefb" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.104", ] [[package]] @@ -2503,9 +2567,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "plotters" @@ -2568,24 +2632,24 @@ dependencies = [ [[package]] name = "polling" -version = "3.7.4" +version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" +checksum = "b53a684391ad002dd6a596ceb6c74fd004fdce75f4be2e3f615068abbea5fd50" dependencies = [ "cfg-if", "concurrent-queue", - "hermit-abi 0.4.0", + "hermit-abi 0.5.2", "pin-project-lite", - "rustix", + "rustix 1.0.7", "tracing", "windows-sys 0.59.0", ] [[package]] name = "ppv-lite86" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ "zerocopy", ] @@ -2608,39 +2672,39 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.2.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" dependencies = [ "toml_edit", ] [[package]] name = "proc-macro2" -version = "1.0.93" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] [[package]] name = "profiling" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d" +checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" dependencies = [ "profiling-procmacros", ] [[package]] name = "profiling-procmacros" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30" +checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b" dependencies = [ "quote", - "syn 2.0.96", + "syn 2.0.104", ] [[package]] @@ -2660,22 +2724,28 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] name = "quick-xml" -version = "0.36.2" +version = "0.37.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe" +checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" dependencies = [ "memchr", ] [[package]] name = "quote" -version = "1.0.38" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" 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 = "rand" version = "0.6.5" @@ -2706,6 +2776,16 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "rand" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", +] + [[package]] name = "rand_chacha" version = "0.1.1" @@ -2726,6 +2806,16 @@ dependencies = [ "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.3", +] + [[package]] name = "rand_core" version = "0.3.1" @@ -2747,7 +2837,16 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.16", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.3", ] [[package]] @@ -2855,9 +2954,9 @@ dependencies = [ [[package]] name = "ravif" -version = "0.11.11" +version = "0.11.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2413fd96bd0ea5cdeeb37eaf446a22e6ed7b981d792828721e74ded1980a45c6" +checksum = "5825c26fddd16ab9f515930d49028a630efec172e903483c94796cfe31893e6b" dependencies = [ "avif-serialize", "imgref", @@ -2914,22 +3013,22 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.8" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" +checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", ] [[package]] name = "redox_users" -version = "0.4.6" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" dependencies = [ - "getrandom", + "getrandom 0.2.16", "libredox", - "thiserror 1.0.69", + "thiserror 2.0.12", ] [[package]] @@ -2988,7 +3087,7 @@ dependencies = [ "gltf", "half", "icosahedron", - "image 0.25.5", + "image 0.25.6", "img-diff", "log", "metal", @@ -3001,7 +3100,7 @@ dependencies = [ "rustc-hash 1.1.0", "serde", "serde_json", - "snafu 0.8.5", + "snafu 0.8.6", "spirv-std", "ttf-parser 0.20.0", "wgpu", @@ -3030,7 +3129,7 @@ dependencies = [ "env_logger", "futures-lite 1.13.0", "glyph_brush", - "image 0.25.5", + "image 0.25.6", "img-diff", "loading-bytes", "log", @@ -3038,15 +3137,15 @@ dependencies = [ "pretty_assertions", "renderling", "rustc-hash 1.1.0", - "snafu 0.8.5", + "snafu 0.8.6", "wgpu", ] [[package]] name = "rgb" -version = "0.8.50" +version = "0.8.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" +checksum = "a457e416a0f90d246a4c3288bd7a25b2304ca727f253f95be383dd17af56be8f" [[package]] name = "rustc-hash" @@ -3056,9 +3155,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc-hash" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] name = "rustc_version" @@ -3071,28 +3170,41 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.43" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.9.1", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", "errno", "libc", - "linux-raw-sys", + "linux-raw-sys 0.9.4", "windows-sys 0.59.0", ] [[package]] name = "rustversion" -version = "1.0.19" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "same-file" @@ -3151,29 +3263,29 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.217" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.217" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.104", ] [[package]] name = "serde_json" -version = "1.0.135" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa", "memchr", @@ -3183,9 +3295,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" dependencies = [ "serde", ] @@ -3213,12 +3325,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg 1.4.0", -] +checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" [[package]] name = "slotmap" @@ -3231,9 +3340,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.2" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "smithay-client-toolkit" @@ -3241,14 +3350,14 @@ version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", "calloop", "calloop-wayland-source", "cursor-icon", "libc", "log", "memmap2", - "rustix", + "rustix 0.38.44", "thiserror 1.0.69", "wayland-backend", "wayland-client", @@ -3281,11 +3390,11 @@ dependencies = [ [[package]] name = "snafu" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "223891c85e2a29c3fe8fb900c1fae5e69c2e42415e3177752e8718475efa5019" +checksum = "320b01e011bf8d5d7a4a4a4be966d9160968935849c83b918827f6a435e7f627" dependencies = [ - "snafu-derive 0.8.5", + "snafu-derive 0.8.6", ] [[package]] @@ -3302,14 +3411,14 @@ dependencies = [ [[package]] name = "snafu-derive" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c3c6b7927ffe7ecaa769ee0e3994da3b8cafc8f444578982c83ecb161af917" +checksum = "1961e2ef424c1424204d3a5d6975f934f56b6d50ff5732382d84ebf460e147f7" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.104", ] [[package]] @@ -3318,16 +3427,17 @@ version = "0.3.0+sdk-1.3.268.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", ] [[package]] name = "spirv-std" version = "0.9.0" -source = "git+https://github.com/LegNeato/rust-gpu.git?rev=16b61ce#16b61ce9c871afa7d305d0b35e165585bde77546" +source = "git+https://github.com/LegNeato/rust-gpu.git?rev=425328a#425328a3ac7f1f18db914d24b3d4754bf13bb7ac" dependencies = [ "bitflags 1.3.2", "glam", + "libm", "num-traits", "spirv-std-macros", "spirv-std-types", @@ -3336,18 +3446,18 @@ dependencies = [ [[package]] name = "spirv-std-macros" version = "0.9.0" -source = "git+https://github.com/LegNeato/rust-gpu.git?rev=16b61ce#16b61ce9c871afa7d305d0b35e165585bde77546" +source = "git+https://github.com/LegNeato/rust-gpu.git?rev=425328a#425328a3ac7f1f18db914d24b3d4754bf13bb7ac" dependencies = [ "proc-macro2", "quote", "spirv-std-types", - "syn 2.0.96", + "syn 2.0.104", ] [[package]] name = "spirv-std-types" version = "0.9.0" -source = "git+https://github.com/LegNeato/rust-gpu.git?rev=16b61ce#16b61ce9c871afa7d305d0b35e165585bde77546" +source = "git+https://github.com/LegNeato/rust-gpu.git?rev=425328a#425328a3ac7f1f18db914d24b3d4754bf13bb7ac" [[package]] name = "static_assertions" @@ -3392,7 +3502,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.96", + "syn 2.0.104", ] [[package]] @@ -3408,9 +3518,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.96" +version = "2.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" dependencies = [ "proc-macro2", "quote", @@ -3465,11 +3575,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.11" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ - "thiserror-impl 2.0.11", + "thiserror-impl 2.0.12", ] [[package]] @@ -3480,18 +3590,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.104", ] [[package]] name = "thiserror-impl" -version = "2.0.11" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.104", ] [[package]] @@ -3532,9 +3642,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.19" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned", @@ -3544,18 +3654,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.22" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap", "serde", @@ -3577,20 +3687,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.28" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.104", ] [[package]] name = "tracing-core" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", ] @@ -3609,18 +3719,18 @@ checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" [[package]] name = "twox-hash" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7b17f197b3050ba473acf9181f7b1d3b66d1cf7356c6cc57886662276e65908" +checksum = "8b907da542cbced5261bd3256de1b3a1bf340a3d37f93425a07362a1d687de56" dependencies = [ - "rand 0.8.5", + "rand 0.9.1", ] [[package]] name = "unicode-ident" -version = "1.0.14" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-segmentation" @@ -3654,9 +3764,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "v_frame" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6f32aaa24bacd11e488aa9ba66369c7cd514885742c9fe08cfe85884db3e92b" +checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2" dependencies = [ "aligned-vec", "num-traits", @@ -3699,9 +3809,18 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] [[package]] name = "wasm-bindgen" @@ -3725,7 +3844,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.104", "wasm-bindgen-shared", ] @@ -3760,7 +3879,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.104", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3795,18 +3914,18 @@ checksum = "17d5042cc5fa009658f9a7333ef24291b1291a25b6382dd68862a7f3b969f69b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.104", ] [[package]] name = "wayland-backend" -version = "0.3.7" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "056535ced7a150d45159d3a8dc30f91a2e2d588ca0b23f70e56033622b8016f6" +checksum = "fe770181423e5fc79d3e2a7f4410b7799d5aab1de4372853de3c6aa13ca24121" dependencies = [ "cc", "downcast-rs", - "rustix", + "rustix 0.38.44", "scoped-tls", "smallvec", "wayland-sys", @@ -3814,12 +3933,12 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.31.7" +version = "0.31.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66249d3fc69f76fd74c82cc319300faa554e9d865dab1f7cd66cc20db10b280" +checksum = "978fa7c67b0847dbd6a9f350ca2569174974cd4082737054dbb7fbb79d7d9a61" dependencies = [ - "bitflags 2.8.0", - "rustix", + "bitflags 2.9.1", + "rustix 0.38.44", "wayland-backend", "wayland-scanner", ] @@ -3830,29 +3949,29 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", "cursor-icon", "wayland-backend", ] [[package]] name = "wayland-cursor" -version = "0.31.7" +version = "0.31.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b08bc3aafdb0035e7fe0fdf17ba0c09c268732707dca4ae098f60cb28c9e4c" +checksum = "a65317158dec28d00416cb16705934070aef4f8393353d41126c54264ae0f182" dependencies = [ - "rustix", + "rustix 0.38.44", "wayland-client", "xcursor", ] [[package]] name = "wayland-protocols" -version = "0.32.5" +version = "0.32.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd0ade57c4e6e9a8952741325c30bf82f4246885dca8bf561898b86d0c1f58e" +checksum = "779075454e1e9a521794fed15886323ea0feda3f8b0fc1390f5398141310422a" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", "wayland-backend", "wayland-client", "wayland-scanner", @@ -3860,11 +3979,11 @@ dependencies = [ [[package]] name = "wayland-protocols-plasma" -version = "0.3.5" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b31cab548ee68c7eb155517f2212049dc151f7cd7910c2b66abfd31c3ee12bd" +checksum = "4fd38cdad69b56ace413c6bcc1fbf5acc5e2ef4af9d5f8f1f9570c0c83eae175" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", "wayland-backend", "wayland-client", "wayland-protocols", @@ -3873,11 +3992,11 @@ dependencies = [ [[package]] name = "wayland-protocols-wlr" -version = "0.3.5" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "782e12f6cd923c3c316130d56205ebab53f55d6666b7faddfad36cecaeeb4022" +checksum = "1cb6cdc73399c0e06504c437fe3cf886f25568dd5454473d565085b36d6a8bbf" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", "wayland-backend", "wayland-client", "wayland-protocols", @@ -3886,9 +4005,9 @@ dependencies = [ [[package]] name = "wayland-scanner" -version = "0.31.5" +version = "0.31.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597f2001b2e5fc1121e3d5b9791d3e78f05ba6bfa4641053846248e3a13661c3" +checksum = "896fdafd5d28145fce7958917d69f2fd44469b1d4e861cb5961bcbeebc6d1484" dependencies = [ "proc-macro2", "quick-xml", @@ -3897,9 +4016,9 @@ dependencies = [ [[package]] name = "wayland-sys" -version = "0.31.5" +version = "0.31.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efa8ac0d8e8ed3e3b5c9fc92c7881406a268e11555abe36493efabe649a29e09" +checksum = "dbcebb399c77d5aa9fa5db874806ee7b4eba4e73650948e8f93963f128896615" dependencies = [ "dlib", "log", @@ -3929,18 +4048,18 @@ dependencies = [ [[package]] name = "weezl" -version = "0.1.8" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" +checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3" [[package]] name = "wgpu" -version = "24.0.1" +version = "24.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47f55718f85c2fa756edffa0e7f0e0a60aba463d1362b57e23123c58f035e4b6" +checksum = "6b0b3436f0729f6cdf2e6e9201f3d39dc95813fad61d826c1ed07918b4539353" dependencies = [ "arrayvec", - "bitflags 2.8.0", + "bitflags 2.9.1", "cfg_aliases", "document-features", "js-sys", @@ -3961,13 +4080,13 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "24.0.0" +version = "24.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82a39b8842dc9ffcbe34346e3ab6d496b32a47f6497e119d762c97fcaae3cb37" +checksum = "7f0aa306497a238d169b9dc70659105b4a096859a34894544ca81719242e1499" dependencies = [ "arrayvec", "bit-vec", - "bitflags 2.8.0", + "bitflags 2.9.1", "bytemuck", "cfg_aliases", "document-features", @@ -3980,22 +4099,22 @@ dependencies = [ "raw-window-handle", "rustc-hash 1.1.0", "smallvec", - "thiserror 2.0.11", + "thiserror 2.0.12", "wgpu-hal", "wgpu-types", ] [[package]] name = "wgpu-hal" -version = "24.0.0" +version = "24.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a782e5056b060b0b4010881d1decddd059e44f2ecd01e2db2971b48ad3627e5" +checksum = "f112f464674ca69f3533248508ee30cb84c67cf06c25ff6800685f5e0294e259" dependencies = [ "android_system_properties", "arrayvec", "ash", "bit-set", - "bitflags 2.8.0", + "bitflags 2.9.1", "block", "bytemuck", "cfg_aliases", @@ -4015,7 +4134,7 @@ dependencies = [ "ndk-sys 0.5.0+25.2.9519653", "objc", "once_cell", - "ordered-float", + "ordered-float 4.6.0", "parking_lot", "profiling", "range-alloc", @@ -4023,12 +4142,12 @@ dependencies = [ "renderdoc-sys", "rustc-hash 1.1.0", "smallvec", - "thiserror 2.0.11", + "thiserror 2.0.12", "wasm-bindgen", "web-sys", "wgpu-types", "windows", - "windows-core", + "windows-core 0.58.0", ] [[package]] @@ -4037,7 +4156,7 @@ version = "24.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50ac044c0e76c03a0378e7786ac505d010a873665e2d51383dcff8dd227dc69c" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", "js-sys", "log", "web-sys", @@ -4080,7 +4199,7 @@ version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" dependencies = [ - "windows-core", + "windows-core 0.58.0", "windows-targets 0.52.6", ] @@ -4090,13 +4209,26 @@ version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" dependencies = [ - "windows-implement", - "windows-interface", - "windows-result", - "windows-strings", + "windows-implement 0.58.0", + "windows-interface 0.58.0", + "windows-result 0.2.0", + "windows-strings 0.1.0", "windows-targets 0.52.6", ] +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement 0.60.0", + "windows-interface 0.59.1", + "windows-link", + "windows-result 0.3.4", + "windows-strings 0.4.2", +] + [[package]] name = "windows-implement" version = "0.58.0" @@ -4105,7 +4237,18 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.104", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", ] [[package]] @@ -4116,14 +4259,25 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.104", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", ] [[package]] name = "windows-link" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" [[package]] name = "windows-result" @@ -4134,32 +4288,41 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-strings" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ - "windows-result", + "windows-result 0.2.0", "windows-targets 0.52.6", ] [[package]] -name = "windows-sys" -version = "0.45.0" +name = "windows-strings" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ - "windows-targets 0.42.2", + "windows-link", ] [[package]] name = "windows-sys" -version = "0.48.0" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "windows-targets 0.48.5", + "windows-targets 0.42.2", ] [[package]] @@ -4180,6 +4343,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.2", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -4219,13 +4391,29 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -4244,6 +4432,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -4262,6 +4456,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -4280,12 +4480,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -4304,6 +4516,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -4322,6 +4540,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -4340,6 +4564,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -4358,16 +4588,22 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + [[package]] name = "winit" -version = "0.30.8" +version = "0.30.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5d74280aabb958072864bff6cfbcf9025cf8bfacdde5e32b5e12920ef703b0f" +checksum = "a4409c10174df8779dc29a4788cac85ed84024ccbc1743b776b21a520ee1aaf4" dependencies = [ "ahash", "android-activity", "atomic-waker", - "bitflags 2.8.0", + "bitflags 2.9.1", "block2", "bytemuck", "calloop", @@ -4390,7 +4626,7 @@ dependencies = [ "pin-project", "raw-window-handle", "redox_syscall 0.4.1", - "rustix", + "rustix 0.38.44", "sctk-adwaita", "smithay-client-toolkit", "smol_str", @@ -4412,9 +4648,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.24" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" +checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" dependencies = [ "memchr", ] @@ -4428,6 +4664,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags 2.9.1", +] + [[package]] name = "x11-dl" version = "2.21.0" @@ -4450,7 +4695,7 @@ dependencies = [ "libc", "libloading", "once_cell", - "rustix", + "rustix 0.38.44", "x11rb-protocol", ] @@ -4462,9 +4707,9 @@ checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" [[package]] name = "xcursor" -version = "0.3.8" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef33da6b1660b4ddbfb3aef0ade110c8b8a781a3b6382fa5f2b5b040fd55f61" +checksum = "bec9e4a500ca8864c5b47b8b482a73d62e4237670e5b5f1d6b9e3cae50f28f2b" [[package]] name = "xi-unicode" @@ -4478,7 +4723,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.1", "dlib", "log", "once_cell", @@ -4493,15 +4738,15 @@ checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" [[package]] name = "xml-rs" -version = "0.8.25" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5b940ebc25896e71dd073bad2dbaa2abfe97b0a391415e22ad1326d9c54e3c4" +checksum = "a62ce76d9b56901b19a74f19431b0d8b3bc7ca4ad685a746dfd78ca8f4fc6bda" [[package]] name = "xtask" version = "0.1.0" dependencies = [ - "clap 4.5.26", + "clap 4.5.40", "env_logger", "log", "renderling_build", @@ -4526,23 +4771,22 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.35" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" dependencies = [ - "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.35" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.104", ] [[package]] @@ -4562,9 +4806,9 @@ dependencies = [ [[package]] name = "zune-jpeg" -version = "0.4.14" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99a5bab8d7dedf81405c4bb1f2b83ea057643d9cb28778cea9eecddeedd2e028" +checksum = "2c9e525af0a6a658e031e95f14b7f889976b74a11ba0eca5a5fc9ac8a1c43a6a" dependencies = [ "zune-core", ] diff --git a/Cargo.toml b/Cargo.toml index 66e32ba5..2962df03 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,14 +21,14 @@ async-channel = "1.8" bytemuck = { version = "1.19.0", features = ["derive"] } cfg_aliases = "0.2" clap = { version = "4.5.23", features = ["derive"] } -craballoc = { version = "0.2.0", path = "../crabslab/crates/craballoc" } -crabslab = { version = "0.6.3", default-features = false, path = "../crabslab/crates/crabslab" } +craballoc = { version = "0.2.0" } +crabslab = { version = "0.6.5", default-features = false } plotters = "0.3.7" ctor = "0.2.2" dagga = "0.2.1" env_logger = "0.10.0" futures-lite = "1.13" -glam = { version = "0.29", default-features = false } +glam = { version = "0.30", default-features = false } gltf = { version = "1.4,1", features = ["KHR_lights_punctual", "KHR_materials_unlit", "KHR_materials_emissive_strength", "extras", "extensions"] } image = "0.25" log = "0.4" @@ -41,7 +41,8 @@ serde = {version = "1.0", features = ["derive"]} serde_json = "1.0.117" send_wrapper = "0.6.0" snafu = "0.8" -spirv-std = { git = "https://github.com/LegNeato/rust-gpu.git", rev = "16b61ce" } +spirv-std = { git = "https://github.com/LegNeato/rust-gpu.git", rev = "425328a" } +spirv-std-macros = { git = "https://github.com/LegNeato/rust-gpu.git", rev = "425328a" } syn = { version = "2.0.49", features = ["full", "extra-traits", "parsing"] } tracing = "0.1.41" wasm-bindgen = "0.2" @@ -62,4 +63,4 @@ opt-level = 3 opt-level = 3 [patch.crates-io] -spirv-std = { git = "https://github.com/LegNeato/rust-gpu.git", rev = "16b61ce" } +spirv-std = { git = "https://github.com/LegNeato/rust-gpu.git", rev = "425328a" } diff --git a/blender/pedestal.blend b/blender/pedestal.blend new file mode 100644 index 00000000..1709e437 Binary files /dev/null and b/blender/pedestal.blend differ diff --git a/crates/renderling/shaders/atlas-atlas_blit_vertex.spv b/crates/renderling/shaders/atlas-atlas_blit_vertex.spv index 45409ff2..9cb3260a 100644 Binary files a/crates/renderling/shaders/atlas-atlas_blit_vertex.spv and b/crates/renderling/shaders/atlas-atlas_blit_vertex.spv differ diff --git a/crates/renderling/shaders/bloom-bloom_downsample_fragment.spv b/crates/renderling/shaders/bloom-bloom_downsample_fragment.spv index c581fd34..d6660d64 100644 Binary files a/crates/renderling/shaders/bloom-bloom_downsample_fragment.spv and b/crates/renderling/shaders/bloom-bloom_downsample_fragment.spv differ diff --git a/crates/renderling/shaders/bloom-bloom_mix_fragment.spv b/crates/renderling/shaders/bloom-bloom_mix_fragment.spv index 125e4e3a..792d9178 100644 Binary files a/crates/renderling/shaders/bloom-bloom_mix_fragment.spv and b/crates/renderling/shaders/bloom-bloom_mix_fragment.spv differ diff --git a/crates/renderling/shaders/bloom-bloom_upsample_fragment.spv b/crates/renderling/shaders/bloom-bloom_upsample_fragment.spv index 01e78d0a..b8f8b0ce 100644 Binary files a/crates/renderling/shaders/bloom-bloom_upsample_fragment.spv and b/crates/renderling/shaders/bloom-bloom_upsample_fragment.spv differ diff --git a/crates/renderling/shaders/convolution-brdf_lut_convolution_fragment.spv b/crates/renderling/shaders/convolution-brdf_lut_convolution_fragment.spv index 758e616b..cc9214b5 100644 Binary files a/crates/renderling/shaders/convolution-brdf_lut_convolution_fragment.spv and b/crates/renderling/shaders/convolution-brdf_lut_convolution_fragment.spv differ diff --git a/crates/renderling/shaders/convolution-prefilter_environment_cubemap_fragment.spv b/crates/renderling/shaders/convolution-prefilter_environment_cubemap_fragment.spv index 5ded01d2..91a72716 100644 Binary files a/crates/renderling/shaders/convolution-prefilter_environment_cubemap_fragment.spv and b/crates/renderling/shaders/convolution-prefilter_environment_cubemap_fragment.spv differ diff --git a/crates/renderling/shaders/convolution-prefilter_environment_cubemap_vertex.spv b/crates/renderling/shaders/convolution-prefilter_environment_cubemap_vertex.spv index a8e990ab..0ef1b2ce 100644 Binary files a/crates/renderling/shaders/convolution-prefilter_environment_cubemap_vertex.spv and b/crates/renderling/shaders/convolution-prefilter_environment_cubemap_vertex.spv differ diff --git a/crates/renderling/shaders/cull-compute_culling.spv b/crates/renderling/shaders/cull-compute_culling.spv index 307fa570..c35bcb52 100644 Binary files a/crates/renderling/shaders/cull-compute_culling.spv and b/crates/renderling/shaders/cull-compute_culling.spv differ diff --git a/crates/renderling/shaders/debug-debug_overlay_fragment.spv b/crates/renderling/shaders/debug-debug_overlay_fragment.spv index a7d8734b..2bb57a93 100644 Binary files a/crates/renderling/shaders/debug-debug_overlay_fragment.spv and b/crates/renderling/shaders/debug-debug_overlay_fragment.spv differ diff --git a/crates/renderling/shaders/ibl-diffuse_irradiance-di_convolution_fragment.spv b/crates/renderling/shaders/ibl-diffuse_irradiance-di_convolution_fragment.spv index 0843942c..f3df3c56 100644 Binary files a/crates/renderling/shaders/ibl-diffuse_irradiance-di_convolution_fragment.spv and b/crates/renderling/shaders/ibl-diffuse_irradiance-di_convolution_fragment.spv differ diff --git a/crates/renderling/shaders/light-light_tiling_compute_tiles.spv b/crates/renderling/shaders/light-light_tiling_compute_tiles.spv index 5fc27659..991ded08 100644 Binary files a/crates/renderling/shaders/light-light_tiling_compute_tiles.spv and b/crates/renderling/shaders/light-light_tiling_compute_tiles.spv differ diff --git a/crates/renderling/shaders/light-light_tiling_compute_tiles_multisampled.spv b/crates/renderling/shaders/light-light_tiling_compute_tiles_multisampled.spv index 11ca70bd..95589e35 100644 Binary files a/crates/renderling/shaders/light-light_tiling_compute_tiles_multisampled.spv and b/crates/renderling/shaders/light-light_tiling_compute_tiles_multisampled.spv differ diff --git a/crates/renderling/shaders/light-light_tiling_depth_pre_pass.spv b/crates/renderling/shaders/light-light_tiling_depth_pre_pass.spv index e6b236e4..93607337 100644 Binary files a/crates/renderling/shaders/light-light_tiling_depth_pre_pass.spv and b/crates/renderling/shaders/light-light_tiling_depth_pre_pass.spv differ diff --git a/crates/renderling/shaders/light-shadow_mapping_vertex.spv b/crates/renderling/shaders/light-shadow_mapping_vertex.spv index 0e9598cf..164781ad 100644 Binary files a/crates/renderling/shaders/light-shadow_mapping_vertex.spv and b/crates/renderling/shaders/light-shadow_mapping_vertex.spv differ diff --git a/crates/renderling/shaders/skybox-skybox_cubemap_fragment.spv b/crates/renderling/shaders/skybox-skybox_cubemap_fragment.spv index d3c61bab..792aea28 100644 Binary files a/crates/renderling/shaders/skybox-skybox_cubemap_fragment.spv and b/crates/renderling/shaders/skybox-skybox_cubemap_fragment.spv differ diff --git a/crates/renderling/shaders/skybox-skybox_cubemap_vertex.spv b/crates/renderling/shaders/skybox-skybox_cubemap_vertex.spv index 9b2b8b0c..99a6daa4 100644 Binary files a/crates/renderling/shaders/skybox-skybox_cubemap_vertex.spv and b/crates/renderling/shaders/skybox-skybox_cubemap_vertex.spv differ diff --git a/crates/renderling/shaders/skybox-skybox_equirectangular_fragment.spv b/crates/renderling/shaders/skybox-skybox_equirectangular_fragment.spv index 6c0cb4bd..3617b009 100644 Binary files a/crates/renderling/shaders/skybox-skybox_equirectangular_fragment.spv and b/crates/renderling/shaders/skybox-skybox_equirectangular_fragment.spv differ diff --git a/crates/renderling/shaders/skybox-skybox_vertex.spv b/crates/renderling/shaders/skybox-skybox_vertex.spv index 8316eb73..91552532 100644 Binary files a/crates/renderling/shaders/skybox-skybox_vertex.spv and b/crates/renderling/shaders/skybox-skybox_vertex.spv differ diff --git a/crates/renderling/shaders/stage-renderlet_fragment.spv b/crates/renderling/shaders/stage-renderlet_fragment.spv index 08b1392e..9c586ded 100644 Binary files a/crates/renderling/shaders/stage-renderlet_fragment.spv and b/crates/renderling/shaders/stage-renderlet_fragment.spv differ diff --git a/crates/renderling/shaders/stage-renderlet_vertex.spv b/crates/renderling/shaders/stage-renderlet_vertex.spv index 79c7c3ba..aa115403 100644 Binary files a/crates/renderling/shaders/stage-renderlet_vertex.spv and b/crates/renderling/shaders/stage-renderlet_vertex.spv differ diff --git a/crates/renderling/shaders/tonemapping-tonemapping_fragment.spv b/crates/renderling/shaders/tonemapping-tonemapping_fragment.spv index c982db1f..cf72d613 100644 Binary files a/crates/renderling/shaders/tonemapping-tonemapping_fragment.spv and b/crates/renderling/shaders/tonemapping-tonemapping_fragment.spv differ diff --git a/crates/renderling/src/light.rs b/crates/renderling/src/light.rs index ad855371..2b1da99e 100644 --- a/crates/renderling/src/light.rs +++ b/crates/renderling/src/light.rs @@ -16,7 +16,7 @@ use crate::{ bvol::{Aabb, BoundingSphere}, cubemap::{CubemapDescriptor, CubemapFaceDirection}, geometry::GeometryDescriptor, - math::{Fetch, IsSampler, IsVector, Sample2dArray}, + math::{Fetch, IsAtomicSlab, IsSampler, IsVector, Sample2dArray}, stage::Renderlet, transform::Transform, }; @@ -223,6 +223,7 @@ impl SpotLightCalculation { let frag_to_light = light_position - frag_position; let frag_to_light_distance = frag_to_light.length(); if frag_to_light_distance == 0.0 { + crate::println!("frag_to_light_distance: {frag_to_light_distance}"); return Self::default(); } let frag_to_light = frag_to_light.alt_norm_or_zero(); @@ -433,6 +434,16 @@ pub enum LightStyle { Spot = 2, } +impl core::fmt::Display for LightStyle { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + LightStyle::Directional => f.write_str("directional"), + LightStyle::Point => f.write_str("point"), + LightStyle::Spot => f.write_str("spot"), + } + } +} + impl SlabItem for LightStyle { const SLAB_SIZE: usize = { 1 }; @@ -804,11 +815,6 @@ impl IsDepth for DepthImage2dMultisampled { type Texture = Image!(2D, type=f32, sampled, depth, multisampled=true); } -fn screen_space_to_clip_space(resolution: Vec2, screen_point: Vec2) -> Vec2 { - let normalized = screen_point / resolution; - Vec2::new(normalized.x, 1.0 - normalized.y) * 2.0 - 1.0 -} - /// A tile of screen space used to cull lights. #[derive(Clone, Copy, Default, SlabItem, core::fmt::Debug)] #[offsets] @@ -882,8 +888,10 @@ impl LightTilingInvocation { } /// The index of the fragment within its tile. - // - // TODO: verify this is correct + /// + /// 1. The fragment position is determined from the global invocation index. + /// 2. The fragment's relative xy position within the tile is determined. + /// 3. The index of the fragment's tile position is calculated and returned. fn frag_index(&self) -> usize { // The fragment's xy position within its tile let frag_tile = self.frag_pos() % LightTilingDescriptor::TILE_SIZE; @@ -894,12 +902,12 @@ impl LightTilingInvocation { /// Compute the min and max depth of one fragment/invocation for light tiling. /// /// Returns the **indices** of the min and max depths of the tile. - fn compute_min_and_max_depth( + fn compute_min_and_max_depth( &self, depth_texture: &impl Fetch, _lighting_slab: &[u32], - tiling_slab: &mut [u32], - ) -> (usize, usize) { + tiling_slab: &mut S, + ) -> (Id, Id) { let frag_pos = self.frag_pos(); // Depth frag value at the fragment position let frag_depth: f32 = depth_texture.fetch(frag_pos).x; @@ -913,24 +921,18 @@ impl LightTilingInvocation { let tiling_desc = tiling_slab.read_unchecked(Id::::new(0)); // index of the tile's min depth atomic value in the tiling slab let tile_id = tiling_desc.tiles_array.at(tile_index); - let min_depth_index = (tile_id + LightTile::OFFSET_OF_DEPTH_MIN).index(); + let min_depth_index = tile_id + LightTile::OFFSET_OF_DEPTH_MIN; // index of the tile's max depth atomic value in the tiling slab - let max_depth_index = (tile_id + LightTile::OFFSET_OF_DEPTH_MAX).index(); + let max_depth_index = tile_id + LightTile::OFFSET_OF_DEPTH_MAX; - let _prev_min_depth = unsafe { - spirv_std::arch::atomic_u_min::< - u32, + let _prev_min_depth = tiling_slab.atomic_u_min::< { spirv_std::memory::Scope::Workgroup as u32 }, { spirv_std::memory::Semantics::WORKGROUP_MEMORY.bits() }, - >(&mut tiling_slab[min_depth_index], frag_depth_u32) - }; - let _prev_max_depth = unsafe { - spirv_std::arch::atomic_u_max::< - u32, + >(min_depth_index, frag_depth_u32); + let _prev_max_depth = tiling_slab.atomic_u_max::< { spirv_std::memory::Scope::Workgroup as u32 }, - { spirv_std::memory::Semantics::WORKGROUP_MEMORY.bits() }, - >(&mut tiling_slab[max_depth_index], frag_depth_u32) - }; + { spirv_std::memory::Semantics::WORKGROUP_MEMORY.bits() } + >(max_depth_index, frag_depth_u32); (min_depth_index, max_depth_index) } @@ -949,7 +951,7 @@ impl LightTilingInvocation { && frag_pos.y % LightTilingDescriptor::TILE_SIZE.y == 0 } - fn clear_tiles(&self, tiling_slab: &mut [u32]) { + fn clear_tiles(&self, tiling_slab: &mut S) { if self.frag_pos_is_tile_corner() { // only continue if this is the invocation in the top-left of the tile, as // we only need one invocation per tile. @@ -969,23 +971,26 @@ impl LightTilingInvocation { // index of the tile's max depth atomic value in the tiling slab let max_depth_index = (tile_id + LightTile::OFFSET_OF_DEPTH_MAX).index(); - tiling_slab[min_depth_index] = u32::MAX; - tiling_slab[max_depth_index] = 0; + tiling_slab.write(min_depth_index.into(), &u32::MAX); + tiling_slab.write(max_depth_index.into(), &0u32); } } - fn compute_light_lists( + // The difficulty here is that in SPIRV we can access `tiling_slab` atomically without wrapping it + // in a type, but on CPU we must pass an array of (something like) `AtomicU32`. I'm not sure how to + // model this interaction to test it on the CPU. I think I'll need something like `AtomicSlab`. + fn compute_light_lists( &self, geometry_slab: &[u32], lighting_slab: &[u32], - tiling_slab: &mut [u32], - min_depth_index: usize, - max_depth_index: usize, + tiling_slab: &mut S, + min_depth_index: Id, + max_depth_index: Id, ) { // At this point we know the depth has been computed, so now we can construct the tile's frustum // in clip space. - let depth_min_u32 = tiling_slab[min_depth_index]; - let depth_max_u32 = tiling_slab[max_depth_index]; + let depth_min_u32 = tiling_slab.read_unchecked(min_depth_index); + let depth_max_u32 = tiling_slab.read_unchecked(max_depth_index); let depth_min = depth_min_u32 as f32 / u32::MAX as f32; let depth_max = depth_max_u32 as f32 / u32::MAX as f32; @@ -1011,7 +1016,7 @@ impl LightTilingInvocation { ); let camera = geometry_slab.read_unchecked(camera_id); - let frag_light_index = self.frag_index(); + let index_of_invocation_in_tile = self.frag_index(); // List of all analytical lights in the scene let analytical_lights_array = lighting_slab.read_unchecked( Id::::new(0) @@ -1023,58 +1028,68 @@ impl LightTilingInvocation { // Each invocation will calculate a few lights' contribution to the tile, until all lights // have been visited for step in 0..(analytical_lights_array.len() / count_of_fragments_in_one_tile) + 1 { - let light_index = step * count_of_fragments_in_one_tile + frag_light_index; + let light_index = step * count_of_fragments_in_one_tile + index_of_invocation_in_tile; if light_index >= analytical_lights_array.len() { break; } let light_id = lighting_slab.read_unchecked(analytical_lights_array.at(light_index)); let light = lighting_slab.read_unchecked(light_id); let transform = geometry_slab.read(light.transform_id); - // let should_add = match light.light_type { - // LightStyle::Directional => true, - // LightStyle::Point => { - // let point_light = lighting_slab.read(light.into_point_id()); - // let center = Mat4::from(transform).transform_point3(point_light.position); - // let radius = point_light.radius_of_illumination(1.0); - // let sphere = BoundingSphere::new(center, radius); - // let aabb_ss = sphere.project_onto_viewport(&camera, resolution); - // aabb_ss.intersects_aabb(&tile_aabb_ss) - // } - // LightStyle::Spot => false, - // }; - - // if should_add { - let next_index = unsafe { - spirv_std::arch::atomic_i_increment::< - u32, + let should_add = match light.light_type { + LightStyle::Directional => true, + LightStyle::Point => { + let point_light = lighting_slab.read(light.into_point_id()); + crate::println!("transform: {transform:?}"); + if transform.translation.x.is_nan() { + crate::println!("step: {step}"); + crate::println!("light_index: {light_index}"); + crate::println!("light_id: {light_id:?}"); + crate::println!( + "analytical_lights_array.len: {}", + analytical_lights_array.len() + ); + crate::println!("transform_id: {:?}", light.transform_id); + } + let center = Mat4::from(transform).transform_point3(point_light.position); + let radius = point_light.radius_of_illumination(1.0); + let sphere = BoundingSphere::new(center, radius); + let aabb_ss = sphere.project_onto_viewport(&camera, resolution); + aabb_ss.intersects_aabb(&tile_aabb_ss) + } + LightStyle::Spot => false, + }; + + if should_add { + let next_index = tiling_slab.atomic_i_increment::< { spirv_std::memory::Scope::Workgroup as u32 }, { spirv_std::memory::Semantics::WORKGROUP_MEMORY.bits() }, - >(&mut tiling_slab[(next_light_id).index()]) - }; - if next_index as usize >= tile_lights_array.len() { - break; + >(next_light_id); + if next_index as usize >= tile_lights_array.len() { + break; + } + tiling_slab.write(next_index.into(), &light_id); } - // tiling_slab[next_index as usize] = light_id.inner(); - // } } } // TODO: think about breaking the light tiling "compute tiles" shader up into sub-shaders. // It would also be possible to join or parallelize some of this work with frustum culling // and occlusion culling. - fn compute_tiles( + fn compute_tiles( &self, depth_texture: &impl Fetch, geometry_slab: &[u32], lighting_slab: &[u32], - tiling_slab: &mut [u32], + tiling_slab: &mut S, ) { self.clear_tiles(tiling_slab); + #[cfg(gpu)] unsafe { spirv_std::arch::workgroup_memory_barrier_with_group_sync(); } let (min_index, max_index) = self.compute_min_and_max_depth(depth_texture, lighting_slab, tiling_slab); + #[cfg(gpu)] unsafe { spirv_std::arch::workgroup_memory_barrier_with_group_sync(); } @@ -1205,31 +1220,6 @@ mod test { ); } - #[test] - fn screen_space_to_clip_space_sanity() { - let resolution = Vec2::new(800.0, 600.0); - let tl = Vec2::new(0.0, 0.0); - let tr = Vec2::new(resolution.x, 0.0); - let bl = Vec2::new(0.0, resolution.y); - let br = resolution; - assert_eq!( - Vec2::new(-1.0, 1.0), - screen_space_to_clip_space(resolution, tl) - ); - assert_eq!( - Vec2::new(1.0, 1.0), - screen_space_to_clip_space(resolution, tr) - ); - assert_eq!( - Vec2::new(-1.0, -1.0), - screen_space_to_clip_space(resolution, bl) - ); - assert_eq!( - Vec2::new(1.0, -1.0), - screen_space_to_clip_space(resolution, br) - ); - } - #[test] fn light_tile_fragment_indices() { let descriptor = LightTilingDescriptor { diff --git a/crates/renderling/src/light/cpu.rs b/crates/renderling/src/light/cpu.rs index 929f0cf5..6ebcab53 100644 --- a/crates/renderling/src/light/cpu.rs +++ b/crates/renderling/src/light/cpu.rs @@ -1,6 +1,7 @@ //! CPU-only lighting and shadows. -use std::sync::{Arc, Mutex, RwLock}; +use core::ops::Deref; +use std::sync::{Arc, Mutex, RwLock, RwLockReadGuard}; use craballoc::{ prelude::{Hybrid, SlabAllocator, WgpuRuntime}, @@ -128,6 +129,16 @@ pub struct AnalyticalLightBundle { pub transform: NestedTransform, } +impl core::fmt::Display for AnalyticalLightBundle { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_fmt(format_args!( + "{} {:?}", + self.light_details.style(), + self.light.id() + )) + } +} + impl Clone for AnalyticalLightBundle where Ct::Container: Clone, @@ -192,6 +203,20 @@ impl AnalyticalLightBundle { } } +struct AnalyticalLightIterator<'a> { + inner: RwLockReadGuard<'a, Vec>>, + index: usize, +} + +impl Iterator for AnalyticalLightIterator<'_> { + type Item = AnalyticalLightBundle; + + fn next(&mut self) -> Option { + let item = self.inner.get(self.index)?; + item.upgrade() + } +} + /// Manages lighting for an entire scene. #[derive(Clone)] pub struct Lighting { @@ -200,8 +225,8 @@ pub struct Lighting { pub(crate) light_slab_buffer: Arc>>, pub(crate) geometry_slab_buffer: Arc>>, pub(crate) lighting_descriptor: Hybrid, - pub(crate) analytical_lights: Arc>>>, - pub(crate) analytical_lights_array: Arc>>>, + pub(crate) analytical_lights: Arc>>>, + pub(crate) analytical_lights_array: Arc>>>>, pub(crate) shadow_map_update_pipeline: Arc, pub(crate) shadow_map_update_bindgroup_layout: Arc, pub(crate) shadow_map_update_blitter: AtlasBlitter, @@ -279,7 +304,7 @@ impl Lighting { Self { shadow_map_atlas: Self::create_shadow_map_atlas(&light_slab, atlas_size), analytical_lights: Default::default(), - analytical_lights_array: Arc::new(Mutex::new(light_slab.new_array([]))), + analytical_lights_array: Default::default(), geometry_slab: geometry.slab_allocator().clone(), light_slab, light_slab_buffer: Arc::new(RwLock::new(light_slab_buffer)), @@ -306,21 +331,18 @@ impl Lighting { /// This can be used to add the light back to the scene after using /// [`Lighting::remove_light`]. pub fn add_light(&self, bundle: &AnalyticalLightBundle) { - { - // Update the array of light ids - // UNWRAP: POP - let mut analytical_lights_array_guard = self.analytical_lights_array.lock().unwrap(); - let mut analytical_light_ids_vec = analytical_lights_array_guard.get_vec(); - analytical_light_ids_vec.push(bundle.light.id()); - *analytical_lights_array_guard = self.light_slab.new_array(analytical_light_ids_vec); - } - { - // Update our list of weakly ref'd light bundles - self.analytical_lights - .lock() - .unwrap() - .push(AnalyticalLightBundle::::from_hybrid(bundle)); - } + log::trace!( + "adding light {:?} ({})", + bundle.light.id(), + bundle.light_details.style() + ); + // Update our list of weakly ref'd light bundles + self.analytical_lights + .write() + .unwrap() + .push(AnalyticalLightBundle::::from_hybrid(bundle)); + // Invalidate the array of lights + *self.analytical_lights_array.write().unwrap() = None; } /// Remove an [`AnalyticalLightBundle`] from the internal list of lights. @@ -329,15 +351,21 @@ impl Lighting { /// /// After calling this function you can include the light again using [`Lighting::add_light`]. pub fn remove_light(&self, bundle: &AnalyticalLightBundle) { - let ids = { - let mut guard = self.analytical_lights.lock().unwrap(); - guard.retain(|stored_light| stored_light.light.id() != bundle.light.id()); - guard - .iter() - .map(|stored_light| stored_light.light.id()) - .collect::>() - }; - *self.analytical_lights_array.lock().unwrap() = self.light_slab.new_array(ids); + log::trace!( + "removing light {:?} ({})", + bundle.light.id(), + bundle.light_details.style() + ); + // Remove the light from the list of weakly ref'd light bundles + let mut guard = self.analytical_lights.write().unwrap(); + guard.retain(|stored_light| stored_light.light.id() != bundle.light.id()); + *self.analytical_lights_array.write().unwrap() = None; + } + + /// Return an iterator over all lights. + pub fn lights(&self) -> impl Iterator + '_ { + let inner = self.analytical_lights.read().unwrap(); + AnalyticalLightIterator { inner, index: 0 } } /// Create a new [`AnalyticalLightBundle`] for the given descriptor `T`. @@ -369,6 +397,11 @@ impl Lighting { light_details, transform, }; + log::trace!( + "created light {:?} ({})", + bundle.light.id(), + bundle.light_details.style() + ); self.add_light(&bundle); @@ -396,22 +429,49 @@ impl Lighting { #[must_use] pub fn commit(&self) -> SlabBuffer { - { - // Drop any analytical lights that don't have external references, - // and update our lights array. - let mut guard = self.analytical_lights.lock().unwrap(); - let mut changed = false; - guard.retain(|light_bundle| { + log::trace!("committing lights"); + let lights_array = { + let mut lights_guard = self.analytical_lights.write().unwrap(); + // Update the list of analytical lights to only reference lights that are still + // held somewhere in the outside program. + let mut analytical_lights_dropped = false; + lights_guard.retain(|light_bundle| { let has_refs = light_bundle.light.has_external_references(); - changed = changed || !has_refs; + if !has_refs { + log::trace!( + " light {:?} ({}) was dropped", + light_bundle.light.id(), + light_bundle.light_details.style() + ); + } + analytical_lights_dropped = analytical_lights_dropped || !has_refs; has_refs }); - if changed { - *self.analytical_lights_array.lock().unwrap() = self - .light_slab - .new_array(guard.iter().map(|bundle| bundle.light.id())); + + // If lights have been dropped, invalidate the array + let mut array_guard = self.analytical_lights_array.write().unwrap(); + if analytical_lights_dropped { + array_guard.take(); } - } + + // If lights have been invalidated (either by some being dropped or if + // it was previously invalidated by `Lighting::add_light` or `Lighting::remove_light`), + // create a new array + array_guard + .get_or_insert_with(|| { + log::trace!(" analytical lights array was invalidated"); + let new_lights = lights_guard + .iter() + .map(|bundle| bundle.light.id()) + .collect::>(); + log::trace!(" lights are now: {new_lights:?}"); + let array = self.light_slab.new_array(new_lights); + log::trace!(" lights array is now: {array:?}"); + array + }) + .array() + }; + self.lighting_descriptor.modify( |LightingDescriptor { analytical_lights_array, @@ -419,706 +479,18 @@ impl Lighting { update_shadow_map_id, update_shadow_map_texture_index, }| { - *analytical_lights_array = self.analytical_lights_array.lock().unwrap().array(); + *analytical_lights_array = lights_array; *shadow_map_atlas_descriptor_id = self.shadow_map_atlas.descriptor_id(); *update_shadow_map_id = Id::NONE; *update_shadow_map_texture_index = 0; }, ); - self.light_slab.commit() + + let buffer = self.light_slab.commit(); + log::trace!(" light slab creation time: {}", buffer.creation_time()); + buffer } } #[cfg(test)] -mod test { - - use core::time::Duration; - use std::time::Instant; - - use craballoc::runtime::CpuRuntime; - use crabslab::{Array, CpuSlab, Slab}; - use glam::{UVec3, Vec3, Vec4, Vec4Swizzles}; - use plotters::{ - chart::{ChartBuilder, SeriesLabelPosition}, - prelude::{ - BitMapBackend, Circle, EmptyElement, IntoDrawingArea, IntoSegmentedCoord, PathElement, - Text, - }, - series::{Histogram, LineSeries, PointSeries}, - style::{Color, IntoFont, ShapeStyle}, - }; - use spirv_std::num_traits::Zero; - - use crate::{ - bvol::BoundingBox, - camera::Camera, - draw::DrawIndirectArgs, - geometry::GeometryDescriptor, - light::{ - LightTile, LightTiling, LightTilingDescriptor, LightTilingInvocation, - SpotLightCalculation, - }, - math::GpuRng, - pbr::Material, - prelude::Transform, - stage::{Renderlet, Stage, Vertex}, - }; - - use super::*; - - #[test] - /// Ensures that a spot light can determine if a point lies inside or outside its cone - /// of emission. - fn spot_one_calc() { - let (doc, _, _) = gltf::import( - crate::test::workspace_dir() - .join("gltf") - .join("spot_one.glb"), - ) - .unwrap(); - let light = doc.lights().unwrap().next().unwrap(); - let spot = if let gltf::khr_lights_punctual::Kind::Spot { - inner_cone_angle, - outer_cone_angle, - } = light.kind() - { - (inner_cone_angle, outer_cone_angle) - } else { - panic!("not a spot light"); - }; - log::info!("spot: {spot:#?}"); - - let light_node = doc.nodes().find(|node| node.light().is_some()).unwrap(); - let parent_transform = Transform::from(light_node.transform()); - log::info!("parent_transform: {parent_transform:#?}"); - - let spot_descriptor = SpotLightDescriptor { - position: Vec3::ZERO, - direction: Vec3::NEG_Z, - inner_cutoff: spot.0, - outer_cutoff: spot.1, - color: Vec3::from(light.color()).extend(1.0), - intensity: light.intensity(), - }; - - let specific_points = [ - (Vec3::ZERO, true, true, Some(1.0)), - (Vec3::new(0.5, 0.0, 0.0), false, true, None), - (Vec3::new(0.5, 0.0, 0.5), false, false, None), - (Vec3::new(1.0, 0.0, 0.0), false, false, Some(0.0)), - ]; - for (i, (point, inside_inner, inside_outer, maybe_contribution)) in - specific_points.into_iter().enumerate() - { - log::info!("{i} descriptor: {spot_descriptor:#?}"); - let spot_calc = - SpotLightCalculation::new(spot_descriptor, parent_transform.into(), point); - log::info!("{i} spot_calc@{point}:\n{spot_calc:#?}"); - assert_eq!( - (inside_inner, inside_outer), - ( - spot_calc.fragment_is_inside_inner_cone, - spot_calc.fragment_is_inside_outer_cone - ), - ); - if let Some(expected_contribution) = maybe_contribution { - assert_eq!(expected_contribution, spot_calc.contribution); - } - } - } - - #[test] - /// Ensures that a spot light illuminates only the objects within its cone of - /// emission. - fn spot_one_frame() { - let m = 32.0; - let (w, h) = (16.0f32 * m, 9.0 * m); - let ctx = crate::Context::headless(w as u32, h as u32); - let stage = ctx.new_stage().with_msaa_sample_count(4); - let doc = stage - .load_gltf_document_from_path( - crate::test::workspace_dir() - .join("gltf") - .join("spot_one.glb"), - ) - .unwrap(); - let camera = doc.cameras.first().unwrap(); - camera - .as_ref() - .modify(|cam| cam.set_projection(crate::camera::perspective(w, h))); - stage.use_camera(camera); - - let frame = ctx.get_next_frame().unwrap(); - stage.render(&frame.view()); - let img = frame.read_image().unwrap(); - img_diff::assert_img_eq("light/spot_lights/one.png", img); - frame.present(); - } - - #[test] - /// Test the spot lights. - /// - /// This should render a cube with two spot lights illuminating a spot on two - /// of its sides. - fn spot_lights() { - let w = 800.0; - let h = 800.0; - let ctx = crate::Context::headless(w as u32, h as u32); - let stage = ctx - .new_stage() - .with_lighting(true) - .with_msaa_sample_count(4); - - let doc = stage - .load_gltf_document_from_path( - crate::test::workspace_dir() - .join("gltf") - .join("spot_lights.glb"), - ) - .unwrap(); - let camera = doc.cameras.first().unwrap(); - camera - .as_ref() - .modify(|cam| cam.set_projection(crate::camera::perspective(w, h))); - stage.use_camera(camera); - - let down_light = doc.lights.first().unwrap(); - log::info!( - "down_light: {:#?}", - down_light.light_details.as_spot().unwrap().get() - ); - - let frame = ctx.get_next_frame().unwrap(); - stage.render(&frame.view()); - let img = frame.read_image().unwrap(); - img_diff::assert_img_eq("light/spot_lights/frame.png", img); - frame.present(); - } - - #[test] - fn light_tiling_light_bounds() { - let magnification = 8; - let w = 16.0 * 2.0f32.powi(magnification); - let h = 9.0 * 2.0f32.powi(magnification); - let ctx = crate::Context::headless(w as u32, h as u32); - let stage = ctx.new_stage().with_msaa_sample_count(4); - let doc = stage - .load_gltf_document_from_path( - crate::test::workspace_dir() - .join("gltf") - .join("light_tiling_test.glb"), - ) - .unwrap(); - let camera = doc.cameras.first().unwrap(); - - stage.use_camera(camera); - - let _lights = crate::test::make_two_directional_light_setup(&stage); - - // Here we only want to render the bounding boxes of the renderlets, - // so mark the renderlets themeselves invisible - doc.renderlets_iter().for_each(|hy_rend| { - hy_rend.modify(|r| { - r.visible = false; - }); - }); - - let colors = [0x6DE1D2FF, 0xFFD63AFF, 0x6DE1D2FF, 0xF75A5AFF].map(|albedo_factor| { - stage.new_material(Material { - albedo_factor: { - let mut color = crate::math::hex_to_vec4(albedo_factor); - crate::color::linear_xfer_vec4(&mut color); - color - }, - ..Default::default() - }) - }); - let mut resources = vec![]; - for (i, node) in doc.nodes.iter().enumerate() { - if node.mesh.is_none() { - continue; - } - let transform = Mat4::from(node.transform.get_global_transform()); - if let Some(mesh_index) = node.mesh { - log::info!("mesh: {}", node.name.as_deref().unwrap_or("unknown")); - let mesh = &doc.meshes[mesh_index]; - for prim in mesh.primitives.iter() { - let (min, max) = prim.bounding_box; - let min = transform.transform_point3(min); - let max = transform.transform_point3(max); - let bb = BoundingBox::from_min_max(min, max); - if bb.half_extent.min_element().is_zero() { - log::warn!("bounding box is not a volume, skipping"); - continue; - } - log::info!("min: {min}, max: {max}"); - resources.push( - stage - .builder() - .with_vertices({ - bb.get_mesh() - .map(|(p, n)| Vertex::default().with_position(p).with_normal(n)) - }) - .with_material_id(colors[i % colors.len()].id()) - .build(), - ); - } - } - } - - let frame = ctx.get_next_frame().unwrap(); - stage.render(&frame.view()); - let img = frame.read_image().unwrap(); - img_diff::save("light/tiling/bounds.png", img); - frame.present(); - } - - fn gen_vec3(prng: &mut GpuRng) -> Vec3 { - let x = prng.gen_f32(-120.0, 120.0); - let y = prng.gen_f32(0.0, 80.0); - let z = prng.gen_f32(-120.0, 120.0); - Vec3::new(x, y, z) - } - - fn gen_light( - stage: &Stage, - prng: &mut GpuRng, - bounding_boxes: &[BoundingBox], - ) -> ( - Hybrid, - HybridArray, - Hybrid, - AnalyticalLightBundle, - Hybrid, - ) { - let mut position = gen_vec3(prng); - while bounding_boxes.iter().any(|bb| bb.contains_point(position)) { - position = gen_vec3(prng); - } - - let color = Vec4::new( - prng.gen_f32(0.0, 1.0), - prng.gen_f32(0.0, 1.0), - prng.gen_f32(0.0, 1.0), - 1.0, - ); - - let scale = prng.gen_f32(0.1, 1.0); - - let light_bb = BoundingBox { - center: Vec3::ZERO, - half_extent: Vec3::new(scale, scale, scale) * 0.5, - }; - - // let inner_cutoff = prng.gen_f32(0.04, 0.09); - // let outer_cutoff = prng.gen_f32(inner_cutoff, 0.16); - - // Also make a renderlet for the light, so we can see where it is. - let rez = stage - .builder() - .with_transform(Transform { - translation: position, - ..Default::default() - }) - .with_vertices( - light_bb - .get_mesh() - .map(|(p, n)| Vertex::default().with_position(p).with_normal(n)), - ) - .with_material(Material { - albedo_factor: color, - has_lighting: false, - emissive_factor: color.xyz(), - emissive_strength_multiplier: 100.0, - ..Default::default() - }) - .suffix({ - let intensity = scale * 100.0; - // let light_descriptor = SpotLightDescriptor { - // position, - // color, - // intensity, - // direction: Vec3::NEG_Y, - // inner_cutoff, - // outer_cutoff, - // }; - let light_descriptor = PointLightDescriptor { - position, - color, - intensity, - }; - let nested_transform = stage.new_nested_transform(); - nested_transform.modify(|t| { - t.translation = position; - }); - stage.new_analytical_light(light_descriptor, None) - }) - .build(); - rez - } - - fn size() -> UVec2 { - UVec2::new( - (10.0 * 2.0f32.powi(8)) as u32, - (9.0 * 2.0f32.powi(8)) as u32, - ) - } - - fn make_camera() -> Camera { - let size = size(); - Camera::new( - Mat4::perspective_rh( - std::f32::consts::FRAC_PI_4, - size.x as f32 / size.y as f32, - 50.0, - 600.0, - ), - Mat4::look_at_rh(Vec3::new(250.0, 200.0, 250.0), Vec3::ZERO, Vec3::Y), - ) - } - - #[test] - fn light_tiling_positions() { - let w = 32; - let h = 32; - let slab = SlabAllocator::new(CpuRuntime, "test", ()); - let descriptor = slab.new_value(LightTilingDescriptor { - depth_texture_size: UVec2::new(w, h), - ..Default::default() - }); - let tiled_size = descriptor.get().tile_dimensions(); - println!("tiled_size: {tiled_size}"); - let tiles = slab.new_array(vec![ - LightTile::default(); - (tiled_size.x * tiled_size.y) as usize - ]); - descriptor.modify(|d| { - d.tiles_array = tiles.array(); - }); - let desc = descriptor.get(); - let mut tiling_slab = slab.commit().as_vec().clone(); - - let mut img = image::RgbImage::new(w, h); - let mut light_img = image::RgbImage::new(w, h); - for x in 0..w { - for y in 0..h { - let global_id = UVec3::new(x, y, 0); - let invocation = LightTilingInvocation::new(global_id, descriptor.get()); - if invocation.should_invoke() { - let pixel = img.get_pixel_mut(x, y); - let r = (x as f32 / w as f32 * 255.0) as u8; - let g = (y as f32 / h as f32 * 255.0) as u8; - pixel.0 = [r, g, 0x00]; - - if invocation.frag_pos_is_tile_corner() { - pixel.0[0] = 0xFF - pixel.0[0]; - pixel.0[1] = 0xFF - pixel.0[1]; - pixel.0[2] = 0xFF - pixel.0[2]; - - let tile_dimensions = tiled_size; - let tile_index = invocation.tile_index(); - println!("frag_pos: {}", invocation.frag_pos()); - println!("tile_pos: {}", invocation.tile_pos()); - println!("tile_index: {tile_index}"); - let num_tiles = tile_dimensions.x * tile_dimensions.y; - - // index of the tile's min depth atomic value in the tiling slab - let min_depth_index = (invocation.descriptor.tiles_array.at(tile_index) - + LightTile::OFFSET_OF_DEPTH_MIN) - .index(); - // index of the tile's max depth atomic value in the tiling slab - let max_depth_index = (invocation.descriptor.tiles_array.at(tile_index) - + LightTile::OFFSET_OF_DEPTH_MAX) - .index(); - - let percent = tile_index as f32 / num_tiles as f32; //frag_pos.x as f32 / self.descriptor.depth_texture_size.x as f32; - tiling_slab[min_depth_index] = (percent * u32::MAX as f32) as u32; - tiling_slab[max_depth_index] = u32::MAX; //(percent * u32::MAX as f32) as u32; - } - - let pixel = light_img.get_pixel_mut(x, y); - let index = invocation.frag_index(); - println!("index: {index}"); - let value = crate::math::scaled_f32_to_u8(index as f32 / (16.0 * 16.0)); - pixel.0[0] = value; - pixel.0[1] = value; - pixel.0[2] = value; - } - } - } - img_diff::save("light/tiling/positions.png", img); - img_diff::save("light/tiling/frag_pos.png", light_img); - - let (mins, maxs) = tiling_slab - .read_vec(desc.tiles_array) - .into_iter() - .map(|tile| { - ( - crate::math::scaled_u32_to_u8(tile.depth_min), - crate::math::scaled_u32_to_u8(tile.depth_max), - ) - }) - .unzip(); - let mins_img = image::GrayImage::from_vec(tiled_size.x, tiled_size.y, mins).unwrap(); - img_diff::save("light/tiling/positions-mins.png", mins_img); - let maxs_img = image::GrayImage::from_vec(tiled_size.x, tiled_size.y, maxs).unwrap(); - img_diff::save("light/tiling/positions-maxs.png", maxs_img); - } - - #[test] - /// Test the light tiling feature. - fn light_tiling_sanity() { - let _ = env_logger::builder().is_test(true).try_init(); - let size = size(); - let ctx = crate::Context::headless(size.x, size.y); - let stage = ctx - .new_stage() - .with_lighting(false) - .with_bloom(true) - .with_bloom_mix_strength(0.5); - - let doc = stage - .load_gltf_document_from_path( - crate::test::workspace_dir() - .join("gltf") - .join("light_tiling_test.glb"), - ) - .unwrap(); - - let camera = stage.new_camera(make_camera()); - stage.use_camera(camera); - snapshot(&ctx, &stage, "light/tiling/1-no-lighting.png"); - - stage.set_has_lighting(true); - - let moonlight = doc.lights.first().unwrap(); - let _shadow = { - let sm = stage - .new_shadow_map(moonlight, UVec2::splat(1024), 0.1, 256.0) - .unwrap(); - sm.shadowmap_descriptor.modify(|d| { - d.bias_min = 0.0; - d.bias_max = 0.0; - d.pcf_samples = 2; - }); - sm.update(&stage, doc.renderlets_iter()).unwrap(); - sm - }; - snapshot(&ctx, &stage, "light/tiling/2-before-lights.png"); - - crate::test::capture_gpu_frame(&ctx, "light/tiling/2.gputrace", || { - let frame = ctx.get_next_frame().unwrap(); - stage.render(&frame.view()); - frame.present(); - }); - - let mut bounding_boxes = vec![]; - for node in doc.nodes.iter() { - if node.mesh.is_none() { - continue; - } - let transform = Mat4::from(node.transform.get_global_transform()); - if let Some(mesh_index) = node.mesh { - let mesh = &doc.meshes[mesh_index]; - for prim in mesh.primitives.iter() { - let (min, max) = prim.bounding_box; - let min = transform.transform_point3(min); - let max = transform.transform_point3(max); - let bb = BoundingBox::from_min_max(min, max); - if bb.half_extent.min_element().is_zero() { - continue; - } - bounding_boxes.push(bb); - } - } - } - log::info!("have {} bounding boxes", bounding_boxes.len()); - - let mut prng = crate::math::GpuRng::new(666); - let mut lights = vec![]; - - for _ in 0..MAX_LIGHTS { - lights.push(gen_light(&stage, &mut prng, &bounding_boxes)); - } - snapshot(&ctx, &stage, "light/tiling/3-after-lights.png"); - - // Remove the light meshes - for (_, _, _, _, renderlet) in lights.iter() { - stage.remove_renderlet(renderlet); - } - snapshot(&ctx, &stage, "light/tiling/4-after-lights-no-meshes.png"); - - let tiling = LightTiling::new(ctx.runtime(), false, size, 32); - let desc = tiling.descriptor().get(); - let depth = stage.depth_texture.read().unwrap(); - let mut depth_img = crate::texture::read_depth_texture_f32( - ctx.runtime(), - size.x as usize, - size.y as usize, - depth.texture.as_ref(), - ) - .unwrap(); - // let mut depth_img = crate::texture::read_depth_texture_to_image( - // ctx.runtime(), - // size.x as usize, - // size.y as usize, - // &depth.texture, - // ) - // .unwrap(); - // img_diff::normalize_gray_img(&mut depth_img); - img_diff::save("light/tiling/5-depth.png", depth_img); - tiling.run(&stage.geometry.commit(), &stage.lighting.commit(), &depth); - let (mut mins_img, mut maxs_img, mut lights_img) = - futures_lite::future::block_on(tiling.read_images()); - img_diff::normalize_gray_img(&mut mins_img); - img_diff::normalize_gray_img(&mut maxs_img); - img_diff::normalize_gray_img(&mut lights_img); - img_diff::save("light/tiling/5-mins.png", mins_img); - img_diff::save("light/tiling/5-maxs.png", maxs_img); - img_diff::save("light/tiling/5-lights.png", lights_img); - - return; - log::info!("running stats"); - - // Stats - let mut stats = LightTilingStats::default(); - for number_of_lights in [ - 1, - MAX_LIGHTS / 8, - MAX_LIGHTS / 4, - MAX_LIGHTS / 2, - ((MAX_LIGHTS / 2) + MAX_LIGHTS) / 2, - MAX_LIGHTS, - ] { - let mut run = LightTilingStatsRun { - number_of_lights, - iterations: vec![], - }; - - for (i, (_, _, _, light, _)) in lights.iter().enumerate() { - stage.remove_light(light); - if i < number_of_lights { - stage.add_light(light); - } - } - - const NUM_RUNS: usize = 2; - for i in 0..NUM_RUNS { - log::info!("{number_of_lights} {i} running"); - let start = Instant::now(); - let frame = ctx.get_next_frame().unwrap(); - stage.render(&frame.view()); - frame.present(); - ctx.get_device().poll(wgpu::Maintain::wait()); - let duration = start.elapsed(); - run.iterations.push(duration); - } - stats.runs.push(run); - } - plot(stats); - } - - fn snapshot(ctx: &crate::Context, stage: &Stage, path: &str) { - let frame = ctx.get_next_frame().unwrap(); - let start = std::time::Instant::now(); - stage.render(&frame.view()); - let elapsed = start.elapsed(); - log::info!("shapshot: {}s '{path}'", elapsed.as_secs_f32()); - let img = frame.read_image().unwrap(); - img_diff::save(path, img); - frame.present(); - } - - const MAX_LIGHTS: usize = 1024; - - struct LightTilingStatsRun { - number_of_lights: usize, - iterations: Vec, - } - - impl LightTilingStatsRun { - fn avg_frame_time(&self) -> f32 { - let total: Duration = self.iterations.iter().sum(); - total.as_secs_f32() / self.iterations.len() as f32 - } - } - - #[derive(Default)] - struct LightTilingStats { - runs: Vec, - } - - fn plot(stats: LightTilingStats) { - let path = crate::test::workspace_dir().join("test_output/lights/tiling/frame-time.png"); - let root_drawing_area = BitMapBackend::new(&path, (800, 600)).into_drawing_area(); - root_drawing_area.fill(&plotters::style::WHITE).unwrap(); - - let mut chart = ChartBuilder::on(&root_drawing_area) - .caption( - "Renderling lighting frame time", - ("sans-serif", 50).into_font(), - ) - .margin(30) - .margin_right(100) - .x_label_area_size(30) - .y_label_area_size(30) - .build_cartesian_2d( - 0..MAX_LIGHTS + 1, - 0.0..stats - .runs - .iter() - .map(|r| r.avg_frame_time()) - .max_by(|a, b| a.total_cmp(b)) - .unwrap_or_default(), - ) - .unwrap(); - chart - .configure_mesh() - .x_desc("number of lights") - .y_desc("avg fps") - .draw() - .unwrap(); - - chart - .draw_series(LineSeries::new( - stats - .runs - .iter() - .map(|r| (r.number_of_lights, r.avg_frame_time())), - plotters::style::RED, - )) - .unwrap() - .label("without-tiling") - .legend(|(x, y)| { - PathElement::new(vec![(x, y), (x + 20, y)], plotters::style::RED.filled()) - }); - chart - .draw_series(PointSeries::of_element( - stats - .runs - .iter() - .map(|r| (r.number_of_lights, r.avg_frame_time())), - 5, - ShapeStyle::from(&plotters::style::RED).filled(), - &|(num_lights, seconds_per_frame), size, style| { - EmptyElement::at((num_lights, seconds_per_frame)) - + Circle::new((0, 0), size, style) - + Text::new( - format!("({num_lights}, {:.2} fps)", 1.0 / seconds_per_frame), - (0, 15), - ("sans-serif", 15), - ) - }, - )) - .unwrap(); - - chart - .configure_series_labels() - .position(SeriesLabelPosition::LowerRight) - .margin(20) - .label_font(("sans-serif", 20)) - .draw() - .unwrap(); - root_drawing_area.present().unwrap(); - } -} +mod test; diff --git a/crates/renderling/src/light/cpu/test.rs b/crates/renderling/src/light/cpu/test.rs new file mode 100644 index 00000000..8b05ac02 --- /dev/null +++ b/crates/renderling/src/light/cpu/test.rs @@ -0,0 +1,960 @@ +//! Tests of the lighting system. + +use core::time::Duration; +use std::time::Instant; + +use craballoc::runtime::CpuRuntime; +use crabslab::{Array, CpuSlab, Slab}; +use glam::{UVec3, Vec2, Vec3, Vec4, Vec4Swizzles}; +use plotters::{ + chart::{ChartBuilder, SeriesLabelPosition}, + prelude::{ + BitMapBackend, Circle, EmptyElement, IntoDrawingArea, IntoSegmentedCoord, PathElement, Text, + }, + series::{Histogram, LineSeries, PointSeries}, + style::{Color, IntoFont, ShapeStyle}, +}; +use spirv_std::num_traits::Zero; + +use crate::{ + bvol::BoundingBox, + camera::Camera, + color::linear_xfer_vec4, + draw::DrawIndirectArgs, + geometry::GeometryDescriptor, + light::{ + LightTile, LightTiling, LightTilingDescriptor, LightTilingInvocation, SpotLightCalculation, + }, + math::{ + hex_to_vec4, scaled_f32_to_u8, ConstTexture, CpuTexture2d, CpuTexture2dArray, GpuRng, + IsVector, NonAtomicSlab, + }, + pbr::Material, + prelude::Transform, + stage::{Renderlet, RenderletPbrVertexInfo, Stage, Vertex}, +}; + +use super::*; + +#[test] +/// Ensures that a spot light can determine if a point lies inside or outside its cone +/// of emission. +fn spot_one_calc() { + let (doc, _, _) = gltf::import( + crate::test::workspace_dir() + .join("gltf") + .join("spot_one.glb"), + ) + .unwrap(); + let light = doc.lights().unwrap().next().unwrap(); + let spot = if let gltf::khr_lights_punctual::Kind::Spot { + inner_cone_angle, + outer_cone_angle, + } = light.kind() + { + (inner_cone_angle, outer_cone_angle) + } else { + panic!("not a spot light"); + }; + log::info!("spot: {spot:#?}"); + + let light_node = doc.nodes().find(|node| node.light().is_some()).unwrap(); + let parent_transform = Transform::from(light_node.transform()); + log::info!("parent_transform: {parent_transform:#?}"); + + let spot_descriptor = SpotLightDescriptor { + position: Vec3::ZERO, + direction: Vec3::NEG_Z, + inner_cutoff: spot.0, + outer_cutoff: spot.1, + color: Vec3::from(light.color()).extend(1.0), + intensity: light.intensity(), + }; + + let specific_points = [ + (Vec3::ZERO, true, true, Some(1.0)), + (Vec3::new(0.5, 0.0, 0.0), false, true, None), + (Vec3::new(0.5, 0.0, 0.5), false, false, None), + (Vec3::new(1.0, 0.0, 0.0), false, false, Some(0.0)), + ]; + for (i, (point, inside_inner, inside_outer, maybe_contribution)) in + specific_points.into_iter().enumerate() + { + log::info!("{i} descriptor: {spot_descriptor:#?}"); + let spot_calc = SpotLightCalculation::new(spot_descriptor, parent_transform.into(), point); + log::info!("{i} spot_calc@{point}:\n{spot_calc:#?}"); + assert_eq!( + (inside_inner, inside_outer), + ( + spot_calc.fragment_is_inside_inner_cone, + spot_calc.fragment_is_inside_outer_cone + ), + ); + if let Some(expected_contribution) = maybe_contribution { + assert_eq!(expected_contribution, spot_calc.contribution); + } + } +} + +#[test] +/// Ensures that a spot light illuminates only the objects within its cone of +/// emission. +fn spot_one_frame() { + let m = 32.0; + let (w, h) = (16.0f32 * m, 9.0 * m); + let ctx = crate::Context::headless(w as u32, h as u32); + let stage = ctx.new_stage().with_msaa_sample_count(4); + let doc = stage + .load_gltf_document_from_path( + crate::test::workspace_dir() + .join("gltf") + .join("spot_one.glb"), + ) + .unwrap(); + let camera = doc.cameras.first().unwrap(); + camera + .as_ref() + .modify(|cam| cam.set_projection(crate::camera::perspective(w, h))); + stage.use_camera(camera); + + let frame = ctx.get_next_frame().unwrap(); + stage.render(&frame.view()); + let img = frame.read_image().unwrap(); + img_diff::assert_img_eq("light/spot_lights/one.png", img); + frame.present(); +} + +#[test] +/// Test the spot lights. +/// +/// This should render a cube with two spot lights illuminating a spot on two +/// of its sides. +fn spot_lights() { + let w = 800.0; + let h = 800.0; + let ctx = crate::Context::headless(w as u32, h as u32); + let stage = ctx + .new_stage() + .with_lighting(true) + .with_msaa_sample_count(4); + + let doc = stage + .load_gltf_document_from_path( + crate::test::workspace_dir() + .join("gltf") + .join("spot_lights.glb"), + ) + .unwrap(); + let camera = doc.cameras.first().unwrap(); + camera + .as_ref() + .modify(|cam| cam.set_projection(crate::camera::perspective(w, h))); + stage.use_camera(camera); + + let down_light = doc.lights.first().unwrap(); + log::info!( + "down_light: {:#?}", + down_light.light_details.as_spot().unwrap().get() + ); + + let frame = ctx.get_next_frame().unwrap(); + stage.render(&frame.view()); + let img = frame.read_image().unwrap(); + img_diff::assert_img_eq("light/spot_lights/frame.png", img); + frame.present(); +} + +#[test] +fn light_tiling_light_bounds() { + let magnification = 8; + let w = 16.0 * 2.0f32.powi(magnification); + let h = 9.0 * 2.0f32.powi(magnification); + let ctx = crate::Context::headless(w as u32, h as u32); + let stage = ctx.new_stage().with_msaa_sample_count(4); + let doc = stage + .load_gltf_document_from_path( + crate::test::workspace_dir() + .join("gltf") + .join("light_tiling_test.glb"), + ) + .unwrap(); + let camera = doc.cameras.first().unwrap(); + + stage.use_camera(camera); + + let _lights = crate::test::make_two_directional_light_setup(&stage); + + // Here we only want to render the bounding boxes of the renderlets, + // so mark the renderlets themeselves invisible + doc.renderlets_iter().for_each(|hy_rend| { + hy_rend.modify(|r| { + r.visible = false; + }); + }); + + let colors = [0x6DE1D2FF, 0xFFD63AFF, 0x6DE1D2FF, 0xF75A5AFF].map(|albedo_factor| { + stage.new_material(Material { + albedo_factor: { + let mut color = crate::math::hex_to_vec4(albedo_factor); + linear_xfer_vec4(&mut color); + color + }, + ..Default::default() + }) + }); + let mut resources = vec![]; + for (i, node) in doc.nodes.iter().enumerate() { + if node.mesh.is_none() { + continue; + } + let transform = Mat4::from(node.transform.get_global_transform()); + if let Some(mesh_index) = node.mesh { + log::info!("mesh: {}", node.name.as_deref().unwrap_or("unknown")); + let mesh = &doc.meshes[mesh_index]; + for prim in mesh.primitives.iter() { + let (min, max) = prim.bounding_box; + let min = transform.transform_point3(min); + let max = transform.transform_point3(max); + let bb = BoundingBox::from_min_max(min, max); + if bb.half_extent.min_element().is_zero() { + log::warn!("bounding box is not a volume, skipping"); + continue; + } + log::info!("min: {min}, max: {max}"); + resources.push( + stage + .builder() + .with_vertices({ + bb.get_mesh() + .map(|(p, n)| Vertex::default().with_position(p).with_normal(n)) + }) + .with_material_id(colors[i % colors.len()].id()) + .build(), + ); + } + } + } + + let frame = ctx.get_next_frame().unwrap(); + stage.render(&frame.view()); + let img = frame.read_image().unwrap(); + img_diff::save("light/tiling/bounds.png", img); + frame.present(); +} + +fn gen_vec3(prng: &mut GpuRng) -> Vec3 { + let x = prng.gen_f32(-120.0, 120.0); + let y = prng.gen_f32(0.0, 80.0); + let z = prng.gen_f32(-120.0, 120.0); + Vec3::new(x, y, z) +} + +fn gen_light( + stage: &Stage, + prng: &mut GpuRng, + bounding_boxes: &[BoundingBox], +) -> ( + Hybrid, + HybridArray, + Hybrid, + AnalyticalLightBundle, + Hybrid, +) { + let mut position = gen_vec3(prng); + while bounding_boxes.iter().any(|bb| bb.contains_point(position)) { + position = gen_vec3(prng); + } + assert!(!position.x.is_nan()); + assert!(!position.y.is_nan()); + assert!(!position.z.is_nan()); + + let color = Vec4::new( + prng.gen_f32(0.0, 1.0), + prng.gen_f32(0.0, 1.0), + prng.gen_f32(0.0, 1.0), + 1.0, + ); + + let scale = prng.gen_f32(0.1, 1.0); + + let light_bb = BoundingBox { + center: Vec3::ZERO, + half_extent: Vec3::new(scale, scale, scale) * 0.5, + }; + + // Also make a renderlet for the light, so we can see where it is. + let transform = stage.new_nested_transform(); + transform.modify(|t| { + t.translation = position; + }); + let rez = stage + .builder() + .with_transform(Transform { + translation: position, + ..Default::default() + }) + .with_vertices( + light_bb + .get_mesh() + .map(|(p, n)| Vertex::default().with_position(p).with_normal(n)), + ) + .with_material(Material { + albedo_factor: color, + has_lighting: false, + emissive_factor: color.xyz(), + emissive_strength_multiplier: 100.0, + ..Default::default() + }) + .suffix({ + // suffix the actual analytical light + let intensity = scale * 100.0; + + let light_descriptor = PointLightDescriptor { + position, + color, + intensity, + }; + + stage.new_analytical_light(light_descriptor, None) + }) + .build(); + rez +} + +fn size() -> UVec2 { + UVec2::new( + (10.0 * 2.0f32.powi(8)) as u32, + (9.0 * 2.0f32.powi(8)) as u32, + ) +} + +fn make_camera() -> Camera { + let size = size(); + Camera::new( + Mat4::perspective_rh( + std::f32::consts::FRAC_PI_4, + size.x as f32 / size.y as f32, + 50.0, + 600.0, + ), + Mat4::look_at_rh(Vec3::new(250.0, 200.0, 250.0), Vec3::ZERO, Vec3::Y), + ) +} + +#[test] +/// Test the light tiling feature. +fn light_tiling_cpu_sanity() { + let _ = env_logger::builder().is_test(true).try_init(); + let size = size(); + let ctx = crate::Context::headless(size.x, size.y); + let stage = ctx + .new_stage() + .with_lighting(true) + .with_bloom(true) + .with_bloom_mix_strength(0.5); + + let doc = stage + .load_gltf_document_from_path( + crate::test::workspace_dir() + .join("gltf") + .join("light_tiling_test.glb"), + ) + .unwrap(); + + let camera = stage.new_camera(make_camera()); + stage.use_camera(camera); + + let moonlight = doc.lights.first().unwrap(); + let _shadow = { + let sm = stage + .new_shadow_map(moonlight, UVec2::splat(1024), 0.1, 256.0) + .unwrap(); + sm.shadowmap_descriptor.modify(|d| { + d.bias_min = 0.0; + d.bias_max = 0.0; + d.pcf_samples = 2; + }); + sm.update(&stage, doc.renderlets_iter()).unwrap(); + sm + }; + + let mut bounding_boxes = vec![]; + for node in doc.nodes.iter() { + if node.mesh.is_none() { + continue; + } + let transform = Mat4::from(node.transform.get_global_transform()); + if let Some(mesh_index) = node.mesh { + let mesh = &doc.meshes[mesh_index]; + for prim in mesh.primitives.iter() { + let (min, max) = prim.bounding_box; + let min = transform.transform_point3(min); + let max = transform.transform_point3(max); + let bb = BoundingBox::from_min_max(min, max); + if bb.half_extent.min_element().is_zero() { + continue; + } + bounding_boxes.push(bb); + } + } + } + + let mut prng = crate::math::GpuRng::new(666); + let mut lights = vec![]; + + for _ in 0..MAX_LIGHTS { + lights.push(gen_light(&stage, &mut prng, &bounding_boxes)); + } + + // Remove the light meshes + for (_, _, _, _, renderlet) in lights.iter() { + stage.remove_renderlet(renderlet); + } + snapshot( + &ctx, + &stage, + "light/tiling/cpu/4-after-lights-no-meshes.png", + ); + + // Get all the slabs and run the shader on the CPU + let tiling = LightTiling::new(ctx.runtime(), false, size, 32); + let desc = tiling.tiling_descriptor.get(); + let depth = stage.depth_texture.read().unwrap(); + let depth_img = crate::texture::read_depth_texture_to_image( + ctx.runtime(), + size.x as usize, + size.y as usize, + &depth.texture, + ) + .unwrap(); + let geometry_slab = + futures_lite::future::block_on(stage.geometry.slab_allocator().read(..)).unwrap(); + let lighting_slab = + futures_lite::future::block_on(stage.lighting.slab_allocator().read(..)).unwrap(); + let tiling_slab = { + tiling.prepare(UVec2::new(depth_img.width(), depth_img.height())); + let _ = tiling.tiling_slab.commit(); + futures_lite::future::block_on(tiling.tiling_slab.read(..)).unwrap() + }; + + let w = depth_img.width() / LightTilingDescriptor::TILE_SIZE.x + 1; + let h = depth_img.height() / LightTilingDescriptor::TILE_SIZE.y + 1; + let mut non_atomic_tiling_slab = NonAtomicSlab::new(tiling_slab); + let depth_img = CpuTexture2d::from_image(depth_img, crate::math::luma_u8_to_vec4); + for x in 0..w { + for y in 0..h { + let global_id = UVec3::new(x, y, 0); + let invocation = LightTilingInvocation::new(global_id, desc); + invocation.compute_tiles( + &depth_img, + &geometry_slab, + &lighting_slab, + &mut non_atomic_tiling_slab, + ); + } + } +} + +#[test] +/// Test the light tiling feature. +fn light_tiling_sanity() { + let _ = env_logger::builder().is_test(true).try_init(); + let size = size(); + let ctx = crate::Context::headless(size.x, size.y); + let stage = ctx + .new_stage() + .with_lighting(false) + .with_bloom(true) + .with_bloom_mix_strength(0.5); + + let doc = stage + .load_gltf_document_from_path( + crate::test::workspace_dir() + .join("gltf") + .join("light_tiling_test.glb"), + ) + .unwrap(); + + let camera = stage.new_camera(make_camera()); + stage.use_camera(camera); + snapshot(&ctx, &stage, "light/tiling/1-no-lighting.png"); + + stage.set_has_lighting(true); + + let moonlight = doc.lights.first().unwrap(); + let _shadow = { + let sm = stage + .new_shadow_map(moonlight, UVec2::splat(1024), 0.1, 256.0) + .unwrap(); + sm.shadowmap_descriptor.modify(|d| { + d.bias_min = 0.0; + d.bias_max = 0.0; + d.pcf_samples = 2; + }); + sm.update(&stage, doc.renderlets_iter()).unwrap(); + sm + }; + snapshot(&ctx, &stage, "light/tiling/2-before-lights.png"); + + crate::test::capture_gpu_frame(&ctx, "light/tiling/2.gputrace", || { + let frame = ctx.get_next_frame().unwrap(); + stage.render(&frame.view()); + frame.present(); + }); + + let mut bounding_boxes = vec![]; + for node in doc.nodes.iter() { + if node.mesh.is_none() { + continue; + } + let transform = Mat4::from(node.transform.get_global_transform()); + if let Some(mesh_index) = node.mesh { + let mesh = &doc.meshes[mesh_index]; + for prim in mesh.primitives.iter() { + let (min, max) = prim.bounding_box; + let min = transform.transform_point3(min); + let max = transform.transform_point3(max); + let bb = BoundingBox::from_min_max(min, max); + if bb.half_extent.min_element().is_zero() { + continue; + } + bounding_boxes.push(bb); + } + } + } + log::info!("have {} bounding boxes", bounding_boxes.len()); + + let mut prng = crate::math::GpuRng::new(666); + let mut lights: Vec<( + Hybrid, + HybridArray, + Hybrid, + AnalyticalLightBundle, + Hybrid, + )> = vec![]; + + for _ in 0..MAX_LIGHTS { + lights.push(gen_light(&stage, &mut prng, &bounding_boxes)); + } + snapshot(&ctx, &stage, "light/tiling/3-after-lights.png"); + + // Remove the light meshes + for (_, _, _, _, renderlet) in lights.iter() { + stage.remove_renderlet(renderlet); + } + snapshot(&ctx, &stage, "light/tiling/4-after-lights-no-meshes.png"); + + let tiling = LightTiling::new(ctx.runtime(), false, size, 32); + let desc = tiling.tiling_descriptor.get(); + let depth = stage.depth_texture.read().unwrap(); + let mut depth_img = crate::texture::read_depth_texture_f32( + ctx.runtime(), + size.x as usize, + size.y as usize, + depth.texture.as_ref(), + ) + .unwrap(); + // let mut depth_img = crate::texture::read_depth_texture_to_image( + // ctx.runtime(), + // size.x as usize, + // size.y as usize, + // &depth.texture, + // ) + // .unwrap(); + // img_diff::normalize_gray_img(&mut depth_img); + img_diff::save("light/tiling/5-depth.png", depth_img); + tiling.run(&stage.geometry.commit(), &stage.lighting.commit(), &depth); + let (mut mins_img, mut maxs_img, mut lights_img) = + futures_lite::future::block_on(tiling.read_images()); + img_diff::normalize_gray_img(&mut mins_img); + img_diff::normalize_gray_img(&mut maxs_img); + img_diff::normalize_gray_img(&mut lights_img); + img_diff::save("light/tiling/5-mins.png", mins_img); + img_diff::save("light/tiling/5-maxs.png", maxs_img); + img_diff::save("light/tiling/5-lights.png", lights_img); + + return; + log::info!("running stats"); + + // Stats + let mut stats = LightTilingStats::default(); + for number_of_lights in [ + 1, + MAX_LIGHTS / 8, + MAX_LIGHTS / 4, + MAX_LIGHTS / 2, + ((MAX_LIGHTS / 2) + MAX_LIGHTS) / 2, + MAX_LIGHTS, + ] { + let mut run = LightTilingStatsRun { + number_of_lights, + iterations: vec![], + }; + + for (i, (_, _, _, light, _)) in lights.iter().enumerate() { + stage.remove_light(light); + if i < number_of_lights { + stage.add_light(light); + } + } + + const NUM_RUNS: usize = 2; + for i in 0..NUM_RUNS { + log::info!("{number_of_lights} {i} running"); + let start = Instant::now(); + let frame = ctx.get_next_frame().unwrap(); + stage.render(&frame.view()); + frame.present(); + ctx.get_device().poll(wgpu::Maintain::wait()); + let duration = start.elapsed(); + run.iterations.push(duration); + } + stats.runs.push(run); + } + plot(stats); +} + +fn snapshot(ctx: &crate::Context, stage: &Stage, path: &str) { + let frame = ctx.get_next_frame().unwrap(); + let start = std::time::Instant::now(); + stage.render(&frame.view()); + let elapsed = start.elapsed(); + log::info!("shapshot: {}s '{path}'", elapsed.as_secs_f32()); + let img = frame.read_image().unwrap(); + img_diff::save(path, img); + frame.present(); +} + +const MAX_LIGHTS: usize = 1024; + +struct LightTilingStatsRun { + number_of_lights: usize, + iterations: Vec, +} + +impl LightTilingStatsRun { + fn avg_frame_time(&self) -> f32 { + let total: Duration = self.iterations.iter().sum(); + total.as_secs_f32() / self.iterations.len() as f32 + } +} + +#[derive(Default)] +struct LightTilingStats { + runs: Vec, +} + +fn plot(stats: LightTilingStats) { + let path = crate::test::workspace_dir().join("test_output/lights/tiling/frame-time.png"); + let root_drawing_area = BitMapBackend::new(&path, (800, 600)).into_drawing_area(); + root_drawing_area.fill(&plotters::style::WHITE).unwrap(); + + let mut chart = ChartBuilder::on(&root_drawing_area) + .caption( + "Renderling lighting frame time", + ("sans-serif", 50).into_font(), + ) + .margin(30) + .margin_right(100) + .x_label_area_size(30) + .y_label_area_size(30) + .build_cartesian_2d( + 0..MAX_LIGHTS + 1, + 0.0..stats + .runs + .iter() + .map(|r| r.avg_frame_time()) + .max_by(|a, b| a.total_cmp(b)) + .unwrap_or_default(), + ) + .unwrap(); + chart + .configure_mesh() + .x_desc("number of lights") + .y_desc("avg fps") + .draw() + .unwrap(); + + chart + .draw_series(LineSeries::new( + stats + .runs + .iter() + .map(|r| (r.number_of_lights, r.avg_frame_time())), + plotters::style::RED, + )) + .unwrap() + .label("without-tiling") + .legend(|(x, y)| { + PathElement::new(vec![(x, y), (x + 20, y)], plotters::style::RED.filled()) + }); + chart + .draw_series(PointSeries::of_element( + stats + .runs + .iter() + .map(|r| (r.number_of_lights, r.avg_frame_time())), + 5, + ShapeStyle::from(&plotters::style::RED).filled(), + &|(num_lights, seconds_per_frame), size, style| { + EmptyElement::at((num_lights, seconds_per_frame)) + + Circle::new((0, 0), size, style) + + Text::new( + format!("({num_lights}, {:.2} fps)", 1.0 / seconds_per_frame), + (0, 15), + ("sans-serif", 15), + ) + }, + )) + .unwrap(); + + chart + .configure_series_labels() + .position(SeriesLabelPosition::LowerRight) + .margin(20) + .label_font(("sans-serif", 20)) + .draw() + .unwrap(); + root_drawing_area.present().unwrap(); +} + +#[test] +/// For all light types: +/// +/// Ensures that a light with a translated position renders the same +/// as a light at the origin that has a transform applied with +/// that same translation. +/// +/// In other words, light in nested transform is the same as light with +/// that same transform pre-applied. +fn pedestal() { + let ctx = crate::Context::headless(256, 256); + let stage = ctx + .new_stage() + .with_lighting(false) + .with_msaa_sample_count(4) + .with_bloom_mix_strength(0.08); + let doc = stage + .load_gltf_document_from_path( + crate::test::workspace_dir() + .join("gltf") + .join("pedestal.glb"), + ) + .unwrap(); + let materials = doc.materials.get_vec(); + log::info!("materials: {materials:#?}"); + doc.materials.set_item( + 0, + Material { + albedo_factor: Vec4::ONE, + roughness_factor: 1.0, + metallic_factor: 0.0, + ..Default::default() + }, + ); + let camera = doc.cameras.first().unwrap(); + camera.camera.modify(|cam| { + cam.set_projection(Mat4::perspective_rh( + std::f32::consts::FRAC_PI_6, + 1.0, + 0.1, + 15.0, + )); + }); + + let color = { + // let mut c = hex_to_vec4(0xEEDF7AFF); + // linear_xfer_vec4(&mut c); + // c + Vec4::ONE + }; + let position = Vec3::new(0.0, 1.0, 0.0); + let transform = stage.new_nested_transform(); + transform.modify(|t| t.translation = position); + + stage.set_has_lighting(true); + + let mut dir_infos = vec![]; + { + log::info!("adding dir light"); + let _dir_light = stage.new_analytical_light( + DirectionalLightDescriptor { + direction: Vec3::new(-0.5, -1.0, 0.0), + color, + intensity: 5.0, + }, + None, + ); + snapshot(&ctx, &stage, "light/pedestal/directional.png"); + + let geometry_slab = + futures_lite::future::block_on(stage.geometry.slab_allocator().read(..)).unwrap(); + + let renderlet = doc.renderlets_iter().next().unwrap(); + log::info!("renderlet: {renderlet:#?}"); + + for vertex_index in 0..renderlet.get().vertices_array.len() { + let mut info = RenderletPbrVertexInfo::default(); + crate::stage::renderlet_vertex( + renderlet.id(), + vertex_index as u32, + &geometry_slab, + &mut Default::default(), + &mut Default::default(), + &mut Default::default(), + &mut Default::default(), + &mut Default::default(), + &mut Default::default(), + &mut Default::default(), + &mut Default::default(), + &mut Default::default(), + &mut info, + ); + + dir_infos.push(info); + } + log::info!("dropping dir light"); + } + assert_eq!(0, stage.lighting.lights().count()); + + { + log::info!("adding point light"); + let _dir_light = stage.new_analytical_light( + PointLightDescriptor { + position, + color, + intensity: 5.0, + }, + None, + ); + snapshot(&ctx, &stage, "light/pedestal/point.png"); + log::info!("dropping point light"); + } + + let bb = BoundingBox { + center: Vec3::ZERO, + half_extent: Vec3::splat(0.25), + }; + // let _light_mesh_rez = stage + // .builder() + // .with_transform_id(transform.global_transform_id()) + // .with_vertices( + // bb.get_mesh() + // .map(|(p, n)| Vertex::default().with_position(p).with_normal(n)), + // ) + // .with_material(Material { + // albedo_factor: color, + // emissive_factor: color.xyz(), + // emissive_strength_multiplier: 4.0, + // ..Default::default() + // }) + // .build(); + { + log::info!("adding spot light"); + let spot_desc = SpotLightDescriptor { + position, + direction: Vec3::NEG_Y, + color, + intensity: 5.0, + ..Default::default() + }; + let _spot = stage.new_analytical_light(spot_desc, None); + snapshot(&ctx, &stage, "light/pedestal/spot.png"); + + let geometry_slab = + futures_lite::future::block_on(stage.geometry.slab_allocator().read(..)).unwrap(); + + let renderlet = doc.renderlets_iter().next().unwrap(); + log::info!("renderlet: {renderlet:#?}"); + let mut spot_infos = vec![]; + + for vertex_index in 0..renderlet.get().vertices_array.len() { + let mut info = RenderletPbrVertexInfo::default(); + crate::stage::renderlet_vertex( + renderlet.id(), + vertex_index as u32, + &geometry_slab, + &mut Default::default(), + &mut Default::default(), + &mut Default::default(), + &mut Default::default(), + &mut Default::default(), + &mut Default::default(), + &mut Default::default(), + &mut Default::default(), + &mut Default::default(), + &mut info, + ); + spot_infos.push(info); + } + + // assert that the output of the vertex shader is the same for the first renderlet, + // regardless of the lighting + pretty_assertions::assert_eq!(dir_infos, spot_infos); + + // let texture = ConstTexture::new(Vec4::ONE); + // let material_slab = + // futures_lite::future::block_on(stage.materials.slab_allocator().read(..)).unwrap(); + // let lighting_slab = + // futures_lite::future::block_on(stage.lighting.slab_allocator().read(..)).unwrap(); + // let mut fragment = Vec4::ZERO; + // crate::pbr::fragment_impl( + // &texture, + // &(), + // &texture, + // &(), + // &texture, + // &(), + // &texture, + // &(), + // &texture, + // &(), + // &geometry_slab, + // &material_slab, + // &lighting_slab, + // info.renderlet_id, + // info.out_color, + // info.out_uv0, + // info.out_uv1, + // info.out_norm, + // info.out_tangent, + // info.out_bitangent, + // info.out_pos, + // &mut fragment, + // ); + + // log::info!("fragment: {fragment}"); + } + + // let light_descriptor = PointLightDescriptor { + // position: Vec3::ZERO, + // color, + // intensity: 10.0, + // }; + // let _light = stage.new_analytical_light(light_descriptor, Some(transform)); + // snapshot(&ctx, &stage, "light/pedestal/point.png"); + + // light.transform.modify(|t| t.translation = position); + + // snapshot(&ctx, &stage, "light/point/transform-nest.png"); + + // let light_slab = + // futures_lite::future::block_on(stage.lighting.light_slab.read(..)).unwrap(); + // let frag = crate::pbr::shade_fragment( + // &ConstTexture::new(Vec4::ZERO), + // &(), + // camera.node_transform.get_global_transform().translation, + // Vec3::Y, + // Vec3::ZERO, + // Vec3::splat(0.5), + // 0.0, + // 1.0, + // 0.0, + // Vec3::ZERO, + // Vec3::ONE, + // Vec3::ONE, + // Vec2::ONE, + // &light_slab, + // ); + // println!("frag: {frag}"); +} diff --git a/crates/renderling/src/light/shadow_map.rs b/crates/renderling/src/light/shadow_map.rs index c6dfe5ee..a03b426f 100644 --- a/crates/renderling/src/light/shadow_map.rs +++ b/crates/renderling/src/light/shadow_map.rs @@ -642,9 +642,10 @@ mod test { let mut shadows = vec![]; let z_near = 0.1; let z_far = 100.0; - for (_i, light_bundle) in doc.lights.iter().enumerate() { + for (i, light_bundle) in doc.lights.iter().enumerate() { { let desc = light_bundle.light_details.as_point().unwrap().get(); + println!("point light {i}: {:?}", desc); let (p, vs) = desc.shadow_mapping_projection_and_view_matrices( &light_bundle.transform.get_global_transform().into(), z_near, diff --git a/crates/renderling/src/light/tiling.rs b/crates/renderling/src/light/tiling.rs index 68becbb5..591be70d 100644 --- a/crates/renderling/src/light/tiling.rs +++ b/crates/renderling/src/light/tiling.rs @@ -9,12 +9,11 @@ use std::sync::Arc; use craballoc::{ runtime::WgpuRuntime, - slab::{SlabAllocator, SlabAllocatorError, SlabBuffer}, + slab::{SlabAllocator, SlabBuffer}, value::{GpuArray, Hybrid}, }; -use crabslab::{Id, Slab}; +use crabslab::Id; use glam::UVec2; -use snafu::OptionExt; use crate::bindgroup::ManagedBindGroup; @@ -22,9 +21,9 @@ use super::{LightTile, LightTilingDescriptor}; pub struct LightTiling { // depth_pre_pass_pipeline: Arc, - tiling_slab: SlabAllocator, - tiling_descriptor: Hybrid, - tiles: GpuArray, + pub(crate) tiling_slab: SlabAllocator, + pub(crate) tiling_descriptor: Hybrid, + _tiles: GpuArray, bind_group_creation_time: Arc, depth_texture_id: Arc, compute_tiles_bind_group_layout: Arc, @@ -113,10 +112,6 @@ impl LightTiling { (compute_tiles_pipeline, pipeline_layout, bind_group_layout) } - pub(crate) fn descriptor(&self) -> &Hybrid { - &self.tiling_descriptor - } - pub fn new( runtime: impl AsRef, multisampled: bool, @@ -148,7 +143,7 @@ impl LightTiling { Self { tiling_slab, tiling_descriptor, - tiles, + _tiles: tiles, bind_group_creation_time: Default::default(), depth_texture_id: Default::default(), compute_tiles_bind_group_layout: compute_tiles_bind_group_layout.into(), @@ -157,17 +152,22 @@ impl LightTiling { } } + pub(crate) fn prepare(&self, depth_texture_size: UVec2) { + self.tiling_descriptor.modify(|d| { + d.depth_texture_size = depth_texture_size; + }); + } + pub fn run( &self, geometry_slab: &SlabBuffer, lighting_slab: &SlabBuffer, depth_texture: &crate::texture::Texture, ) { + let depth_texture_size = depth_texture.size(); + self.prepare(depth_texture_size); + let runtime = self.tiling_slab.runtime(); - let depth_texture_size = self.tiling_descriptor.modify(|d| { - d.depth_texture_size = depth_texture.size(); - d.depth_texture_size - }); let tiling_slab_buffer = self.tiling_slab.commit(); let label = Some("light-tiling-compute-tiles"); let mut encoder = runtime @@ -226,8 +226,8 @@ impl LightTiling { }); compute_pass.set_bind_group(0, bind_group.as_ref(), &[]); - let x = depth_texture_size.x / 16 + 1; - let y = depth_texture_size.y / 16 + 1; + let x = depth_texture_size.x / LightTilingDescriptor::TILE_SIZE.x + 1; + let y = depth_texture_size.y / LightTilingDescriptor::TILE_SIZE.y + 1; let z = 1; compute_pass.dispatch_workgroups(x, y, z); } @@ -238,6 +238,7 @@ impl LightTiling { pub(crate) async fn read_images( &self, ) -> (image::GrayImage, image::GrayImage, image::GrayImage) { + use crabslab::Slab; let size = self.tiling_descriptor.get().depth_texture_size / 16; let slab = self.tiling_slab.read(..).await.unwrap(); log::info!("tiling slab size: {}", slab.len()); diff --git a/crates/renderling/src/math.rs b/crates/renderling/src/math.rs index cd677c6d..f22cde88 100644 --- a/crates/renderling/src/math.rs +++ b/crates/renderling/src/math.rs @@ -6,7 +6,8 @@ //! run on the CPU. //! //! Lastly, it provides some constant geometry used in many shaders. -use core::ops::Mul; +use core::ops::{IndexMut, Mul}; +use crabslab::{Id, Slab}; use spirv_std::{ image::{sample_with, Cubemap, Image2d, Image2dArray, ImageWithMethods}, Image, Sampler, @@ -103,6 +104,130 @@ impl SampleCube for Cubemap { } } +/// Abstraction over shader atomic integer operations. +pub trait IsAtomicSlab: Slab { + /// Perform the following steps atomically with respect to any other atomic + /// accesses within `SCOPE` to the same location: + /// + /// 1. Load through `id` to get an original value, + /// 2. Get a new value through integer addition of 1 to original value, and + /// 3. Store the new value back through `id`. + /// + /// The result is the original value. + fn atomic_i_increment(&mut self, id: Id) -> u32; + fn atomic_u_min( + &mut self, + id: Id, + val: u32, + ) -> u32; + fn atomic_u_max( + &mut self, + id: Id, + val: u32, + ) -> u32; +} + +impl IsAtomicSlab for [u32] { + fn atomic_i_increment(&mut self, id: Id) -> u32 { + let ptr = &mut self[id.index()]; + unsafe { spirv_std::arch::atomic_i_increment::(ptr) } + } + + fn atomic_u_min( + &mut self, + id: Id, + val: u32, + ) -> u32 { + let ptr = &mut self[id.index()]; + unsafe { spirv_std::arch::atomic_u_min::(ptr, val) } + } + + fn atomic_u_max( + &mut self, + id: Id, + val: u32, + ) -> u32 { + let ptr = &mut self[id.index()]; + unsafe { spirv_std::arch::atomic_u_max::(ptr, val) } + } +} + +#[cfg(cpu)] +mod non_atomic { + use super::*; + + /// A slab for testing that is **not** atomic. + pub struct NonAtomicSlab { + inner: T, + } + + impl NonAtomicSlab { + pub fn new(inner: T) -> Self { + NonAtomicSlab { inner } + } + } + + impl Slab for NonAtomicSlab { + fn len(&self) -> usize { + self.inner.len() + } + + fn read_unchecked(&self, id: Id) -> T { + self.inner.read_unchecked(id) + } + + fn write_indexed(&mut self, t: &T, index: usize) -> usize { + self.inner.write_indexed(t, index) + } + + fn write_indexed_slice(&mut self, t: &[T], index: usize) -> usize { + self.inner.write_indexed_slice(t, index) + } + } + + impl IsAtomicSlab for NonAtomicSlab + where + S: Slab + IndexMut, + { + fn atomic_i_increment( + &mut self, + id: Id, + ) -> u32 { + let ptr = &mut self.inner[id.index()]; + let i = *ptr; + *ptr = i + 1; + i + } + + fn atomic_u_min( + &mut self, + id: Id, + val: u32, + ) -> u32 { + let ptr = &mut self.inner[id.index()]; + let original = *ptr; + let new = original.min(val); + *ptr = new; + original + } + + fn atomic_u_max( + &mut self, + id: Id, + val: u32, + ) -> u32 { + let ptr = &mut self.inner[id.index()]; + let original = *ptr; + let new = original.max(val); + *ptr = new; + original + } + } +} + +#[cfg(cpu)] +pub use non_atomic::*; + #[cfg(not(target_arch = "spirv"))] mod cpu { @@ -257,6 +382,11 @@ mod cpu { u as f32 / 255.0 } + pub fn luma_u8_to_vec4(p: &image::Luma) -> Vec4 { + let shade = scaled_u8_to_f32(p.0[0]); + Vec3::splat(shade).extend(1.0) + } + /// Convert an f32 in range 0.0 - 1.0 into a u8 in range 0-255. pub fn scaled_f32_to_u8(f: f32) -> u8 { (f * 255.0) as u8 diff --git a/crates/renderling/src/pbr.rs b/crates/renderling/src/pbr.rs index ef561fcf..973d9b4d 100644 --- a/crates/renderling/src/pbr.rs +++ b/crates/renderling/src/pbr.rs @@ -136,7 +136,7 @@ fn fresnel_schlick_roughness(cos_theta: f32, f0: Vec3, roughness: f32) -> Vec3 { } #[allow(clippy::too_many_arguments)] -fn outgoing_radiance( +pub fn outgoing_radiance( light_color: Vec4, albedo: Vec3, attenuation: f32, @@ -574,8 +574,8 @@ where let lighting_desc = light_slab.read_unchecked(Id::::new(0)); let analytical_lights_array = lighting_desc.analytical_lights_array; my_println!("lights: {analytical_lights_array:?}"); - my_println!("n: {n:?}"); - my_println!("v: {v:?}"); + my_println!("surface normal: {n:?}"); + my_println!("vector from surface to camera: {v:?}"); // accumulated outgoing radiance let mut lo = Vec3::ZERO; @@ -584,6 +584,7 @@ where let light_id = light_slab.read(analytical_lights_array.at(i)); let light = light_slab.read(light_id); let transform = light_slab.read(light.transform_id); + crate::println!("transform: {transform:?}"); let transform = Mat4::from(transform); // determine the light ray and the radiance @@ -595,13 +596,14 @@ where intensity, } = light_slab.read(light.into_point_id()); let position = transform.transform_point3(position); - let frag_to_light = position - in_pos; + let frag_to_light = in_pos - position; // - in_pos; let distance = frag_to_light.length(); if distance == 0.0 { + crate::println!("distance between point light and surface is zero"); continue; } let l = frag_to_light.alt_norm_or_zero(); - let attenuation = intensity * 1.0 / (distance * distance); + let attenuation = intensity / (distance * distance); let radiance = outgoing_radiance(color, albedo, attenuation, v, l, n, metallic, roughness); let shadow = if light.shadow_map_desc_id.is_some() { @@ -623,6 +625,7 @@ where let spot_light_descriptor = light_slab.read(light.into_spot_id()); let calculation = SpotLightCalculation::new(spot_light_descriptor, transform, in_pos); + crate::println!("calculation: {calculation:#?}"); if calculation.frag_to_light_distance == 0.0 { continue; } @@ -671,6 +674,8 @@ where (radiance, shadow) } }; + crate::println!("radiance: {radiance}"); + crate::println!("shadow: {shadow}"); lo += radiance * (1.0 - shadow); } diff --git a/crates/renderling/src/stage/cpu.rs b/crates/renderling/src/stage/cpu.rs index 541f216e..8c441bbc 100644 --- a/crates/renderling/src/stage/cpu.rs +++ b/crates/renderling/src/stage/cpu.rs @@ -96,6 +96,30 @@ impl StageCommitResult { .max() .unwrap_or_default() } + + pub fn should_invalidate(&self, previous_creation_time: usize) -> bool { + let mut should = false; + if self.geometry_buffer.is_new_this_commit() { + log::trace!("geometry buffer is new this frame"); + should = true; + } + if self.materials_buffer.is_new_this_commit() { + log::trace!("materials buffer is new this frame"); + should = true; + } + if self.lighting_buffer.is_new_this_commit() { + log::trace!("lighting buffer is new this frame"); + should = true; + } + let current = self.latest_creation_time(); + if current > previous_creation_time { + log::trace!( + "current latest buffer creation time {current} > previous {previous_creation_time}" + ); + should = true; + } + should + } } struct RenderletBindGroup<'a> { @@ -200,12 +224,13 @@ impl StageRendering<'_> { current_renderlet_bind_group_creation_time, std::sync::atomic::Ordering::Relaxed, ); - let should_invalidate_renderlet_bind_group = current_renderlet_bind_group_creation_time - > previous_renderlet_bind_group_creation_time; + let should_invalidate_renderlet_bind_group = + commit_result.should_invalidate(previous_renderlet_bind_group_creation_time); let renderlet_bind_group = self.stage .renderlet_bind_group .get(should_invalidate_renderlet_bind_group, || { + log::trace!("recreating renderlet bind group"); let atlas_texture = self.stage.materials.atlas().get_texture(); let skybox = self.stage.skybox.read().unwrap(); let shadow_map = self.stage.lighting.shadow_map_atlas.get_texture(); diff --git a/gltf/pedestal.glb b/gltf/pedestal.glb new file mode 100644 index 00000000..fc47e6e8 Binary files /dev/null and b/gltf/pedestal.glb differ