diff --git a/.gitignore b/.gitignore index 4bfd777..71994f6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ *.rdc pilka.cap +_typos.toml /.cargo /shaders /target diff --git a/Cargo.lock b/Cargo.lock index 67b40d6..cd32f91 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "ab_glyph" -version = "0.2.12" +version = "0.2.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20b228f2c198f98d4337ceb560333fb12cbb2f4948a953bf8c57d09deb219603" +checksum = "79faae4620f45232f599d9bc7b290f88247a0834162c4495ab2f02d60004adfb" dependencies = [ "ab_glyph_rasterizer", "owned_ttf_parser", @@ -14,18 +14,9 @@ dependencies = [ [[package]] name = "ab_glyph_rasterizer" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a13739d7177fbd22bb0ed28badfff9f372f8bef46c863db4e1c6248f6b223b6e" - -[[package]] -name = "addr2line" -version = "0.17.0" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" -dependencies = [ - "gimli", -] +checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" [[package]] name = "adler" @@ -35,57 +26,58 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" -dependencies = [ - "getrandom", - "once_cell", - "version_check", -] - -[[package]] -name = "ahash" -version = "0.8.0" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57e6e951cfbb2db8de1828d49073a113a29fd7117b1596caa781a258c7e38d72" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", "getrandom", "once_cell", "version_check", + "zerocopy", ] [[package]] name = "aho-corasick" -version = "0.7.18" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] -name = "alsa" +name = "android-activity" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5915f52fe2cf65e83924d037b6c5290b7cee097c6b5c8700746e6168a343fd6b" +checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" dependencies = [ - "alsa-sys", - "bitflags", + "android-properties", + "bitflags 2.6.0", + "cc", + "cesu8", + "jni", + "jni-sys", "libc", - "nix 0.23.1", + "log", + "ndk", + "ndk-context", + "ndk-sys", + "num_enum", + "thiserror", ] [[package]] -name = "alsa-sys" -version = "0.3.1" +name = "android-properties" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527" -dependencies = [ - "libc", - "pkg-config", -] +checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" [[package]] name = "android_system_properties" @@ -97,153 +89,109 @@ dependencies = [ ] [[package]] -name = "anyhow" -version = "1.0.51" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203" - -[[package]] -name = "arrayref" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" - -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - -[[package]] -name = "arrayvec" -version = "0.7.2" +name = "anstream" +version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] [[package]] -name = "ash" -version = "0.35.1+1.2.203" +name = "anstyle" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7fd04def1c9101b5fb488c131022d2d6f87753ef4b1b11b279e2af404fae6b9" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" [[package]] -name = "ash" -version = "0.37.0+1.3.209" +name = "anstyle-parse" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "006ca68e0f2b03f22d6fa9f2860f85aed430d257fec20f8879b2145e7c7ae1a6" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" dependencies = [ - "libloading", + "utf8parse", ] [[package]] -name = "ash-molten" -version = "0.13.0+1.1.10" +name = "anstyle-query" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ddc8dfcdf7ba11f085ff7a5cf39165c13c6446159f286da1071514f1a5b6e45" +checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" dependencies = [ - "anyhow", - "ash 0.35.1+1.2.203", - "plist", - "serde", + "windows-sys 0.52.0", ] [[package]] -name = "ash-window" -version = "0.12.0" +name = "anstyle-wincon" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b912285a7c29f3a8f87ca6f55afc48768624e5e33ec17dbd2f2075903f5e35ab" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" dependencies = [ - "ash 0.37.0+1.3.209", - "raw-window-handle 0.5.0", - "raw-window-metal", + "anstyle", + "windows-sys 0.52.0", ] [[package]] -name = "atomic_refcell" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73b5e5f48b927f04e952dedc932f31995a65a0bf65ec971c74436e51bf6e970d" - -[[package]] -name = "atty" -version = "0.2.14" +name = "anyhow" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] -name = "autocfg" -version = "1.1.0" +name = "arrayref" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" [[package]] -name = "backtrace" -version = "0.3.63" +name = "arrayvec" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "321629d8ba6513061f26707241fa9bc89524ff1cd7a915a97ef0c62c666ce1b6" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide 0.4.4", - "object", - "rustc-demangle", -] +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] -name = "base64" -version = "0.13.0" +name = "as-raw-xcb-connection" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" [[package]] -name = "bincode" -version = "1.3.3" +name = "ash" +version = "0.38.0+1.3.281" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" dependencies = [ - "serde", + "libloading", ] [[package]] -name = "bindgen" -version = "0.56.0" +name = "ash-window" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da379dbebc0b76ef63ca68d8fc6e71c0f13e59432e0987e508c1820e6ab5239" +checksum = "52bca67b61cb81e5553babde81b8211f713cb6db79766f80168f3e5f40ea6c82" dependencies = [ - "bitflags", - "cexpr", - "clang-sys", - "lazy_static", - "lazycell", - "peeking_take_while", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", + "ash", + "raw-window-handle", + "raw-window-metal", ] [[package]] -name = "bit-set" -version = "0.5.2" +name = "atomic-waker" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de" -dependencies = [ - "bit-vec", -] +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] -name = "bit-vec" -version = "0.6.3" +name = "autocfg" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "bitflags" @@ -251,6 +199,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + [[package]] name = "block" version = "0.1.6" @@ -258,63 +212,73 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" [[package]] -name = "bumpalo" -version = "3.8.0" +name = "block2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c" +checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" +dependencies = [ + "objc2", +] [[package]] -name = "bytemuck" -version = "1.12.1" +name = "bumpalo" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f5715e491b5a1598fc2bef5a606847b5dc1d48ea625bd3c02c00de8285591da" -dependencies = [ - "bytemuck_derive", -] +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] -name = "bytemuck_derive" -version = "1.2.1" +name = "bytemuck" +version = "1.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9e1f5fa78f69496407a27ae9ed989e3c3b072310286f5ef385525e4cbc24a9" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] +checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.1.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "calloop" -version = "0.10.1" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a22a6a8f622f797120d452c630b0ab12e1331a1a753e2039ce7868d4ac77b4ee" +checksum = "fba7adb4dd5aa98e5553510223000e7148f621165ec5f9acd7113f6ca4995298" dependencies = [ + "bitflags 2.6.0", "log", - "nix 0.24.2", - "slotmap", + "polling", + "rustix", + "slab", "thiserror", - "vec_map", +] + +[[package]] +name = "calloop-wayland-source" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f0ea9b9476c7fad82841a8dbb380e2eae480c21910feba80725b46931ed8f02" +dependencies = [ + "calloop", + "rustix", + "wayland-backend", + "wayland-client", ] [[package]] name = "cc" -version = "1.0.72" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" +checksum = "74b6a57f98764a267ff415d50a25e6e166f3831a5071af4995296ea97d210490" dependencies = [ "jobserver", + "libc", + "once_cell", ] [[package]] @@ -323,15 +287,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" -[[package]] -name = "cexpr" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27" -dependencies = [ - "nom 5.1.2", -] - [[package]] name = "cfg-if" version = "1.0.0" @@ -340,134 +295,93 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cfg_aliases" -version = "0.1.1" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.22" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ + "android-tzdata", "iana-time-zone", "js-sys", - "num-integer", "num-traits", - "time 0.1.44", "wasm-bindgen", - "winapi", -] - -[[package]] -name = "clang-sys" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa66045b9cb23c2e9c1520732030608b02ee07e5cfaa5a521ec15ded7fa24c90" -dependencies = [ - "glob", - "libc", - "libloading", + "windows-targets 0.52.6", ] [[package]] name = "cmake" -version = "0.1.46" +version = "0.1.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7b858541263efe664aead4a5209a4ae5c5d2811167d4ed4ee0944503f8d2089" +checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" dependencies = [ "cc", ] [[package]] name = "cocoa" -version = "0.24.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63902e9223530efb4e26ccd0cf55ec30d592d3b42e21a28defc42a9586e832" +checksum = "f6140449f97a6e97f9511815c5632d84c8aacf8ac271ad77c559218161a1373c" dependencies = [ - "bitflags", + "bitflags 1.3.2", "block", "cocoa-foundation", "core-foundation", "core-graphics", - "foreign-types 0.3.2", + "foreign-types", "libc", "objc", ] [[package]] name = "cocoa-foundation" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318" +checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" dependencies = [ - "bitflags", + "bitflags 1.3.2", "block", "core-foundation", "core-graphics-types", - "foreign-types 0.3.2", "libc", "objc", ] [[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] - -[[package]] -name = "color-eyre" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a667583cca8c4f8436db8de46ea8233c42a7d9ae424a82d338f2e4675229204" -dependencies = [ - "backtrace", - "color-spantrace", - "eyre", - "indenter", - "once_cell", - "owo-colors", - "tracing-error", -] - -[[package]] -name = "color-spantrace" -version = "0.2.0" +name = "colorchoice" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ba75b3d9449ecdccb27ecbc479fdc0b87fa2dd43d2f8298f9bf0e59aacc8dce" -dependencies = [ - "once_cell", - "owo-colors", - "tracing-core", - "tracing-error", -] +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" [[package]] name = "combine" -version = "4.6.2" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b2f5d0ee456f3928812dfc8c6d9a1d592b98678f6d56db9b0cd2b7bc6c8db5" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" dependencies = [ "bytes", "memchr", ] [[package]] -name = "copyless" -version = "0.1.5" +name = "concurrent-queue" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2df960f5d869b2dd8532793fde43eb5427cceb126c929747a26823ab0eeb536" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] [[package]] name = "core-foundation" -version = "0.9.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", @@ -475,465 +389,188 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.3" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "core-graphics" -version = "0.22.3" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" +checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "core-graphics-types", - "foreign-types 0.3.2", + "foreign-types", "libc", ] [[package]] name = "core-graphics-types" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", - "foreign-types 0.3.2", "libc", ] [[package]] -name = "core-text" -version = "19.2.0" +name = "crc32fast" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d74ada66e07c1cefa18f8abfba765b486f250de2e4a999e5727fc0dd4b4a25" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ - "core-foundation", - "core-graphics", - "foreign-types 0.3.2", - "libc", + "cfg-if", ] [[package]] -name = "coreaudio-rs" -version = "0.10.0" +name = "crossbeam-channel" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11894b20ebfe1ff903cbdc52259693389eea03b94918a2def2c30c3bf227ad88" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" dependencies = [ - "bitflags", - "coreaudio-sys", + "crossbeam-utils", ] [[package]] -name = "coreaudio-sys" -version = "0.2.8" +name = "crossbeam-utils" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b7e3347be6a09b46aba228d6608386739fb70beff4f61e07422da87b0bb31fa" -dependencies = [ - "bindgen", -] +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] -name = "cpal" -version = "0.14.0" +name = "cursor-icon" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d466b47cf0ea4100186a7c12d7d0166813dda7cf648553554c9c39c6324841b" -dependencies = [ - "alsa", - "core-foundation-sys", - "coreaudio-rs", - "jni", - "js-sys", - "libc", - "mach", - "ndk 0.7.0", - "ndk-context", - "nix 0.23.1", - "oboe", - "once_cell", - "parking_lot", - "stdweb", - "thiserror", - "web-sys", - "windows", -] +checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" [[package]] -name = "crc32fast" -version = "1.3.0" +name = "ddsfile" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "738c290dfaea84fc1ca15ad9c168d083b05a714e1efddd8edaab678dc28d2836" +checksum = "479dfe1e6737aa9e96c6ac7b69689dc4c32da8383f2c12744739d76afa8b66c4" dependencies = [ - "cfg-if", + "bitflags 2.6.0", + "byteorder", + "enum-primitive-derive", + "num-traits", ] [[package]] -name = "crossbeam-channel" -version = "0.5.1" +name = "dispatch" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" [[package]] -name = "crossbeam-utils" -version = "0.8.8" +name = "dlib" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" dependencies = [ - "cfg-if", - "lazy_static", + "libloading", ] [[package]] -name = "crossfont" -version = "0.5.0" +name = "downcast-rs" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f66b1c1979c4362323f03ab6bf7fb522902bfc418e0c37319ab347f9561d980f" -dependencies = [ - "cocoa", - "core-foundation", - "core-foundation-sys", - "core-graphics", - "core-text", - "dwrote", - "foreign-types 0.5.0", - "freetype-rs", - "libc", - "log", - "objc", - "once_cell", - "pkg-config", - "servo-fontconfig", - "winapi", -] +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" [[package]] -name = "cty" -version = "0.2.2" +name = "dpi" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" +checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" [[package]] -name = "cxx" -version = "1.0.79" +name = "either" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f83d0ebf42c6eafb8d7c52f7e5f2d3003b89c7aa4fd2b79229209459a849af8" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] -name = "cxx-build" -version = "1.0.79" +name = "enum-primitive-derive" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07d050484b55975889284352b0ffc2ecbda25c0c55978017c132b29ba0818a86" +checksum = "c375b9c5eadb68d0a6efee2999fef292f45854c3444c86f09d8ab086ba942b0e" dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", + "num-traits", "quote", - "scratch", - "syn", + "syn 1.0.109", ] [[package]] -name = "cxxbridge-flags" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d2199b00553eda8012dfec8d3b1c75fce747cf27c169a270b3b99e3448ab78" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.79" +name = "env_filter" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb67a6de1f602736dd7eaead0080cf3435df806c61b24b13328db128c58868f" +checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" dependencies = [ - "proc-macro2", - "quote", - "syn", + "log", + "regex", ] [[package]] -name = "d3d12" -version = "0.5.0" +name = "env_logger" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "827914e1f53b1e0e025ecd3d967a7836b7bcb54520f90e21ef8df7b4d88a2759" +checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" dependencies = [ - "bitflags", - "libloading", - "winapi", + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", ] [[package]] -name = "darling" -version = "0.10.2" +name = "equivalent" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" -dependencies = [ - "darling_core 0.10.2", - "darling_macro 0.10.2", -] - -[[package]] -name = "darling" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0d720b8683f8dd83c65155f0530560cba68cd2bf395f6513a483caee57ff7f4" -dependencies = [ - "darling_core 0.13.1", - "darling_macro 0.13.1", -] - -[[package]] -name = "darling_core" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim 0.9.3", - "syn", -] - -[[package]] -name = "darling_core" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a340f241d2ceed1deb47ae36c4144b2707ec7dd0b649f894cb39bb595986324" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim 0.10.0", - "syn", -] - -[[package]] -name = "darling_macro" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" -dependencies = [ - "darling_core 0.10.2", - "quote", - "syn", -] - -[[package]] -name = "darling_macro" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c41b3b7352feb3211a0d743dc5700a4e3b60f51bd2b368892d1e0f9a95f44b" -dependencies = [ - "darling_core 0.13.1", - "quote", - "syn", -] - -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "dispatch" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" - -[[package]] -name = "dlib" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac1b7517328c04c2aa68422fc60a41b92208182142ed04a25879c26c8f878794" -dependencies = [ - "libloading", -] - -[[package]] -name = "downcast-rs" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] -name = "dwrote" -version = "0.11.0" +name = "errno" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439a1c2ba5611ad3ed731280541d36d2e9c4ac5e7fb818a27b604bdc5a6aa65b" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ - "lazy_static", "libc", - "serde", - "serde_derive", - "winapi", - "wio", -] - -[[package]] -name = "egui" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc9fcd393c3daaaf5909008a1d948319d538b79c51871e4df0993260260a94e4" -dependencies = [ - "ahash 0.8.0", - "epaint", - "nohash-hasher", -] - -[[package]] -name = "egui-wgpu" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f12a8d8f92a429e2e9399003bc01d48f54aefa6fec126cbd3462e313c0ee0e91" -dependencies = [ - "bytemuck", - "egui", - "pollster", - "tracing", - "type-map", - "wgpu 0.13.1", - "winit", -] - -[[package]] -name = "egui_wgpu_backend" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9a4a022610dec7cb5ccce43d397727d190ca38b7c988dece516d585c96caa6" -dependencies = [ - "bytemuck", - "egui", - "wgpu 0.14.0", -] - -[[package]] -name = "egui_winit_platform" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34fb1c870207c14b99fb7ed9a8760fd7be9a0d96b3516ead3a5e3abe7bb88400" -dependencies = [ - "egui", - "winit", -] - -[[package]] -name = "emath" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9542a40106fdba943a055f418d1746a050e1a903a049b030c2b097d4686a33cf" -dependencies = [ - "bytemuck", -] - -[[package]] -name = "env_logger" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c90bf5f19754d10198ccb95b70664fc925bd1fc090a0fd9a6ebc54acc8cd6272" -dependencies = [ - "atty", - "humantime", - "log", - "regex", - "termcolor", -] - -[[package]] -name = "epaint" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ba04741be7f6602b1a1b28f1082cce45948a7032961c52814f8946b28493300" -dependencies = [ - "ab_glyph", - "ahash 0.8.0", - "atomic_refcell", - "bytemuck", - "emath", - "nohash-hasher", - "parking_lot", -] - -[[package]] -name = "expat-sys" -version = "2.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658f19728920138342f68408b7cf7644d90d4784353d8ebc32e7e8663dbe45fa" -dependencies = [ - "cmake", - "pkg-config", + "windows-sys 0.52.0", ] [[package]] -name = "eyre" -version = "0.6.8" +name = "fdeflate" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" +checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" dependencies = [ - "indenter", - "once_cell", + "simd-adler32", ] [[package]] name = "filetime" -version = "0.2.15" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ "cfg-if", "libc", - "redox_syscall", - "winapi", + "redox_syscall 0.4.1", + "windows-sys 0.52.0", ] -[[package]] -name = "fixedbitset" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "398ea4fabe40b9b0d885340a2a991a44c8a645624075ad966d21f88688e2b69e" - [[package]] name = "flate2" -version = "1.0.24" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" dependencies = [ "crc32fast", - "miniz_oxide 0.5.4", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared 0.1.1", + "miniz_oxide", ] [[package]] @@ -943,175 +580,97 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" dependencies = [ "foreign-types-macros", - "foreign-types-shared 0.3.1", + "foreign-types-shared", ] [[package]] name = "foreign-types-macros" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8469d0d40519bc608ec6863f1cc88f3f1deee15913f2f3b3e573d81ed38cccc" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.68", ] -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "foreign-types-shared" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" -[[package]] -name = "freetype-rs" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74eadec9d0a5c28c54bb9882e54787275152a4e36ce206b45d7451384e5bf5fb" -dependencies = [ - "bitflags", - "freetype-sys", - "libc", -] - -[[package]] -name = "freetype-sys" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a37d4011c0cc628dfa766fcc195454f4b068d7afdc2adfd28861191d866e731a" -dependencies = [ - "cmake", - "libc", - "pkg-config", -] - [[package]] name = "fsevent-sys" -version = "4.0.0" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c0e564d24da983c053beff1bb7178e237501206840a3e6bf4e267b9e8ae734a" +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" dependencies = [ "libc", ] [[package]] -name = "fxhash" -version = "0.2.1" +name = "gethostname" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" dependencies = [ - "byteorder", + "libc", + "windows-targets 0.48.5", ] [[package]] name = "getrandom" -version = "0.2.3" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", "wasi", ] -[[package]] -name = "gimli" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" - -[[package]] -name = "glob" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" - -[[package]] -name = "glow" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c07210904884e8e2e6a2d7f36f39040a9cefe3b379b721969b5275e9f5b464a" -dependencies = [ - "js-sys", - "slotmap", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "gpu-alloc" -version = "0.5.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e64cbb8d36508d3e19da95e56e196a84f674fc190881f2cc010000798838aa6" +checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" dependencies = [ - "bitflags", + "bitflags 2.6.0", "gpu-alloc-types", ] [[package]] -name = "gpu-alloc-types" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54804d0d6bc9d7f26db4eaec1ad10def69b599315f487d32c334a80d1efe67a5" -dependencies = [ - "bitflags", -] - -[[package]] -name = "gpu-descriptor" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a538f217be4d405ff4719a283ca68323cc2384003eca5baaa87501e821c81dda" -dependencies = [ - "bitflags", - "gpu-descriptor-types", - "hashbrown 0.11.2", -] - -[[package]] -name = "gpu-descriptor-types" -version = "0.1.1" +name = "gpu-alloc-ash" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "363e3677e55ad168fef68cf9de3a4a310b53124c5e784c53a1d70e92d23f2126" +checksum = "cbda7a18a29bc98c2e0de0435c347df935bf59489935d0cbd0b73f1679b6f79a" dependencies = [ - "bitflags", + "ash", + "gpu-alloc-types", + "tinyvec", ] [[package]] -name = "hashbrown" -version = "0.11.2" +name = "gpu-alloc-types" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" dependencies = [ - "ahash 0.7.6", + "bitflags 2.6.0", ] [[package]] name = "hashbrown" -version = "0.12.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hexf-parse" -version = "0.2.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" [[package]] name = "humantime" @@ -1121,49 +680,35 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "iana-time-zone" -version = "0.1.51" +version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5a6ef98976b22b3b7f2f3a806f858cb862044cfa66805aa3ad84cb3d3b785ed" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "winapi", + "windows-core", ] [[package]] name = "iana-time-zone-haiku" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ - "cxx", - "cxx-build", + "cc", ] -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "indenter" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" - [[package]] name = "indexmap" -version = "1.9.1" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ - "autocfg", - "hashbrown 0.12.3", - "serde", + "equivalent", + "hashbrown", ] [[package]] @@ -1172,7 +717,7 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" dependencies = [ - "bitflags", + "bitflags 1.3.2", "inotify-sys", "libc", ] @@ -1187,41 +732,25 @@ dependencies = [ ] [[package]] -name = "inplace_it" -version = "0.3.3" +name = "is_terminal_polyfill" +version = "1.70.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90953f308a79fe6d62a4643e51f848fbfddcd05975a38e69fdf4ab86a7baf7ca" - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" [[package]] name = "jni" -version = "0.19.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" dependencies = [ "cesu8", + "cfg-if", "combine", "jni-sys", "log", "thiserror", "walkdir", + "windows-sys 0.45.0", ] [[package]] @@ -1232,38 +761,27 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.24" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.60" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] -[[package]] -name = "khronos-egl" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c2352bd1d0bceb871cb9d40f24360c8133c11d7486b68b5381c1dd1a32015e3" -dependencies = [ - "libc", - "libloading", - "pkg-config", -] - [[package]] name = "kqueue" -version = "1.0.4" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "058a107a784f8be94c7d35c1300f4facced2e93d2fbe5b1452b44e905ddca4a9" +checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c" dependencies = [ "kqueue-sys", "libc", @@ -1271,74 +789,52 @@ dependencies = [ [[package]] name = "kqueue-sys" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8367585489f01bc55dd27404dcf56b95e6da061a256a666ab23be9ba96a2e587" +checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" dependencies = [ - "bitflags", + "bitflags 1.3.2", "libc", ] -[[package]] -name = "ktx" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0112c5d660975a0c6e068c0901b9178d9aeeb62106eac227cbab2502955ea9f8" -dependencies = [ - "byteorder", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - [[package]] name = "libc" -version = "0.2.132" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libloading" -version = "0.7.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afe203d669ec979b7128619bae5a63b7b42e9203c1b29146079ee05e2f604b52" +checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d" dependencies = [ "cfg-if", - "winapi", + "windows-targets 0.52.6", ] [[package]] -name = "line-wrap" -version = "0.1.1" +name = "libredox" +version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9" +checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607" dependencies = [ - "safemem", + "bitflags 2.6.0", + "libc", + "redox_syscall 0.4.1", ] [[package]] -name = "link-cplusplus" -version = "1.0.7" +name = "linux-raw-sys" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" -dependencies = [ - "cc", -] +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "lock_api" -version = "0.4.7" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -1346,21 +842,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "mach" -version = "0.3.2" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" -dependencies = [ - "libc", -] +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "malloc_buf" @@ -1373,471 +857,372 @@ dependencies = [ [[package]] name = "memchr" -version = "2.4.1" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" -version = "0.5.7" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95af15f345b17af2efc8ead6080fb8bc376f8cec1b35277b935637595fe77498" +checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" dependencies = [ "libc", ] -[[package]] -name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] - -[[package]] -name = "metal" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de11355d1f6781482d027a3b4d4de7825dcedb197bf573e0596d00008402d060" -dependencies = [ - "bitflags", - "block", - "core-graphics-types", - "foreign-types 0.3.2", - "log", - "objc", -] - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - [[package]] name = "miniz_oxide" -version = "0.4.4" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" -dependencies = [ - "adler", - "autocfg", -] - -[[package]] -name = "miniz_oxide" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", + "simd-adler32", ] [[package]] name = "mio" -version = "0.8.0" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba272f85fa0b41fc91872be579b3bbe0f56b792aa361a380eb669469f68dafb2" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", - "miow", - "ntapi", - "winapi", -] - -[[package]] -name = "miow" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" -dependencies = [ - "winapi", + "wasi", + "windows-sys 0.48.0", ] [[package]] -name = "naga" +name = "ndk" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f50357e1167a3ab92d6b3c7f4bf5f7fd13fde3f4b28bf0d5ea07b5100fdb6c0" -dependencies = [ - "bit-set", - "bitflags", - "codespan-reporting", - "hexf-parse", - "indexmap", - "log", - "num-traits", - "rustc-hash", - "spirv", - "termcolor", - "thiserror", - "unicode-xid", -] - -[[package]] -name = "naga" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "262d2840e72dbe250e8cf2f522d080988dfca624c4112c096238a4845f591707" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bit-set", - "bitflags", - "codespan-reporting", - "hexf-parse", - "indexmap", + "bitflags 2.6.0", + "jni-sys", "log", - "num-traits", - "petgraph", - "pp-rs", - "rustc-hash", - "spirv", - "termcolor", + "ndk-sys", + "num_enum", + "raw-window-handle", "thiserror", - "unicode-xid", ] [[package]] -name = "natord" -version = "1.0.9" +name = "ndk-context" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308d96db8debc727c3fd9744aac51751243420e46edf401010908da7f8d5e57c" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" [[package]] -name = "ndk" -version = "0.4.0" +name = "ndk-sys" +version = "0.6.0+11769913" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d64d6af06fde0e527b1ba5c7b79a6cc89cfc46325b0b2887dffe8f70197e0c3c" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" dependencies = [ - "bitflags", "jni-sys", - "ndk-sys 0.2.2", - "num_enum", - "thiserror", ] [[package]] -name = "ndk" -version = "0.7.0" +name = "notify" +version = "6.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0" +checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" dependencies = [ - "bitflags", - "jni-sys", - "ndk-sys 0.4.0", - "num_enum", - "raw-window-handle 0.5.0", - "thiserror", + "bitflags 2.6.0", + "crossbeam-channel", + "filetime", + "fsevent-sys", + "inotify", + "kqueue", + "libc", + "log", + "mio", + "walkdir", + "windows-sys 0.48.0", ] [[package]] -name = "ndk-context" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" - -[[package]] -name = "ndk-glue" -version = "0.4.0" +name = "notify-debouncer-mini" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e9e94628f24e7a3cb5b96a2dc5683acd9230bf11991c2a1677b87695138420" +checksum = "5d40b221972a1fc5ef4d858a2f671fb34c75983eb385463dff3780eeff6a9d43" dependencies = [ - "lazy_static", - "libc", + "crossbeam-channel", "log", - "ndk 0.4.0", - "ndk-macro 0.2.0", - "ndk-sys 0.2.2", + "notify", ] [[package]] -name = "ndk-glue" -version = "0.7.0" +name = "num-traits" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0434fabdd2c15e0aab768ca31d5b7b333717f03cf02037d5a0a3ff3c278ed67f" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ - "libc", - "log", - "ndk 0.7.0", - "ndk-context", - "ndk-macro 0.3.0", - "ndk-sys 0.4.0", - "once_cell", - "parking_lot", + "autocfg", ] [[package]] -name = "ndk-macro" -version = "0.2.0" +name = "num_enum" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d" +checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" dependencies = [ - "darling 0.10.2", - "proc-macro-crate 0.1.5", - "proc-macro2", - "quote", - "syn", + "num_enum_derive", ] [[package]] -name = "ndk-macro" -version = "0.3.0" +name = "num_enum_derive" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0df7ac00c4672f9d5aece54ee3347520b7e20f158656c7db2e6de01902eb7a6c" +checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" dependencies = [ - "darling 0.13.1", - "proc-macro-crate 1.1.0", + "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 2.0.68", ] [[package]] -name = "ndk-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1bcdd74c20ad5d95aacd60ef9ba40fdf77f767051040541df557b7a9b2a2121" - -[[package]] -name = "ndk-sys" -version = "0.4.0" +name = "objc" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21d83ec9c63ec5bf950200a8e508bdad6659972187b625469f58ef8c08e29046" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" dependencies = [ - "jni-sys", + "malloc_buf", ] [[package]] -name = "nix" -version = "0.22.3" +name = "objc-sys" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4916f159ed8e5de0082076562152a76b7a1f64a01fd9d1e0fea002c37624faf" -dependencies = [ - "bitflags", - "cc", - "cfg-if", - "libc", - "memoffset", -] +checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" [[package]] -name = "nix" -version = "0.23.1" +name = "objc2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" +checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" dependencies = [ - "bitflags", - "cc", - "cfg-if", - "libc", - "memoffset", + "objc-sys", + "objc2-encode", ] [[package]] -name = "nix" -version = "0.24.2" +name = "objc2-app-kit" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "195cdbc1741b8134346d515b3a56a1c94b0912758009cfd53f99ea0f57b065fc" +checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ - "bitflags", - "cfg-if", + "bitflags 2.6.0", + "block2", "libc", - "memoffset", -] - -[[package]] -name = "nohash-hasher" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" - -[[package]] -name = "nom" -version = "5.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" -dependencies = [ - "memchr", - "version_check", + "objc2", + "objc2-core-data", + "objc2-core-image", + "objc2-foundation", + "objc2-quartz-core", ] [[package]] -name = "nom" -version = "7.1.0" +name = "objc2-cloud-kit" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109" +checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" dependencies = [ - "memchr", - "minimal-lexical", - "version_check", + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-core-location", + "objc2-foundation", ] [[package]] -name = "notify" -version = "5.0.0" +name = "objc2-contacts" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2c66da08abae1c024c01d635253e402341b4060a12e99b31c7594063bf490a" +checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" dependencies = [ - "bitflags", - "crossbeam-channel", - "filetime", - "fsevent-sys", - "inotify", - "kqueue", - "libc", - "mio", - "walkdir", - "winapi", + "block2", + "objc2", + "objc2-foundation", ] [[package]] -name = "ntapi" -version = "0.3.6" +name = "objc2-core-data" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" +checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ - "winapi", + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-foundation", ] [[package]] -name = "num-complex" -version = "0.4.0" +name = "objc2-core-image" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26873667bbbb7c5182d4a37c1add32cdf09f841af72da53318fdb81543c15085" +checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" dependencies = [ - "num-traits", + "block2", + "objc2", + "objc2-foundation", + "objc2-metal", ] [[package]] -name = "num-derive" -version = "0.3.3" +name = "objc2-core-location" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" dependencies = [ - "proc-macro2", - "quote", - "syn", + "block2", + "objc2", + "objc2-contacts", + "objc2-foundation", ] [[package]] -name = "num-integer" -version = "0.1.44" +name = "objc2-encode" +version = "4.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" -dependencies = [ - "autocfg", - "num-traits", -] +checksum = "7891e71393cd1f227313c9379a26a584ff3d7e6e7159e988851f0934c993f0f8" [[package]] -name = "num-traits" -version = "0.2.14" +name = "objc2-foundation" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "autocfg", + "bitflags 2.6.0", + "block2", + "dispatch", + "libc", + "objc2", ] [[package]] -name = "num_enum" -version = "0.5.4" +name = "objc2-link-presentation" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9bd055fb730c4f8f4f57d45d35cd6b3f0980535b056dc7ff119cee6a66ed6f" +checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" dependencies = [ - "derivative", - "num_enum_derive", + "block2", + "objc2", + "objc2-app-kit", + "objc2-foundation", ] [[package]] -name = "num_enum_derive" -version = "0.5.4" +name = "objc2-metal" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "486ea01961c4a818096de679a8b740b26d9033146ac5291b1c98557658f8cdd9" +checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ - "proc-macro-crate 1.1.0", - "proc-macro2", - "quote", - "syn", + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-foundation", ] [[package]] -name = "objc" -version = "0.2.7" +name = "objc2-quartz-core" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ - "malloc_buf", - "objc_exception", + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-foundation", + "objc2-metal", ] [[package]] -name = "objc_exception" -version = "0.1.2" +name = "objc2-symbols" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" +checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc" dependencies = [ - "cc", + "objc2", + "objc2-foundation", ] [[package]] -name = "object" -version = "0.27.1" +name = "objc2-ui-kit" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9" +checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" dependencies = [ - "memchr", + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-cloud-kit", + "objc2-core-data", + "objc2-core-image", + "objc2-core-location", + "objc2-foundation", + "objc2-link-presentation", + "objc2-quartz-core", + "objc2-symbols", + "objc2-uniform-type-identifiers", + "objc2-user-notifications", ] [[package]] -name = "oboe" -version = "0.4.4" +name = "objc2-uniform-type-identifiers" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e15e22bc67e047fe342a32ecba55f555e3be6166b04dd157cd0f803dfa9f48e1" +checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" dependencies = [ - "jni", - "ndk 0.4.0", - "ndk-glue 0.4.0", - "num-derive", - "num-traits", - "oboe-sys", + "block2", + "objc2", + "objc2-foundation", ] [[package]] -name = "oboe-sys" -version = "0.4.4" +name = "objc2-user-notifications" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "338142ae5ab0aaedc8275aa8f67f460e43ae0fca76a695a742d56da0a269eadc" +checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ - "cc", + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-core-location", + "objc2-foundation", ] [[package]] name = "once_cell" -version = "1.14.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] -name = "owned_ttf_parser" -version = "0.13.2" +name = "orbclient" +version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65ee3f72636e6f164cc41c9f9057f4e58c4e13507699ea7f5e5242b64b8198ee" +checksum = "52f0d54bde9774d3a51dcf281a5def240c71996bc6ca05d2c847ec8b2b216166" dependencies = [ - "ttf-parser", + "libredox", ] [[package]] -name = "owo-colors" -version = "3.2.0" +name = "owned_ttf_parser" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20448fd678ec04e6ea15bbe0476874af65e98a01515d667aa49f1434dc44ebf4" +checksum = "490d3a563d3122bf7c911a59b0add9389e5ec0f5f0c3ac6b91ff235a0e6a7f90" +dependencies = [ + "ttf-parser", +] [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -1845,309 +1230,210 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.3" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.5.2", "smallvec", - "windows-sys", + "windows-targets 0.52.6", ] -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" - [[package]] name = "percent-encoding" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" - -[[package]] -name = "petgraph" -version = "0.6.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f" -dependencies = [ - "fixedbitset", - "indexmap", -] +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pilka" -version = "0.7.11" +version = "0.8.0" dependencies = [ + "ahash", + "anyhow", + "ash", + "ash-window", + "bitflags 2.6.0", + "bytemuck", "chrono", - "color-eyre", - "cpal", "crossbeam-channel", - "egui", - "egui-wgpu", - "egui_wgpu_backend", - "egui_winit_platform", + "ddsfile", + "either", "env_logger", - "eyre", - "naga 0.10.0", + "gpu-alloc", + "gpu-alloc-ash", "notify", - "pilka_ash", - "pilka_types", - "pilka_wgpu", + "notify-debouncer-mini", + "parking_lot", "png", - "pollster", - "puffin", - "puffin_egui", - "raw-window-handle 0.5.0", - "rustfft", + "raw-window-handle", "shaderc", + "slotmap", "winit", ] [[package]] -name = "pilka_ash" -version = "0.7.11" -dependencies = [ - "ash 0.37.0+1.3.209", - "ash-molten", - "ash-window", - "bytemuck", - "ktx", - "pilka_types", - "puffin", - "raw-window-handle 0.5.0", -] - -[[package]] -name = "pilka_types" -version = "0.7.10" +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" dependencies = [ - "bytemuck", + "pin-project-internal", ] [[package]] -name = "pilka_wgpu" -version = "0.7.11" +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ - "bytemuck", - "color-eyre", - "env_logger", - "notify", - "pilka_types", - "pollster", - "puffin", - "raw-window-handle 0.5.0", - "smaa", - "wgpu 0.14.0", - "winit", + "proc-macro2", + "quote", + "syn 2.0.68", ] [[package]] name = "pin-project-lite" -version = "0.2.7" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pkg-config" -version = "0.3.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f" - -[[package]] -name = "plist" -version = "1.3.1" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd39bc6cdc9355ad1dc5eeedefee696bb35c34caf21768741e81826c0bbd7225" -dependencies = [ - "base64", - "indexmap", - "line-wrap", - "serde", - "time 0.3.5", - "xml-rs", -] +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "png" -version = "0.17.6" +version = "0.17.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f0e7f4c94ec26ff209cee506314212639d6c91b80afb82984819fafce9df01c" +checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" dependencies = [ - "bitflags", + "bitflags 1.3.2", "crc32fast", + "fdeflate", "flate2", - "miniz_oxide 0.5.4", -] - -[[package]] -name = "pollster" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5da3b0203fd7ee5720aa0b5e790b591aa5d3f41c3ed2c34a3a393382198af2f7" - -[[package]] -name = "pp-rs" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb458bb7f6e250e6eb79d5026badc10a3ebb8f9a15d1fff0f13d17c71f4d6dee" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "primal-check" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01419cee72c1a1ca944554e23d83e483e1bccf378753344e881de28b5487511d" -dependencies = [ - "num-integer", + "miniz_oxide", ] [[package]] -name = "proc-macro-crate" -version = "0.1.5" +name = "polling" +version = "3.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +checksum = "a3ed00ed3fbf728b5816498ecd316d1716eecaced9c0c8d2c5a6740ca214985b" dependencies = [ - "toml", + "cfg-if", + "concurrent-queue", + "hermit-abi", + "pin-project-lite", + "rustix", + "tracing", + "windows-sys 0.52.0", ] [[package]] name = "proc-macro-crate" -version = "1.1.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ebace6889caf889b4d3f76becee12e90353f2b8c7d875534a71e5742f8f6f83" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" dependencies = [ - "thiserror", - "toml", + "toml_edit", ] [[package]] name = "proc-macro2" -version = "1.0.47" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] -name = "profiling" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9926767b8b8244d7b6b64546585121d193c3d0b4856ccd656b7bfa9deb91ab6a" - -[[package]] -name = "puffin" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b40725b2702b9c660938b8d9c56978091252374cc50d73a83b59695b8d32ec03" -dependencies = [ - "anyhow", - "bincode", - "byteorder", - "once_cell", - "parking_lot", - "ruzstd", - "serde", - "zstd", -] - -[[package]] -name = "puffin_egui" -version = "0.17.0" +name = "quick-xml" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e39069dce952a38613121233b06f40cdc5864b12f9c8c9fb2b12de07d1841de5" +checksum = "6f24d770aeca0eacb81ac29dfbc55ebcc09312fdd1f8bbecdc7e4a84e000e3b4" dependencies = [ - "chrono", - "egui", - "indexmap", - "natord", - "once_cell", - "puffin", - "vec1", + "memchr", ] [[package]] name = "quote" -version = "1.0.10" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] -[[package]] -name = "range-alloc" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63e935c45e09cc6dcf00d2f0b2d630a58f4095320223d47fc68918722f0538b6" - [[package]] name = "raw-window-handle" -version = "0.4.3" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b800beb9b6e7d2df1fe337c9e3d04e3af22a124460fb4c30fcc22c9117cefb41" -dependencies = [ - "cty", -] +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" [[package]] -name = "raw-window-handle" -version = "0.5.0" +name = "raw-window-metal" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed7e3d950b66e19e0c372f3fa3fbbcf85b1746b571f74e0c2af6042a5c93420a" +checksum = "76e8caa82e31bb98fee12fa8f051c94a6aa36b07cddb03f0d4fc558988360ff1" dependencies = [ - "cty", + "cocoa", + "core-graphics", + "objc", + "raw-window-handle", ] [[package]] -name = "raw-window-metal" -version = "0.3.0" +name = "redox_syscall" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d18241d631f19847a5f4cc0a3f81d978202c375573ab7d90ab14dcf0a9262ec" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ - "cocoa", - "core-graphics", - "objc", - "raw-window-handle 0.5.0", + "bitflags 1.3.2", ] [[package]] name = "redox_syscall" -version = "0.2.10" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" dependencies = [ - "bitflags", + "bitflags 2.6.0", ] [[package]] name = "regex" -version = "1.5.6" +version = "1.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" dependencies = [ "aho-corasick", "memchr", + "regex-automata", "regex-syntax", ] [[package]] -name = "regex-syntax" -version = "0.6.26" +name = "regex-automata" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] [[package]] -name = "renderdoc-sys" -version = "0.7.1" +name = "regex-syntax" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1382d1f0a252c4bf97dc20d979a2fdd05b024acd7c2ed0f7595d7817666a157" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "roxmltree" @@ -2159,56 +1445,18 @@ dependencies = [ ] [[package]] -name = "rustc-demangle" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustfft" -version = "6.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d089e5c57521629a59f5f39bca7434849ff89bd6873b521afe389c1c602543" -dependencies = [ - "num-complex", - "num-integer", - "num-traits", - "primal-check", - "strength_reduce", - "transpose", -] - -[[package]] -name = "ruzstd" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cada0ef59efa6a5f4dc5e491f93d9f31e3fc7758df421ff1de8a706338e1100" -dependencies = [ - "byteorder", - "twox-hash", -] - -[[package]] -name = "safe_arch" -version = "0.5.2" +name = "rustix" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ff3d6d9696af502cc3110dacce942840fb06ff4514cad92236ecc455f2ce05" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bytemuck", + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", ] -[[package]] -name = "safemem" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" - [[package]] name = "same-file" version = "1.0.6" @@ -2220,80 +1468,54 @@ dependencies = [ [[package]] name = "scoped-tls" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" [[package]] name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "scratch" -version = "1.0.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sctk-adwaita" -version = "0.4.2" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04b7c47a572f73de28bee5b5060d085b42b6ce1e4ee2b49c956ea7b25e94b6f0" +checksum = "7555fcb4f753d095d734fdefebb0ad8c98478a21db500492d87c55913d3b0086" dependencies = [ - "crossfont", + "ab_glyph", "log", + "memmap2", "smithay-client-toolkit", "tiny-skia", ] [[package]] name = "serde" -version = "1.0.130" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.130" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn", -] - -[[package]] -name = "servo-fontconfig" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7e3e22fe5fd73d04ebf0daa049d3efe3eae55369ce38ab16d07ddd9ac5c217c" -dependencies = [ - "libc", - "servo-fontconfig-sys", -] - -[[package]] -name = "servo-fontconfig-sys" -version = "5.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e36b879db9892dfa40f95da1c38a835d41634b825fbd8c4c418093d53c24b388" -dependencies = [ - "expat-sys", - "freetype-sys", - "pkg-config", + "syn 2.0.68", ] [[package]] name = "shaderc" -version = "0.8.0" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e6fe602a861622769530a23bc40bfba31adbf186d0c8412e83f5519c5d6bee" +checksum = "27e07913ada18607bb60d12431cbe3358d3bbebbe95948e1618851dc01e63b7b" dependencies = [ "libc", "shaderc-sys", @@ -2301,9 +1523,9 @@ dependencies = [ [[package]] name = "shaderc-sys" -version = "0.8.0" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3794498651f8173d0afbc0bb8aca45ced111098227e755dde4c0ef2888c8d0bf" +checksum = "73120d240fe22196300f39ca8547ca2d014960f27b19b47b21288b396272f7f7" dependencies = [ "cmake", "libc", @@ -2311,109 +1533,80 @@ dependencies = [ ] [[package]] -name = "sharded-slab" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "shlex" -version = "0.1.1" +name = "simd-adler32" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" [[package]] -name = "slotmap" -version = "1.0.6" +name = "slab" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ - "version_check", + "autocfg", ] [[package]] -name = "smaa" -version = "0.8.0" +name = "slotmap" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6dcfff0d71ba0df57e47b557468f703a91efe3d22f703bf6b702dd9957423e3" +checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" dependencies = [ - "naga 0.10.0", - "wgpu 0.14.0", + "version_check", ] [[package]] name = "smallvec" -version = "1.7.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "smithay-client-toolkit" -version = "0.16.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f307c47d32d2715eb2e0ece5589057820e0e5e70d07c247d1063e844e107f454" +checksum = "922fd3eeab3bd820d76537ce8f582b1cf951eceb5475c28500c7457d9d17f53a" dependencies = [ - "bitflags", + "bitflags 2.6.0", "calloop", - "dlib", - "lazy_static", + "calloop-wayland-source", + "cursor-icon", + "libc", "log", "memmap2", - "nix 0.24.2", - "pkg-config", + "rustix", + "thiserror", + "wayland-backend", "wayland-client", + "wayland-csd-frame", "wayland-cursor", "wayland-protocols", + "wayland-protocols-wlr", + "wayland-scanner", + "xkeysym", ] [[package]] -name = "spirv" -version = "0.2.0+1.5.4" +name = "smol_str" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "246bfa38fe3db3f1dfc8ca5a2cdeb7348c78be2112740cc0ec8ef18b6d94f830" +checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" dependencies = [ - "bitflags", - "num-traits", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "stdweb" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef5430c8e36b713e13b48a9f709cc21e046723fe44ce34587b73a830203b533e" - -[[package]] -name = "strength_reduce" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3ff2f71c82567c565ba4b3009a9350a96a7269eaa4001ebedae926230bc2254" - -[[package]] -name = "strsim" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" + "serde", +] [[package]] -name = "strsim" -version = "0.10.0" +name = "strict-num" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" [[package]] name = "syn" -version = "1.0.102" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", @@ -2421,203 +1614,132 @@ dependencies = [ ] [[package]] -name = "termcolor" -version = "1.1.2" +name = "syn" +version = "2.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" dependencies = [ - "winapi-util", + "proc-macro2", + "quote", + "unicode-ident", ] [[package]] name = "thiserror" -version = "1.0.30" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.30" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn", -] - -[[package]] -name = "thread_local" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" -dependencies = [ - "once_cell", -] - -[[package]] -name = "time" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" -dependencies = [ - "libc", - "wasi", - "winapi", -] - -[[package]] -name = "time" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41effe7cfa8af36f439fac33861b66b049edc6f9a32331e2312660529c1c24ad" -dependencies = [ - "itoa", - "libc", + "syn 2.0.68", ] [[package]] name = "tiny-skia" -version = "0.7.0" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "642680569bb895b16e4b9d181c60be1ed136fa0c9c7f11d004daf053ba89bf82" +checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab" dependencies = [ "arrayref", - "arrayvec 0.5.2", + "arrayvec", "bytemuck", "cfg-if", - "png", - "safe_arch", + "log", "tiny-skia-path", ] [[package]] name = "tiny-skia-path" -version = "0.7.0" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c114d32f0c2ee43d585367cb013dfaba967ab9f62b90d9af0d696e955e70fa6c" +checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93" dependencies = [ "arrayref", "bytemuck", + "strict-num", ] [[package]] -name = "toml" -version = "0.5.8" +name = "tinyvec" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +checksum = "ce6b6a2fb3a985e99cebfaefa9faa3024743da73304ca1c683a36429613d3d22" dependencies = [ - "serde", + "tinyvec_macros", ] [[package]] -name = "tracing" -version = "0.1.29" +name = "tinyvec_macros" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" -dependencies = [ - "cfg-if", - "pin-project-lite", - "tracing-core", -] +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] -name = "tracing-core" -version = "0.1.21" +name = "toml_datetime" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" -dependencies = [ - "lazy_static", -] +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" [[package]] -name = "tracing-error" -version = "0.2.0" +name = "toml_edit" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ - "tracing", - "tracing-subscriber", + "indexmap", + "toml_datetime", + "winnow", ] [[package]] -name = "tracing-subscriber" -version = "0.3.7" +name = "tracing" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5312f325fe3588e277415f5a6cca1f4ccad0f248c4cd5a4bd33032d7286abc22" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "sharded-slab", - "thread_local", + "pin-project-lite", "tracing-core", ] [[package]] -name = "transpose" -version = "0.2.1" +name = "tracing-core" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95f9c900aa98b6ea43aee227fd680550cdec726526aab8ac801549eadb25e39f" -dependencies = [ - "num-integer", - "strength_reduce", -] +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" [[package]] name = "ttf-parser" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76dacc724328b3d5e2ed67f9e30cdb56893a34ab239032502cc8f19f8dae4bbc" - -[[package]] -name = "twox-hash" -version = "1.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" -dependencies = [ - "cfg-if", - "static_assertions", -] - -[[package]] -name = "type-map" -version = "0.5.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deb68604048ff8fa93347f02441e4487594adc20bb8a084f9e564d2b827a0a9f" -dependencies = [ - "rustc-hash", -] +checksum = "8686b91785aff82828ed725225925b33b4fde44c4bb15876e5f7c832724c420a" [[package]] name = "unicode-ident" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" - -[[package]] -name = "unicode-width" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" - -[[package]] -name = "unicode-xid" -version = "0.2.3" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] -name = "vec1" -version = "1.8.0" +name = "unicode-segmentation" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fc1631c774f0f9570797191e01247cbefde789eebfbf128074cb934115a6133" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] -name = "vec_map" -version = "0.8.2" +name = "utf8parse" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "version_check" @@ -2627,26 +1749,25 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "walkdir" -version = "2.3.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", - "winapi", "winapi-util", ] [[package]] name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.83" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2654,24 +1775,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.83" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.68", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.33" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ "cfg-if", "js-sys", @@ -2681,9 +1802,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.83" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2691,510 +1812,515 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.83" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.68", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.83" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] -name = "wayland-client" -version = "0.29.5" +name = "wayland-backend" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f3b068c05a039c9f755f881dc50f01732214f5685e379829759088967c46715" +checksum = "269c04f203640d0da2092d1b8d89a2d081714ae3ac2f1b53e99f205740517198" dependencies = [ - "bitflags", + "cc", "downcast-rs", - "libc", - "nix 0.24.2", + "rustix", "scoped-tls", - "wayland-commons", - "wayland-scanner", + "smallvec", "wayland-sys", ] [[package]] -name = "wayland-commons" -version = "0.29.5" +name = "wayland-client" +version = "0.31.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8691f134d584a33a6606d9d717b95c4fa20065605f798a3f350d78dced02a902" +checksum = "08bd0f46c069d3382a36c8666c1b9ccef32b8b04f41667ca1fef06a1adcc2982" dependencies = [ - "nix 0.24.2", - "once_cell", - "smallvec", - "wayland-sys", + "bitflags 2.6.0", + "rustix", + "wayland-backend", + "wayland-scanner", +] + +[[package]] +name = "wayland-csd-frame" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" +dependencies = [ + "bitflags 2.6.0", + "cursor-icon", + "wayland-backend", ] [[package]] name = "wayland-cursor" -version = "0.29.1" +version = "0.31.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c19bb6628daf4097e58b7911481e8371e13318d5a60894779901bd3267407a7" +checksum = "09414bcf0fd8d9577d73e9ac4659ebc45bcc9cff1980a350543ad8e50ee263b2" dependencies = [ - "nix 0.22.3", + "rustix", "wayland-client", "xcursor", ] [[package]] name = "wayland-protocols" -version = "0.29.5" +version = "0.31.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4" +dependencies = [ + "bitflags 2.6.0", + "wayland-backend", + "wayland-client", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-plasma" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23803551115ff9ea9bce586860c5c5a971e360825a0309264102a9495a5ff479" +dependencies = [ + "bitflags 2.6.0", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-wlr" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b950621f9354b322ee817a23474e479b34be96c2e909c14f7bc0100e9a970bc6" +checksum = "ad1f61b76b6c2d8742e10f9ba5c3737f6530b4c243132c2a2ccc8aa96fe25cd6" dependencies = [ - "bitflags", + "bitflags 2.6.0", + "wayland-backend", "wayland-client", - "wayland-commons", + "wayland-protocols", "wayland-scanner", ] [[package]] name = "wayland-scanner" -version = "0.29.5" +version = "0.31.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53" +checksum = "edf466fc49a4feb65a511ca403fec3601494d0dee85dbf37fff6fa0dd4eec3b6" dependencies = [ "proc-macro2", + "quick-xml", "quote", - "xml-rs", ] [[package]] name = "wayland-sys" -version = "0.29.5" +version = "0.31.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be12ce1a3c39ec7dba25594b97b42cb3195d54953ddb9d3d95a7c3902bc6e9d4" +checksum = "4a6754825230fa5b27bafaa28c30b3c9e72c55530581220cef401fa422c0fae7" dependencies = [ "dlib", - "lazy_static", + "log", + "once_cell", "pkg-config", ] [[package]] name = "web-sys" -version = "0.3.60" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] -name = "wgpu" -version = "0.13.1" +name = "web-time" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "277e967bf8b7820a76852645a6bce8bbd31c32fda2042e82d8e3ea75fda8892d" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ - "arrayvec 0.7.2", "js-sys", - "log", - "naga 0.9.0", - "parking_lot", - "raw-window-handle 0.4.3", - "smallvec", "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "wgpu-core 0.13.2", - "wgpu-hal 0.13.2", - "wgpu-types 0.13.2", ] [[package]] -name = "wgpu" -version = "0.14.0" +name = "winapi-util" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2272b17bffc8a0c7d53897435da7c1db587c87d3a14e8dae9cdb8d1d210fc0f" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ - "arrayvec 0.7.2", - "js-sys", - "log", - "naga 0.10.0", - "parking_lot", - "raw-window-handle 0.5.0", - "smallvec", - "static_assertions", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "wgpu-core 0.14.0", - "wgpu-hal 0.14.0", - "wgpu-types 0.14.0", + "windows-sys 0.52.0", ] [[package]] -name = "wgpu-core" -version = "0.13.2" +name = "windows-core" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b92788dec9d0c1bed849a1b83f01b2ee12819bf04a79c90f68e4173f7b5ba2" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "arrayvec 0.7.2", - "bit-vec", - "bitflags", - "cfg_aliases", - "codespan-reporting", - "copyless", - "fxhash", - "log", - "naga 0.9.0", - "parking_lot", - "profiling", - "raw-window-handle 0.4.3", - "smallvec", - "thiserror", - "web-sys", - "wgpu-hal 0.13.2", - "wgpu-types 0.13.2", + "windows-targets 0.52.6", ] [[package]] -name = "wgpu-core" -version = "0.14.0" +name = "windows-sys" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73d14cad393054caf992ee02b7da6a372245d39a484f7461c1f44f6f6359bd28" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "arrayvec 0.7.2", - "bit-vec", - "bitflags", - "cfg_aliases", - "codespan-reporting", - "fxhash", - "log", - "naga 0.10.0", - "parking_lot", - "profiling", - "raw-window-handle 0.5.0", - "smallvec", - "thiserror", - "web-sys", - "wgpu-hal 0.14.0", - "wgpu-types 0.14.0", + "windows-targets 0.42.2", ] [[package]] -name = "wgpu-hal" -version = "0.13.2" +name = "windows-sys" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cbdfc3d0637dba3d5536b93adef3d26023a0b96f0e1ee5ee9560a401d9f646" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "android_system_properties", - "arrayvec 0.7.2", - "ash 0.37.0+1.3.209", - "bit-set", - "bitflags", - "block", - "core-graphics-types", - "d3d12", - "foreign-types 0.3.2", - "fxhash", - "glow", - "gpu-alloc", - "gpu-descriptor", - "inplace_it", - "js-sys", - "khronos-egl", - "libloading", - "log", - "metal", - "naga 0.9.0", - "objc", - "parking_lot", - "profiling", - "range-alloc", - "raw-window-handle 0.4.3", - "renderdoc-sys", - "thiserror", - "wasm-bindgen", - "web-sys", - "wgpu-types 0.13.2", - "winapi", + "windows-targets 0.48.5", ] [[package]] -name = "wgpu-hal" -version = "0.14.0" +name = "windows-sys" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdae6a80dbc725343f02f854b310b37190be946aeea65e9d83afaa7d840ebaac" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "android_system_properties", - "arrayvec 0.7.2", - "ash 0.37.0+1.3.209", - "bit-set", - "bitflags", - "block", - "core-graphics-types", - "d3d12", - "foreign-types 0.3.2", - "fxhash", - "glow", - "gpu-alloc", - "gpu-descriptor", - "js-sys", - "khronos-egl", - "libloading", - "log", - "metal", - "naga 0.10.0", - "objc", - "parking_lot", - "profiling", - "range-alloc", - "raw-window-handle 0.5.0", - "renderdoc-sys", - "smallvec", - "thiserror", - "wasm-bindgen", - "web-sys", - "wgpu-types 0.14.0", - "winapi", + "windows-targets 0.52.6", ] [[package]] -name = "wgpu-types" -version = "0.13.2" +name = "windows-targets" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f762cbc08e1a51389859cf9c199c7aef544789cf3510889aab12c607f701604" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" dependencies = [ - "bitflags", + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", ] [[package]] -name = "wgpu-types" -version = "0.14.0" +name = "windows-targets" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28fb86c1909233c804aa79b7dd1ad06ebd979b2a465e3e980582db0ea9e69f3f" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "bitflags", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] -name = "winapi" -version = "0.3.9" +name = "windows-targets" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "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 = "winapi-i686-pc-windows-gnu" -version = "0.4.0" +name = "windows_aarch64_gnullvm" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] -name = "winapi-util" -version = "0.1.5" +name = "windows_aarch64_gnullvm" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +name = "windows_aarch64_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] -name = "windows" -version = "0.37.0" +name = "windows_aarch64_msvc" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57b543186b344cc61c85b5aab0d2e3adf4e0f99bc076eff9aa5927bcc0b8a647" -dependencies = [ - "windows_aarch64_msvc 0.37.0", - "windows_i686_gnu 0.37.0", - "windows_i686_msvc 0.37.0", - "windows_x86_64_gnu 0.37.0", - "windows_x86_64_msvc 0.37.0", -] +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] -name = "windows-sys" -version = "0.36.1" +name = "windows_aarch64_msvc" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" -dependencies = [ - "windows_aarch64_msvc 0.36.1", - "windows_i686_gnu 0.36.1", - "windows_i686_msvc 0.36.1", - "windows_x86_64_gnu 0.36.1", - "windows_x86_64_msvc 0.36.1", -] +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.36.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] -name = "windows_aarch64_msvc" -version = "0.37.0" +name = "windows_i686_gnu" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2623277cb2d1c216ba3b578c0f3cf9cdebeddb6e66b1b218bb33596ea7769c3a" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_gnu" -version = "0.36.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.37.0" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[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_msvc" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3925fd0b0b804730d44d4b6278c50f9699703ec49bcd628020f46f4ba07d9e1" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_i686_msvc" -version = "0.36.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.37.0" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce907ac74fe331b524c1298683efbf598bb031bc84d5e274db2083696d07c57c" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnu" -version = "0.36.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.37.0" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2babfba0828f2e6b32457d5341427dcbb577ceef556273229959ac23a10af33d" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "windows_x86_64_msvc" -version = "0.36.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.37.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4dd6dc7df2d84cf7b33822ed5b86318fb1781948e9663bacd047fc9dd52259d" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winit" -version = "0.27.4" +version = "0.30.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37f64802920c4c35d12a53dad5e0c55bbc3004d8dc4f2e4dd64ad02c5665d7aa" +checksum = "49f45a7b7e2de6af35448d7718dab6d95acec466eb3bb7a56f4d31d1af754004" dependencies = [ - "bitflags", - "cocoa", + "ahash", + "android-activity", + "atomic-waker", + "bitflags 2.6.0", + "block2", + "bytemuck", + "calloop", + "cfg_aliases", + "concurrent-queue", "core-foundation", "core-graphics", - "dispatch", - "instant", + "cursor-icon", + "dpi", + "js-sys", "libc", - "log", - "mio", - "ndk 0.7.0", - "ndk-glue 0.7.0", - "objc", - "once_cell", - "parking_lot", + "memmap2", + "ndk", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "objc2-ui-kit", + "orbclient", "percent-encoding", - "raw-window-handle 0.4.3", - "raw-window-handle 0.5.0", + "pin-project", + "raw-window-handle", + "redox_syscall 0.4.1", + "rustix", "sctk-adwaita", "smithay-client-toolkit", + "smol_str", + "tracing", + "unicode-segmentation", "wasm-bindgen", + "wasm-bindgen-futures", + "wayland-backend", "wayland-client", "wayland-protocols", + "wayland-protocols-plasma", "web-sys", - "windows-sys", + "web-time", + "windows-sys 0.52.0", "x11-dl", + "x11rb", + "xkbcommon-dl", ] [[package]] -name = "wio" -version = "0.2.2" +name = "winnow" +version = "0.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" dependencies = [ - "winapi", + "memchr", ] [[package]] name = "x11-dl" -version = "2.19.1" +version = "2.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea26926b4ce81a6f5d9d0f3a0bc401e5a37c6ae14a1bfaa8ff6099ca80038c59" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" dependencies = [ - "lazy_static", "libc", + "once_cell", "pkg-config", ] [[package]] -name = "xcursor" -version = "0.3.4" +name = "x11rb" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7" +checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" dependencies = [ - "nom 7.1.0", + "as-raw-xcb-connection", + "gethostname", + "libc", + "libloading", + "once_cell", + "rustix", + "x11rb-protocol", ] [[package]] -name = "xml-rs" -version = "0.8.4" +name = "x11rb-protocol" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" +checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" [[package]] -name = "xmlparser" -version = "0.13.3" +name = "xcursor" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "114ba2b24d2167ef6d67d7d04c8cc86522b87f490025f39f0303b7db5bf5e3d8" +checksum = "6a0ccd7b4a5345edfcd0c3535718a4e9ff7798ffc536bb5b5a0e26ff84732911" [[package]] -name = "zstd" -version = "0.11.2+zstd.1.5.2" +name = "xkbcommon-dl" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" dependencies = [ - "zstd-safe", + "bitflags 2.6.0", + "dlib", + "log", + "once_cell", + "xkeysym", ] [[package]] -name = "zstd-safe" -version = "5.0.2+zstd.1.5.2" +name = "xkeysym" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" + +[[package]] +name = "xmlparser" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" + +[[package]] +name = "zerocopy" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ - "libc", - "zstd-sys", + "zerocopy-derive", ] [[package]] -name = "zstd-sys" -version = "2.0.1+zstd.1.5.2" +name = "zerocopy-derive" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fd07cbbc53846d9145dbffdf6dd09a7a0aa52be46741825f5c97bdd4f73f12b" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ - "cc", - "libc", + "proc-macro2", + "quote", + "syn 2.0.68", ] diff --git a/Cargo.toml b/Cargo.toml index 53751ca..f06c97e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "pilka" -version = "0.7.11" +version = "0.8.0" authors = ["Alex Komissarov "] edition = "2021" license = "MIT" description = "Another live-coding tool for creating shaders demos." repository = "https://github.com/pudnax/pilka/" readme = "README.md" -keywords = ["graphics", "vulkan", "wgpu", "shaders", "creative"] +keywords = ["graphics", "vulkan", "shaders", "creative"] exclude = [".gitignore", "examples", ".github", "menger_sponge.png", "screenshots", "recordings", "shader_dump"] categories = ["command-line-utilities", "graphics", "rendering"] @@ -15,55 +15,41 @@ categories = ["command-line-utilities", "graphics", "rendering"] appveyor = { repository = "https://github.com/pudnax/pilka", branch = "master", service = "github" } maintenance = { status = "experimental" } -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[workspace] -members = ["pilka_ash", "pilka_wgpu", "pilka_types"] - [dependencies] -# Ecosystem choice for crossplatform window -winit = "0.27.4" -raw-window-handle = "0.5.0" +# Ecosystem choice for crossplatform windows +raw-window-handle = "0.6.2" +winit = "0.30" +ash = "0.38" +ash-window = "0.13" +bitflags = "2" +bytemuck = "1.16" +ahash = "0.8" +slotmap = "1.0" +either = "1.13" +parking_lot = "0.12" +gpu-alloc = "0.6.0" +gpu-alloc-ash = "0.7.0" # Fancy-pants errors -color-eyre = "0.6.2" -eyre = "0.6.8" - -pilka_ash = { version = "0.7.9", path = "pilka_ash" } -pilka_wgpu = { version = "0.7.9", path = "pilka_wgpu" } -pilka_types = { version = "0.7.1", path = "pilka_types" } +anyhow = "1.0" # Crossplatform filesystem event handler -notify = "5.0.0" +notify = "^6" +notify-debouncer-mini = "0.4" # Deps for image manipulations -chrono = "0.4.22" -png = "0.17.6" - -# Sounds analysis -cpal = "0.14.0" -rustfft = "6.0.1" +chrono = "0.4" +png = "0.17" -crossbeam-channel = "0.5.1" -env_logger = "0.9.1" +crossbeam-channel = "0.5.13" +env_logger = "0.11.3" # Shader compiler -shaderc = "0.8.0" - -# Blocking executor -pollster = "0.2.5" - -# GUI profiler dependencies -puffin = "0.13.3" -puffin_egui = "0.17.0" -egui_wgpu_backend = "0.20.0" -egui_winit_platform = "0.16.0" -egui = "0.19.0" -egui-wgpu = { version = "0.19.0", features = ["winit"] } - -#Shader compiler -naga = {version = "0.10.0", features = ["wgsl-in", "span", "spv-out", "wgsl-out", "validate"] } +shaderc = "0.8" +ddsfile = "0.5.2" -[profile.release] +[profile.deploy] +inherits = "release" lto = true [profile.dev.package.'*'] diff --git a/assets/BLUE_RGBA_0.dds b/assets/BLUE_RGBA_0.dds new file mode 100644 index 0000000..3a22adc Binary files /dev/null and b/assets/BLUE_RGBA_0.dds differ diff --git a/assets/dither.dds b/assets/dither.dds new file mode 100644 index 0000000..57a7620 Binary files /dev/null and b/assets/dither.dds differ diff --git a/assets/noise.dds b/assets/noise.dds new file mode 100644 index 0000000..c810702 Binary files /dev/null and b/assets/noise.dds differ diff --git a/examples/balls/shaders/prelude.glsl b/examples/balls/shaders/prelude.glsl deleted file mode 100644 index dfd2a4d..0000000 --- a/examples/balls/shaders/prelude.glsl +++ /dev/null @@ -1,95 +0,0 @@ -#define PI 3.14159265359 -#define TWOPI 6.28318530718 - -const vec3 EPS = vec3(0., 0.01, 0.001); -const float HIT_DIST = EPS.y; -const int MAX_STEPS = 100; -const float MISS_DIST = 10.0; - -const float WIDTH = 2.0; -const float HALF_WIDTH = 1.0; - -float worldSDF(vec3 rayPos); - -vec2 ray_march(vec3 rayPos, vec3 rayDir) { - float dist = 0.0; - - for(int i = 0; i < MAX_STEPS; i++) { - vec3 pos = rayPos + (dist * rayDir); - float posToScene = worldSDF(pos); - dist += posToScene; - if(abs(posToScene) < HIT_DIST) return vec2(dist, i); - if(posToScene > MISS_DIST) break; - } - - return vec2(-dist, MAX_STEPS); -} - -float crossSDF(vec3 rayPos) { - const vec3 corner = vec3(HALF_WIDTH); - vec3 ray = abs(rayPos); - vec3 cornerToRay = ray - corner; - float minComp = min(min(cornerToRay.x, cornerToRay.y), cornerToRay.z); - float maxComp = max(max(cornerToRay.x, cornerToRay.y), cornerToRay.z); - float midComp = cornerToRay.x + cornerToRay.y + cornerToRay.z - - minComp - maxComp; - vec2 closestOutsidePoint = max(vec2(minComp, midComp), 0.0); - vec2 closestInsidePoint = min(vec2(midComp, maxComp), 0.0); - return (midComp > 0.0) ? length(closestOutsidePoint) : -length(closestInsidePoint); -} - -float cubeSDF(vec3 rayPos) { - const vec3 corner = vec3(HALF_WIDTH); - vec3 ray = abs(rayPos); - vec3 cornerToRay = ray - corner; - float cornerToRayMaxComponent = max(max(cornerToRay.x, cornerToRay.y), cornerToRay.z); - float distToInsideRay = min(cornerToRayMaxComponent, 0.0); - vec3 closestToOusideRay = max(cornerToRay, 0.0); - return length(closestToOusideRay) + distToInsideRay; -} - -float squareSDF(vec2 rayPos) { - const vec2 corner = vec2(HALF_WIDTH); - vec2 ray = abs(rayPos.xy); - vec2 cornerToRay = ray - corner; - float cornerToRayMaxComponent = max(cornerToRay.x, cornerToRay.y); - float distToInsideRay = min(cornerToRayMaxComponent, 0.0); - vec2 closestToOusideRay = max(cornerToRay, 0.0); - return length(closestToOusideRay) + distToInsideRay; -} - -float sphereSDF(vec3 rayPosition, vec3 sphereCenterPosition, float radius) { - vec3 centerToRay = rayPosition - sphereCenterPosition; - float distToCenter = length(centerToRay); - return distToCenter - radius; -} - -float sphereSDF(vec3 rayPos, float radius) { - return length(rayPos) - radius; -} - -float sphereSDF(vec3 rayPos) { - return length(rayPos) - HALF_WIDTH; -} - -float yplaneSDF(vec3 rayPos) { - return abs(rayPos.y); -} - -mat2 rotate(float angle) { - float sine = sin(angle); - float cosine = cos(angle); - return mat2(cosine, -sine, sine, cosine); -} - -vec3 enlight(in vec3 at, vec3 normal, vec3 diffuse, vec3 l_color, vec3 l_pos) { - vec3 l_dir = l_pos - at; - return diffuse * l_color * max(0., dot(normal, normalize(l_dir))) / - dot(l_dir, l_dir); -} - -vec3 wnormal(in vec3 p) { - return normalize(vec3(worldSDF(p + EPS.yxx) - worldSDF(p - EPS.yxx), - worldSDF(p + EPS.xyx) - worldSDF(p - EPS.xyx), - worldSDF(p + EPS.xxy) - worldSDF(p - EPS.xxy))); -} \ No newline at end of file diff --git a/examples/balls/shaders/shader.comp b/examples/balls/shaders/shader.comp deleted file mode 100644 index cf230a0..0000000 --- a/examples/balls/shaders/shader.comp +++ /dev/null @@ -1,34 +0,0 @@ -#version 460 - -layout(std430, push_constant) uniform PushConstant { - vec3 pos; - float time; - vec2 resolution; - vec2 mouse; - float spectrum; - bool mouse_pressed; -} pc; - -layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in; - -layout (binding = 0, rgba8) uniform image2D previous_frame; -layout (binding = 1, rgba8) uniform image2D generic_texture; -layout (binding = 2, rgba8) uniform image2D dummy_texture; -layout (binding = 3, r32f) uniform image2D float_texture1; -layout (binding = 4, r32f) uniform image2D float_texture2; - -void main() { - if (gl_GlobalInvocationID.x >= pc.resolution.x || - gl_GlobalInvocationID.y >= pc.resolution.y) { - return; - } - - float time = pc.time; - vec2 p = gl_GlobalInvocationID.xy; - float col = sin(p.x / 13.2 - cos(time) * 5) * cos(p.y / 25.1 + time); - col = 0.; - col = smoothstep(col, col + 5.9, 0.2 + p.x / p.y); - /* col += cos(p.x) + sin(p.y + time); */ - - imageStore(generic_texture, ivec2(p), vec4(col)); -} diff --git a/examples/balls/shaders/shader.frag b/examples/balls/shaders/shader.frag deleted file mode 100644 index aa1b54c..0000000 --- a/examples/balls/shaders/shader.frag +++ /dev/null @@ -1,122 +0,0 @@ -#version 460 - -// In the beginning, colours never existed. There's nothing that was done before you... - -layout(location = 0) in vec2 in_uv; -layout(location = 0) out vec4 out_color; - -layout(set = 0, binding = 0) uniform sampler2D previous_frame; -layout(set = 0, binding = 1) uniform sampler2D generic_texture; -layout(set = 0, binding = 2) uniform sampler2D dummy_texture; -layout(set = 0, binding = 3) uniform sampler2D float_texture1; -layout(set = 0, binding = 4) uniform sampler2D float_texture2; -#define T(t) (texture(t, vec2(in_uv.x, -in_uv.y))) -#define T_off(t,off) (texture(t, vec2(in_uv.x + off.x, -(in_uv.y + off.y)))) - -layout(std430, push_constant) uniform PushConstant { - vec3 pos; - float time; - vec2 resolution; - vec2 mouse; - float spectrum; - bool mouse_pressed; -} pc; - -#define TRACE_STEPS 128 -#define TRACE_EPSILON .001 -#define REFLECT_EPSILON .1 -#define TRACE_DISTANCE 30. -#define NORMAL_EPSILON .01 -#define REFLECT_DEPTH 4 -#define NUM_BALLS 7 -#define CUBEMAP_SIZE 128 - -vec3 balls[NUM_BALLS]; - -float touching_balls(in vec3 at) { - float sum = 0.; - for (int i = 0; i < NUM_BALLS; ++i) { - float r = length(balls[i] - at); - sum += 1. / (r * r); - } - return 1. - sum; -} - -void update_balls(float t) { - for (int i = 0; i < NUM_BALLS; ++i) { - balls[i] = - 3. * vec3(sin(.3 + float(i + 1) * t), cos(1.7 + float(i - 5) * t), - 1.1 * sin(2.3 + float(i + 7) * t)); - } -} - -float world(in vec3 at) { - return touching_balls(at); -} - -vec3 normal(in vec3 at) { - vec2 e = vec2(0., NORMAL_EPSILON); - return normalize(vec3(world(at + e.yxx) - world(at), - world(at + e.xyx) - world(at), - world(at + e.xxy) - world(at))); -} - -vec4 raymarch(in vec3 pos, in vec3 dir, in float maxL) { - float l = 0.; - for (int i = 0; i < TRACE_STEPS; ++i) { - float d = world(pos + dir * l); - if (d < TRACE_EPSILON * l) - break; - l += d; - if (l > maxL) - break; - } - return vec4(pos + dir * l, l); -} - -vec3 lookAtDir(in vec3 dir, in vec3 pos, in vec3 at) { - vec3 f = normalize(at - pos); - vec3 r = cross(f, vec3(0., 1., 0.)); - vec3 u = cross(r, f); - return normalize(dir.x * r + dir.y * u + dir.z * f); -} - -vec3 cube(in vec3 v) { - float M = max(max(abs(v.x), abs(v.y)), abs(v.z)); - float scale = (float(CUBEMAP_SIZE) - 1.) / float(CUBEMAP_SIZE); - if (abs(v.x) != M) v.x *= scale; - if (abs(v.y) != M) v.y *= scale; - if (abs(v.z) != M) v.z *= scale; - return texture(generic_texture, v.xy).xyz; -} - -void main() { - vec2 uv = (in_uv + -0.5) * 2.0 / vec2(pc.resolution.y / pc.resolution.x, 1); - float t = pc.time * .11; - update_balls(t); - - vec3 pos = vec3(cos(2. + 4. * cos(t)) * 10., 2. + 8. * cos(t * .8), - 10. * sin(2. + 3. * cos(t))); - vec3 dir = lookAtDir(normalize(vec3(uv, 2.)), pos.xyz, vec3(balls[0])); - - vec3 color = vec3(0.); - float k = 1.; - for (int reflections = 0; reflections < REFLECT_DEPTH; ++reflections) { - vec4 tpos = raymarch(pos, dir, TRACE_DISTANCE); - if (tpos.w >= TRACE_DISTANCE) { - /* color += sin(dir) + cos(dir); */ - /* color += T(generic_texture).rgb * 0.1; */ - /* color += T(generic_texture).rgb * 0.1; */ - - color += cube(dir); - break; - } - color += vec3(0.1) * k; - k *= 0.6; - dir = normalize(reflect(dir, normal(tpos.xyz))); - pos = tpos.xyz + dir * REFLECT_EPSILON; - } - - out_color = vec4(color, 1.0); - /* out_color = vec4(T(generic_texture).rgb, 1.); */ -} diff --git a/examples/balls/shaders/shader.vert b/examples/balls/shaders/shader.vert deleted file mode 100644 index ed48525..0000000 --- a/examples/balls/shaders/shader.vert +++ /dev/null @@ -1,18 +0,0 @@ -#version 460 - -layout(location = 0) out vec2 out_uv; - -layout(std430, push_constant) uniform PushConstant { - vec3 pos; - float time; - vec2 resolution; - vec2 mouse; - float spectrum; - bool mouse_pressed; -} -pc; - -void main() { - out_uv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); - gl_Position = vec4(out_uv * 2.0f + -1.0f, 0.0, 1.0); -} diff --git a/examples/cellular_automata/cellular-automata.gif b/examples/cellular_automata/cellular-automata.gif deleted file mode 100644 index 24ef46e..0000000 Binary files a/examples/cellular_automata/cellular-automata.gif and /dev/null differ diff --git a/examples/cellular_automata/shaders/prelude.glsl b/examples/cellular_automata/shaders/prelude.glsl deleted file mode 100644 index e69de29..0000000 diff --git a/examples/cellular_automata/shaders/shader.comp b/examples/cellular_automata/shaders/shader.comp deleted file mode 100644 index a3182b6..0000000 --- a/examples/cellular_automata/shaders/shader.comp +++ /dev/null @@ -1,131 +0,0 @@ -#version 460 - -layout(std430, push_constant) uniform PushConstant { - vec3 pos; - float time; - vec2 resolution; - vec2 mouse; - bool mouse_pressed; - uint frame; - float time_delta; - float record_period; -} pc; - -layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in; - -layout (binding = 0, rgba8) uniform image2D previous_frame; -layout (binding = 1, rgba8) uniform image2D generic_texture; -layout (binding = 2, rgba8) uniform image2D dummy_texture; -layout (binding = 3, r32f) uniform image2D float_texture1; -layout (binding = 4, r32f) uniform image2D float_texture2; - -#define PI acos(-1.) - -// You'd never existed without vim macros :/ -const int PATTERN_SIZE = 216; -const vec2 PATTERN[PATTERN_SIZE] = vec2[]( - vec2(-7, -7),vec2(-7, -6),vec2(-7, -5),vec2(-7, -4),vec2(-7, -3),vec2(-7, -2),vec2(-7, -1), - vec2(-7, 0), vec2(-7, 1), vec2(-7, 2), vec2(-7, 3), vec2(-7, 4), vec2(-7, 5), vec2(-7, 6), - vec2(-7, 7), vec2(-6, -7),vec2(-6, -6),vec2(-6, -5),vec2(-6, -4),vec2(-6, -3),vec2(-6, -2), - vec2(-6, -1),vec2(-6, 0), vec2(-6, 1), vec2(-6, 2), vec2(-6, 3), vec2(-6, 4), vec2(-6, 5), - vec2(-6, 6), vec2(-6, 7), vec2(-5, -7),vec2(-5, -6),vec2(-5, -5),vec2(-5, -4),vec2(-5, -3), - vec2(-5, -2),vec2(-5, -1),vec2(-5, 0), vec2(-5, 1), vec2(-5, 2), vec2(-5, 3), vec2(-5, 4), - vec2(-5, 5), vec2(-5, 6), vec2(-5, 7), vec2(-4, -7),vec2(-4, -6),vec2(-4, -5),vec2(-4, -4), - vec2(-4, -3),vec2(-4, -2),vec2(-4, -1),vec2(-4, 0), vec2(-4, 1), vec2(-4, 2), vec2(-4, 3), - vec2(-4, 4), vec2(-4, 5), vec2(-4, 6), vec2(-4, 7), vec2(-3, -7),vec2(-3, -6),vec2(-3, -5), - vec2(-3, -4),vec2(-3, -3),vec2(-3, -2),vec2(-3, -1),vec2(-3, 0), vec2(-3, 1), vec2(-3, 2), - vec2(-3, 3), vec2(-3, 4), vec2(-3, 5), vec2(-3, 6), vec2(-3, 7), vec2(-2, -7),vec2(-2, -6), - vec2(-2, -5),vec2(-2, -4),vec2(-2, -3),vec2(-2, -2),vec2(-2, -1),vec2(-2, 0), vec2(-2, 1), - vec2(-2, 2), vec2(-2, 3), vec2(-2, 4), vec2(-2, 5), vec2(-2, 6), vec2(-2, 7), vec2(-1, -7), - vec2(-1, -6),vec2(-1, -5),vec2(-1, -4),vec2(-1, -3),vec2(-1, -2),vec2(-1, 2), vec2(-1, 3), - vec2(-1, 4), vec2(-1, 5), vec2(-1, 6), vec2(-1, 7), vec2(0, -7), vec2(0, -6), vec2(0, -5), - vec2(0, -4), vec2(0, -3), vec2(0, -2), vec2(0, 2), vec2(0, 3), vec2(0, 4), vec2(0, 5), - vec2(0, 6), vec2(0, 7), vec2(1, -7), vec2(1, -6), vec2(1, -5), vec2(1, -4), vec2(1, -3), - vec2(1, -2), vec2(1, 2), vec2(1, 3), vec2(1, 4), vec2(1, 5), vec2(1, 6), vec2(1, 7), - vec2(2, -7), vec2(2, -6), vec2(2, -5), vec2(2, -4), vec2(2, -3), vec2(2, -2), vec2(2, -1), - vec2(2, 0), vec2(2, 1), vec2(2, 2), vec2(2, 3), vec2(2, 4), vec2(2, 5), vec2(2, 6), - vec2(2, 7), vec2(3, -7), vec2(3, -6), vec2(3, -5), vec2(3, -4), vec2(3, -3), vec2(3, -2), - vec2(3, -1), vec2(3, 0), vec2(3, 1), vec2(3, 2), vec2(3, 3), vec2(3, 4), vec2(3, 5), - vec2(3, 6), vec2(3, 7), vec2(4, -7), vec2(4, -6), vec2(4, -5), vec2(4, -4), vec2(4, -3), - vec2(4, -2), vec2(4, -1), vec2(4, 0), vec2(4, 1), vec2(4, 2), vec2(4, 3), vec2(4, 4), - vec2(4, 5), vec2(4, 6), vec2(4, 7), vec2(5, -7), vec2(5, -6), vec2(5, -5), vec2(5, -4), - vec2(5, -3), vec2(5, -2), vec2(5, -1), vec2(5, 0), vec2(5, 1), vec2(5, 2), vec2(5, 3), - vec2(5, 4), vec2(5, 5), vec2(5, 6), vec2(5, 7), vec2(6, -7), vec2(6, -6), vec2(6, -5), - vec2(6, -4), vec2(6, -3), vec2(6, -2), vec2(6, -1), vec2(6, 0), vec2(6, 1), vec2(6, 2), - vec2(6, 3), vec2(6, 4), vec2(6, 5), vec2(6, 6), vec2(6, 7), vec2(7, -7), vec2(7, -6), - vec2(7, -5), vec2(7, -4), vec2(7, -3), vec2(7, -2), vec2(7, -1), vec2(7, 0), vec2(7, 1), - vec2(7, 2), vec2(7, 3), vec2(7, 4), vec2(7, 5), vec2(7, 6), vec2(7, 7)); - -ivec2 wrap_idx(vec2 p, vec2 off) { - vec2 border = pc.resolution; - vec2 res = p + off; - - if (res.x < 0) { - res.x = border.x + res.x; - } else if (res.x > border.x) { - res.x = res.x - border.x; - } - if (res.y < 0) { - res.y = border.y + res.y; - } else if (res.y > border.y) { - res.y = res.y - border.y; - } - return ivec2(res); -} - -struct ImageData { - vec2 avg[216]; -} imageData; - -float conv(in float[9] kernel, in float[9] data, in float denom, in float offset) { - float res = 0.0; - for (int i = 0; i < 9; ++i) { - res += kernel[i] * data[i]; - } - return clamp(res / denom + offset, 0.0, 1.0); -} - -float hash(float n) { - return fract(sin(n) * 43758.5453); -} - -float hash2(vec2 n) { - return hash(dot(n, vec2(12.9898, 4.1414))); -} - -void main() { - if (gl_GlobalInvocationID.x >= pc.resolution.x || - gl_GlobalInvocationID.y >= pc.resolution.y) { - return; - } - - ivec2 pos = ivec2(gl_GlobalInvocationID.xy); - float cell = imageLoad(float_texture1, pos).r; - - float avg = 0; - for (int i = 0; i < PATTERN_SIZE; ++i) { - float x = imageLoad(float_texture1, wrap_idx(pos, PATTERN[i])).r; - avg += x; - } - avg /= PATTERN_SIZE; - - float col = 0.0; - if (pc.time < 1.0) { - col += sin(pos.x / 8. - PI * 0.5) + cos(pos.y / 16. + PI); - /* col = hash(pos.x * pos.y); */ - } else { - if (cell < 0.0 && avg > -0.2) - col = -cell + 0.025; - else if (cell > 0. && avg < 0.) - col = -cell - 0.025; - else if (cell > 0. && avg > 0.55) - col = -cell - 0.025; - else if (cell < avg) - col = cell + 0.01; - else if (avg < cell) - col = cell - 0.01; - } - col = clamp(col, -1, 1); - - imageStore(float_texture1, ivec2(gl_GlobalInvocationID.xy), vec4(col)); -} diff --git a/examples/cellular_automata/shaders/shader.frag b/examples/cellular_automata/shaders/shader.frag deleted file mode 100644 index 8a461de..0000000 --- a/examples/cellular_automata/shaders/shader.frag +++ /dev/null @@ -1,38 +0,0 @@ -#version 460 - -// In the beginning, colours never existed. There's nothing that was done before you... - -layout(location = 0) in vec2 in_uv; -layout(location = 0) out vec4 out_color; - -layout(set = 0, binding = 0) uniform texture2D prev_frame; -layout(set = 0, binding = 1) uniform texture2D generic_texture; -layout(set = 0, binding = 2) uniform texture2D dummy_texture; -layout(set = 0, binding = 3) uniform texture2D float_texture1; -layout(set = 0, binding = 4) uniform texture2D float_texture2; -layout(set = 1, binding = 0) uniform sampler tex_sampler; -#define T(tex, uv_coord) (texture(sampler2D(tex, tex_sampler), uv_coord)) -#define Tuv(tex) (T(tex, vec2(in_uv.x, -in_uv.y))) -#define T_off(tex, off) (T(tex, vec2(in_uv.x + off.x, -(in_uv.y + off.y)))) - -layout(std430, push_constant) uniform PushConstant { - vec3 pos; - float time; - vec2 resolution; - vec2 mouse; - float spectrum; - bool mouse_pressed; -} pc; - -void main() { - vec2 uv = (in_uv + -0.5) * 2.0 / vec2(pc.resolution.y / pc.resolution.x, 1); - - float tex = Tuv(float_texture1).r; - - float circ = distance(in_uv, vec2(0.5)); - circ = step(circ, 0.4); - - float col = min(tex, circ); - - out_color = vec4(vec3(col), 1.0); -} diff --git a/examples/cellular_automata/shaders/shader.vert b/examples/cellular_automata/shaders/shader.vert deleted file mode 100644 index 9d9e662..0000000 --- a/examples/cellular_automata/shaders/shader.vert +++ /dev/null @@ -1,19 +0,0 @@ -#version 460 - -layout(location = 0) out vec2 out_uv; - -layout(std430, push_constant) uniform PushConstant { - vec3 pos; - float time; - vec2 resolution; - vec2 mouse; - bool mouse_pressed; - uint frame; - float time_delta; - float record_period; -} pc; - -void main() { - out_uv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); - gl_Position = vec4(out_uv * 2.0f + -1.0f, 0.0, 1.0); -} diff --git a/examples/circle_pattern/circle-pattern.png b/examples/circle_pattern/circle-pattern.png deleted file mode 100644 index ec67722..0000000 Binary files a/examples/circle_pattern/circle-pattern.png and /dev/null differ diff --git a/examples/circle_pattern/shaders/prelude.glsl b/examples/circle_pattern/shaders/prelude.glsl deleted file mode 100644 index a219c3a..0000000 --- a/examples/circle_pattern/shaders/prelude.glsl +++ /dev/null @@ -1,99 +0,0 @@ -#define PI 3.14159265359 -#define TWOPI 6.28318530718 - -const vec3 EPS = vec3(0., 0.01, 0.001); -const float HIT_DIST = EPS.y; -const int MAX_STEPS = 100; -const float MISS_DIST = 10.0; - -const float WIDTH = 2.0; -const float HALF_WIDTH = 1.0; - -float worldSDF(vec3 rayPos); - -vec2 ray_march(vec3 rayPos, vec3 rayDir) { - float dist = 0.0; - - for (int i = 0; i < MAX_STEPS; i++) { - vec3 pos = rayPos + (dist * rayDir); - float posToScene = worldSDF(pos); - dist += posToScene; - if (abs(posToScene) < HIT_DIST) - return vec2(dist, i); - if (posToScene > MISS_DIST) - break; - } - - return vec2(-dist, MAX_STEPS); -} - -float crossSDF(vec3 rayPos) { - const vec3 corner = vec3(HALF_WIDTH); - vec3 ray = abs(rayPos); - vec3 cornerToRay = ray - corner; - float minComp = min(min(cornerToRay.x, cornerToRay.y), cornerToRay.z); - float maxComp = max(max(cornerToRay.x, cornerToRay.y), cornerToRay.z); - float midComp = - cornerToRay.x + cornerToRay.y + cornerToRay.z - minComp - maxComp; - vec2 closestOutsidePoint = max(vec2(minComp, midComp), 0.0); - vec2 closestInsidePoint = min(vec2(midComp, maxComp), 0.0); - return (midComp > 0.0) ? length(closestOutsidePoint) - : -length(closestInsidePoint); -} - -float cubeSDF(vec3 rayPos) { - const vec3 corner = vec3(HALF_WIDTH); - vec3 ray = abs(rayPos); - vec3 cornerToRay = ray - corner; - float cornerToRayMaxComponent = - max(max(cornerToRay.x, cornerToRay.y), cornerToRay.z); - float distToInsideRay = min(cornerToRayMaxComponent, 0.0); - vec3 closestToOusideRay = max(cornerToRay, 0.0); - return length(closestToOusideRay) + distToInsideRay; -} - -float squareSDF(vec2 rayPos) { - const vec2 corner = vec2(HALF_WIDTH); - vec2 ray = abs(rayPos.xy); - vec2 cornerToRay = ray - corner; - float cornerToRayMaxComponent = max(cornerToRay.x, cornerToRay.y); - float distToInsideRay = min(cornerToRayMaxComponent, 0.0); - vec2 closestToOusideRay = max(cornerToRay, 0.0); - return length(closestToOusideRay) + distToInsideRay; -} - -float sphereSDF(vec3 rayPosition, vec3 sphereCenterPosition, float radius) { - vec3 centerToRay = rayPosition - sphereCenterPosition; - float distToCenter = length(centerToRay); - return distToCenter - radius; -} - -float sphereSDF(vec3 rayPos, float radius) { - return length(rayPos) - radius; -} - -float sphereSDF(vec3 rayPos) { - return length(rayPos) - HALF_WIDTH; -} - -float yplaneSDF(vec3 rayPos) { - return abs(rayPos.y); -} - -mat2 rotate(float angle) { - float sine = sin(angle); - float cosine = cos(angle); - return mat2(cosine, -sine, sine, cosine); -} - -vec3 enlight(in vec3 at, vec3 normal, vec3 diffuse, vec3 l_color, vec3 l_pos) { - vec3 l_dir = l_pos - at; - return diffuse * l_color * max(0., dot(normal, normalize(l_dir))) / - dot(l_dir, l_dir); -} - -vec3 wnormal(in vec3 p) { - return normalize(vec3(worldSDF(p + EPS.yxx) - worldSDF(p - EPS.yxx), - worldSDF(p + EPS.xyx) - worldSDF(p - EPS.xyx), - worldSDF(p + EPS.xxy) - worldSDF(p - EPS.xxy))); -} diff --git a/examples/circle_pattern/shaders/shader.comp b/examples/circle_pattern/shaders/shader.comp deleted file mode 100644 index 75df188..0000000 --- a/examples/circle_pattern/shaders/shader.comp +++ /dev/null @@ -1,45 +0,0 @@ -#version 460 - -layout(std430, push_constant) uniform PushConstant { - vec3 pos; - float time; - vec2 resolution; - vec2 mouse; - float spectrum; - bool mouse_pressed; -} pc; - -layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in; - -layout (binding = 0, rgba8) uniform image2D previous_frame; -layout (binding = 1, rgba8) uniform image2D generic_texture; -layout (binding = 2, rgba8) uniform image2D dummy_texture; -layout (binding = 3, r32f) uniform image2D float_texture1; -layout (binding = 4, r32f) uniform image2D float_texture2; - -#define PI acos(-1.) -#define dt_off(speed, off) fract(pc.time * speed + off) -#define dt(speed) dt_off(speed, 0) - -float hash(float n) { - return fract(sin(n) * 43758.5453); -} - -float hash2(vec2 n) { - return hash(dot(n, vec2(12.9898, 4.1414))); -} - -void main() { - if (gl_GlobalInvocationID.x >= pc.resolution.x || - gl_GlobalInvocationID.y >= pc.resolution.y) { - return; - } - - vec2 pos = gl_GlobalInvocationID.xy; - float time = pc.time; - - float p = sin(pos.x * 50) + cos(pos.y / 5); - p *= sin(pos.y * 50) + cos(pos.x * 50 + PI * time); - - imageStore(float_texture1, ivec2(gl_GlobalInvocationID.xy), vec4(p)); -} diff --git a/examples/circle_pattern/shaders/shader.frag b/examples/circle_pattern/shaders/shader.frag deleted file mode 100644 index 953aaaf..0000000 --- a/examples/circle_pattern/shaders/shader.frag +++ /dev/null @@ -1,45 +0,0 @@ -#version 460 - -// In the beginning, colours never existed. There's nothing that was done before you... - -#include - -layout(location = 0) in vec2 uv; -layout(location = 0) out vec4 out_color; - -layout(set = 0, binding = 0) uniform sampler2D previous_frame; -layout(set = 0, binding = 1) uniform sampler2D generic_texture; -layout(set = 0, binding = 2) uniform sampler2D dummy_texture; -#define T(t) (texture(t, vec2(uv.x, -uv.y))) -#define T_off(t,off) (texture(t, vec2(uv.x + off.x, -(uv.y + off.y)))) - -layout(set = 0, binding = 3) uniform sampler2D float_texture1; -layout(set = 0, binding = 4) uniform sampler2D float_texture2; - -layout(std430, push_constant) uniform PushConstant { - vec3 pos; - float time; - vec2 resolution; - vec2 mouse; - float spectrum; - bool mouse_pressed; -} pc; - -float worldSDF(in vec3 pos) { - float res = -1.0; - res = sphereSDF(pos); - - return res; -} - -void main() { - float tex = texture(float_texture1, uv).r; - vec2 uu = (uv + -0.5) * 2.0 / vec2(pc.resolution.y / pc.resolution.x, 1); - - float circ = distance(uv, vec2(0.5)); - circ = step(circ, 0.4); - - float col = min(tex, circ); - - out_color = vec4(vec3(col), 1.0); -} diff --git a/examples/circle_pattern/shaders/shader.vert b/examples/circle_pattern/shaders/shader.vert deleted file mode 100644 index 4592c1f..0000000 --- a/examples/circle_pattern/shaders/shader.vert +++ /dev/null @@ -1,17 +0,0 @@ -#version 460 - -layout(location = 0) out vec2 out_uv; - -layout(std430, push_constant) uniform PushConstant { - vec3 pos; - float time; - vec2 resolution; - vec2 mouse; - float spectrum; - bool mouse_pressed; -} pc; - -void main() { - out_uv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); - gl_Position = vec4(out_uv * 2.0f + -1.0f, 0.0, 1.0); -} diff --git a/examples/cube/cube.gif b/examples/cube/cube.gif deleted file mode 100644 index 1e755f7..0000000 Binary files a/examples/cube/cube.gif and /dev/null differ diff --git a/examples/cube/shaders/prelude.glsl b/examples/cube/shaders/prelude.glsl deleted file mode 100644 index e69de29..0000000 diff --git a/examples/cube/shaders/shader.comp b/examples/cube/shaders/shader.comp deleted file mode 100644 index f150c4f..0000000 --- a/examples/cube/shaders/shader.comp +++ /dev/null @@ -1,27 +0,0 @@ -#version 460 - -layout(std430, push_constant) uniform PushConstant { - vec3 pos; - float time; - vec2 resolution; - vec2 mouse; - bool mouse_pressed; - uint frame; - float time_delta; - float record_period; -} pc; - -layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in; - -layout (binding = 0, rgba8) uniform image2D previous_frame; -layout (binding = 1, rgba8) uniform image2D generic_texture; -layout (binding = 2, rgba8) uniform image2D dummy_texture; -layout (binding = 3, r32f) uniform image2D float_texture1; -layout (binding = 4, r32f) uniform image2D float_texture2; - -void main() { - if (gl_GlobalInvocationID.x >= pc.resolution.x || - gl_GlobalInvocationID.y >= pc.resolution.y) { - return; - } -} diff --git a/examples/cube/shaders/shader.frag b/examples/cube/shaders/shader.frag deleted file mode 100644 index 5c0ade6..0000000 --- a/examples/cube/shaders/shader.frag +++ /dev/null @@ -1,91 +0,0 @@ -#version 460 - -// Heavily inspired by Flopine's streams... HBHS and cheers! -// https://www.shadertoy.com/user/Flopine - -layout(std430, push_constant) uniform PushConstant { - vec3 pos; - float time; - vec2 resolution; - vec2 mouse; - bool mouse_pressed; - uint frame; - float time_delta; - float record_period; -} pc; - -layout(location = 0) in vec2 uv; -layout(location = 0) out vec4 out_color; - -#define PI 3.14159265 -#define TAU 6.2831853071 -#define dt (mod(pc.time + PI * 0.5, TAU)) - -// reference for animation curves: https://easings.net/ -float easeInOutCirc(float x) { - return x < 0.5 ? (1. - sqrt(1. - pow(2. * x, 2.))) / 2. - : (sqrt(1. - pow(-2. * x + 2., 2.)) + 1.) / 2.; -} - -mat2 rot(float a) { - return mat2(cos(a), sin(a), -sin(a), cos(a)); -} - -#define animation(time) (-1. + 2. * easeInOutCirc(time)) -float square(vec2 uv) { - float width = 0.35; - uv.x += animation(sin(dt) * 0.5 + 0.5); - uv *= rot(animation(sin(dt) * 0.5 + 0.5) * PI); - uv = abs(uv); - return smoothstep(width, width * 1.05, max(uv.x, uv.y)); -} - -float sc(vec3 p, float s) { - p = abs(p); - p = max(p, p.yzx); - return min(p.x, min(p.y, p.z)) - s; -} - -float cube(vec3 p) { - p.x += animation(sin(dt) * 0.5 + 0.5) * 2.8; - if (sin(pc.time / 2 + 0 * PI) > 0) { - p.yz *= rot(-atan(1. / sqrt(2.))); - } else { - p.zy *= rot(-atan(1. / sqrt(2.))); - } - /* p.xz *= rot(PI / 4.); */ - p.xy *= rot(animation(sin(dt) * 0.5 + 0.5) * PI); - return max(-sc(p, 0.8), length(max(abs(p) - vec3(1.), 0.))); - /* return length(max(abs(p) - vec3(1.), 0.)); */ -} - -const vec3 PINK = vec3(212., 33., 93.) / 256; - -vec3 raymarch(vec2 uv) { - vec3 ro = vec3(uv * 3., 5.), rd = normalize(vec3(0., 0., -1.)), p = ro, - col = vec3(0., 0.05, 0.05); - col = PINK; - float shad; - bool hit = false; - - for (float i = 0.; i < 32.; i++) { - float d = cube(p); - if (d < 0.01) { - hit = true; - shad = i / 32.; - break; - } - p += d * rd; - } - if (hit) - col = vec3(1. - shad); - return col; -} - -void main() { - vec3 cuber = raymarch(uv); - vec3 col = (uv.y >= sin(dt + 2 * PI) * 2) ? cuber : PINK + square(uv); - - out_color = vec4(col * 1.2 / (2.1 - col * 0.5), 1.0); - out_color = vec4(pow(col, vec3(3 / 1.0)), 1.0); -} diff --git a/examples/cube/shaders/shader.vert b/examples/cube/shaders/shader.vert deleted file mode 100644 index 24936d1..0000000 --- a/examples/cube/shaders/shader.vert +++ /dev/null @@ -1,21 +0,0 @@ - -#version 460 - -layout(location = 0) out vec2 out_uv; - -layout(std430, push_constant) uniform PushConstant { - vec3 pos; - float time; - vec2 resolution; - vec2 mouse; - bool mouse_pressed; - uint frame; - float time_delta; - float record_period; -} pc; - -void main() { - out_uv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); - gl_Position = vec4(out_uv * 2.0f + -1.0f, 0.0, 1.0); - out_uv = (out_uv + -0.5) * 2.0 / vec2(pc.resolution.y / pc.resolution.x, 1); -} diff --git a/examples/dithering/dithering.png b/examples/dithering/dithering.png deleted file mode 100644 index ee3ce10..0000000 Binary files a/examples/dithering/dithering.png and /dev/null differ diff --git a/examples/dithering/shaders/prelude.glsl b/examples/dithering/shaders/prelude.glsl deleted file mode 100644 index e69de29..0000000 diff --git a/examples/dithering/shaders/shader.comp b/examples/dithering/shaders/shader.comp deleted file mode 100644 index 801d6d6..0000000 --- a/examples/dithering/shaders/shader.comp +++ /dev/null @@ -1,35 +0,0 @@ -#version 460 - -layout(std430, push_constant) uniform PushConstant { - vec3 pos; - float time; - vec2 resolution; - vec2 mouse; - bool mouse_pressed; - uint frame; - float time_delta; - float record_period; -} pc; - -layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in; - -layout (binding = 0, rgba8) uniform image2D previous_frame; -layout (binding = 1, rgba8) uniform image2D generic_texture; -layout (binding = 2, rgba8) uniform image2D dummy_texture; - -layout (binding = 3, rgba32f) uniform image2D float_texture1; -layout (binding = 4, rgba32f) uniform image2D float_texture2; - -void main() { - if (gl_GlobalInvocationID.x >= pc.resolution.x || - gl_GlobalInvocationID.y >= pc.resolution.y) { - return; - } - - vec2 pos = gl_GlobalInvocationID.xy; - float time = pc.time; - - float col = cos(pos.x / 1.3) * sin(pos.y / 1.1 + time); - - imageStore(float_texture1, ivec2(pos), vec4(col)); -} diff --git a/examples/dithering/shaders/shader.frag b/examples/dithering/shaders/shader.frag deleted file mode 100644 index 7979805..0000000 --- a/examples/dithering/shaders/shader.frag +++ /dev/null @@ -1,118 +0,0 @@ -#version 460 - -// In the beginning, colours never existed. There's nothing that was done before you... - -layout(location = 0) in vec2 in_uv; -layout(location = 0) out vec4 out_color; - -layout(set = 0, binding = 0) uniform texture2D prev_frame; -layout(set = 0, binding = 1) uniform texture2D generic_texture; -layout(set = 0, binding = 2) uniform texture2D dummy_texture; -layout(set = 0, binding = 3) uniform texture2D float_texture1; -layout(set = 0, binding = 4) uniform texture2D float_texture2; -layout(set = 1, binding = 0) uniform sampler tex_sampler; -#define T(tex, uv_coord) (texture(sampler2D(tex, tex_sampler), uv_coord)) -#define Tuv(tex) (T(tex, vec2(in_uv.x, -in_uv.y))) -#define T_off(tex, off) (T(tex, vec2(in_uv.x + off.x, -(in_uv.y + off.y)))) - -layout(std430, push_constant) uniform PushConstant { - vec3 pos; - float time; - vec2 resolution; - vec2 mouse; - bool mouse_pressed; - uint frame; - float time_delta; - float record_period; -} pc; - -#define MAX_DIST 0.1 -const vec3 EPS = vec3(0., 0.01, 0.001); -const float HIT_DIST = EPS.y; -const int MAX_STEPS = 100; -const float MISS_DIST = 10.0; - -mat2 rot(float a) { - float c = cos(a), s = sin(a); - return mat2(c, -s, s, c); -} - -float sc(vec3 p, float s) { - p = abs(p); - p = max(p, p.yzx); - return min(p.x, min(p.y, p.z)) - s; -} - -float sdTorus(vec3 p, vec2 t) { - vec2 q = vec2(length(p.xz) - t.x, p.y); - return length(q) - t.y; -} - -vec3 getRayDir(vec2 uv, vec3 p, vec3 l, float z) { - vec3 f = normalize(l - p), - r = normalize(cross(vec3(0, 1, 0), f)), - u = cross(f, r), - c = f*z, - i = c + uv.x * r + uv.y * u, - d = normalize(i); - return d; -} - -float scene(vec3 p, float t) { - p.xz *= rot(t * 5.); - p.xy *= rot(t * 7.); - float scale = 0.6 + .2 * sin(t * 10.); - p /= scale; - return max(-sc(p, 0.8), length(max(abs(p) - vec3(1.), 0.))) * scale; -} - -vec2 ray_march(vec3 rayPos, vec3 rayDir, float t) { - float dist = 0.0; - - for(int i = 0; i < MAX_STEPS; i++) { - vec3 pos = rayPos + (dist * rayDir); - float posToScene = scene(pos, t); - dist += posToScene; - if(abs(posToScene) < HIT_DIST) return vec2(dist, i); - if(posToScene > MISS_DIST) break; - } - - return vec2(0, MAX_STEPS); -} - -vec3 normal_vec(vec3 p, float t) { - mat3 k = mat3(p, p, p) - mat3(EPS.z); - return normalize(vec3(p - vec3(scene(k[0], t), scene(k[1], t), scene(k[2], t)))); -} - -void main() { - vec2 uv = (in_uv + -0.5) * 2.0 * vec2(pc.resolution.x / pc.resolution.y, 1); - - float t = pc.time / 5; - vec3 ro = vec3(0.0, 0.0, 4.0); - vec3 rd = normalize(vec3(uv, -2.)); - vec3 color = vec3(0); - - for (int i = 0; i < 3; i++) { - vec2 rm = ray_march(ro, rd, t); - float d = rm[0]; - vec3 light = vec3(10, 0.0, 0.0); - vec3 p = ro + rd * d; - if (d > MAX_DIST) { - vec3 n = normal_vec(p, t); - vec3 dir_to_light = normalize(light - p); - vec2 ray_march_light = ray_march(p - dir_to_light * .06, dir_to_light, t); - float dist_to_obstacle = ray_march_light.x; - float dist_to_light = length(light - p); - color[i] = .5 * dot(n, dir_to_light) + 0.5; - color[i] = step(T(float_texture1, (in_uv + 4. * float(i)) / 2.0).x, color[i]); - } else { - float tex = T(float_texture1, (in_uv + 8. * float(i)) / 32.).x * 0.03; - color = max(color, vec3(tex)); - } - t += .011; - } - - color += 0.01; - out_color = vec4(color, 1.0); -} diff --git a/examples/dithering/shaders/shader.vert b/examples/dithering/shaders/shader.vert deleted file mode 100644 index 9d9e662..0000000 --- a/examples/dithering/shaders/shader.vert +++ /dev/null @@ -1,19 +0,0 @@ -#version 460 - -layout(location = 0) out vec2 out_uv; - -layout(std430, push_constant) uniform PushConstant { - vec3 pos; - float time; - vec2 resolution; - vec2 mouse; - bool mouse_pressed; - uint frame; - float time_delta; - float record_period; -} pc; - -void main() { - out_uv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); - gl_Position = vec4(out_uv * 2.0f + -1.0f, 0.0, 1.0); -} diff --git a/examples/laser/laser.png b/examples/laser/laser.png deleted file mode 100644 index 960fde1..0000000 Binary files a/examples/laser/laser.png and /dev/null differ diff --git a/examples/laser/shaders/prelude.glsl b/examples/laser/shaders/prelude.glsl deleted file mode 100644 index c455aab..0000000 --- a/examples/laser/shaders/prelude.glsl +++ /dev/null @@ -1,257 +0,0 @@ -float time; - -/* #define COMPUTE_ROUTINE */ - -#define MAX_DISTANCE 10000. -#define TWO_PI 6.28318530718 -#define PI 3.14159265359 - -/* #define time pc.time */ -/* #define time 157.07131 */ - -#define MAX_LEVEL 5 -#define bayer2x2(a) (4-(a).x-((a).y<<1))%4 -float get_bayer_from_coord(vec2 pixelpos) { - ivec2 ppos = ivec2(pixelpos); - int sum = 0; - for (int i = 0; i < MAX_LEVEL; i++) { - sum += bayer2x2(ppos >> (MAX_LEVEL - 1 - i) & 1) << (2 * i); - } - - return float(sum) / float(2 << (MAX_LEVEL * 2 - 1)); -} - -uvec4 s0, s1; -ivec2 pixel; - -void rng_initialize(vec2 p, uint frame) { - pixel = ivec2(p); - - //white noise seed - s0 = uvec4(p, uint(frame), uint(p.x) + uint(p.y)); - - //blue noise seed - s1 = uvec4(frame, frame * 15843, frame * 31 + 4566, frame * 2345 + 58585); -} - -// https://www.pcg-random.org/ -uvec4 pcg4d(inout uvec4 v) { - v = v * 1664525u + 1013904223u; - v.x += v.y*v.w; v.y += v.z*v.x; v.z += v.x*v.y; v.w += v.y*v.z; - v = v ^ (v >> 16u); - v.x += v.y*v.w; v.y += v.z*v.x; v.z += v.x*v.y; v.w += v.y*v.z; - return v; -} -float rand() { return float(pcg4d(s0).x) / float(0xffffffffu); } -vec2 rand2() { return vec2(pcg4d(s0).xy) / float(0xffffffffu); } -vec3 rand3() { return vec3(pcg4d(s0).xyz) / float(0xffffffffu); } -vec4 rand4() { return vec4(pcg4d(s0)) / float(0xffffffffu); } - -vec3 nrand3(float sigma, vec3 mean) { - vec4 Z = rand4(); - return mean + - sigma * sqrt(-2.0 * log(Z.xxy)) * - vec3(cos(TWO_PI * Z.z), sin(TWO_PI * Z.z), cos(TWO_PI * Z.w)); -} - -mat2 rot(float a) { - float c = cos(a), s = sin(a); - return mat2(c, -s, s, c); -} - -float sd_sphere(vec3 p, float r) { - return length(p) - r; -} - -float sd_box(vec3 p, vec3 s) { - p = abs(p) - s; - return length(max(p, 0.0)) + min(max(p.x, max(p.y, p.z)), 0.0); -} - -float sd_caps(vec3 p, vec3 p1, vec3 p2, float s) { - vec3 pa = p - p1; - vec3 pb = p2 - p1; - float proj = dot(pa, pb) / dot(pb, pb); - proj = clamp(proj, 0., 1.); - return length(p1 + pb * proj - p) - s; -} - -float scene2(vec3 p) { - vec3 p2 = p; - float t = time * 0.1; - /* p2.yz *= rot(t); */ - /* p2.yx *= rot(t * 1.3); */ - float d = sd_box(p2, vec3(3.)); - /* d = max(d, -sd_sphere(p, 1.2)); */ - - float width = 3.; - d = max(d, -sd_caps(p2, vec3(0., -width, 0.), vec3(0., width, 0.), 1.)); - - return d; -} - -float op_cut_space(inout vec3 p, in vec3 n, in float w, in float sp) { - float dt = dot(p, n) + w; - float dcut = abs(dt) - sp; - p -= sp * n * sign(dt); - return dcut; -} - -vec3 erot(vec3 p, vec3 ax, float ro) { - return mix(dot(ax, p) * ax, p, cos(ro)) + cross(ax, p) * sin(ro); -} - -float scene(vec3 p) { - vec3 pos = p; - float t = time * 0.05; - pos.yz *= rot(t); - pos.yx *= rot(t * 1.3); - - float d = length(p) - 1.5; - - /* pos = erot(pos, vec3(1., 0., 0.), pos.x > 0 ? time : -time); */ - pos = erot(pos, vec3(1., 0., 0.), pos.x > 0 ? 0.5 : - 0.3); - d = sd_box(pos, vec3(2.6)); - - float cut = op_cut_space(pos, vec3(1., 0., 0.), 0.0, 0.05); - - d = max(d, -cut); - - float box = sd_box(p, vec3(4.3)); - d = max(d, box); - - return d; -} - -vec3 norm(vec3 p) { - mat3 k = mat3(p, p, p) - mat3(0.001); - return normalize(scene(p) - vec3(scene(k[0]), scene(k[1]), scene(k[2]))); -} - -float rnd(vec2 uv) { - return fract(dot(sin(uv * 4532.714 + uv.yx *543.524), vec2(352.887))); -} - - -const int NUM_LASERS = 2; -const int LASER_LENGTH = 10; -vec3 LASERS[NUM_LASERS][LASER_LENGTH]; -int NPATH[NUM_LASERS] = int[](1, 1); - -float ATT = 0.; - -float scene_with_lasers(vec3 p) { - float d = scene(p); - - float d2 = 10000.; - for (int i = 0; i < NUM_LASERS; ++i) { - for (int laser_segment = 0; laser_segment < NPATH[i] - 1; ++laser_segment) { - float d3 = sd_caps(p, LASERS[i][laser_segment], LASERS[i][laser_segment + 1], 0.01); - ATT += 0.013 / (0.05 + abs(d3)) * smoothstep(4., 0.3, d3); - - d2 = min(d2, d3); - } - } - return min(abs(d), d2); -} - -vec3 process_hit(inout float dist, vec3 r, vec3 p, inout float side, float ior) { - const float abberation = 0.3; - vec2 off = vec2(0.01, 0); - vec3 n = side * norm(p); - n = normalize(nrand3(0.005, n)); - vec3 rn; - if (side == 0.) { - rn = refract(r, n, side * (abberation + 0.1 * ior)); - } else { - rn = refract(r, n, 1 / side * (abberation + 0.1 * ior)); - } - rn = refract(r, n, 1 - side * (abberation + 0.1 * ior)); - /* rn = refract(r, n, 1 - side * (-2.0 + 0.1 * ior)); */ - /* rn = refract(r, n, pow(ior, -side)); */ - if (length(rn) > 0.5) { - side *= -1; - } else { - rn = reflect(r, n); - } - dist = 0.1; - return rn; -} - -void trace_lazer(vec3 ro, vec3 rd, float ior, int n) { - vec3 p = ro; - LASERS[n][0] = p; - NPATH[n] = 1; - float side = 1.; - for (int i = 0; i < 60; ++i) { - float d = abs(scene(p)); - if (d < 0.001) { - LASERS[n][NPATH[n]] = p; - NPATH[n] += 1; - if (NPATH[n] >= LASER_LENGTH - 1) - break; - - rd = process_hit(d, rd, p, side, ior); - } - if (d > 100.0) break; - p += rd * d; - } - LASERS[n][NPATH[n]] = p + rd * 1000.; - NPATH[n] += 1; -} - -void trace_lasers(vec3 ro, vec3 rd, float ior) { - trace_lazer(ro, rd, ior, 0); - - ro *= -1.; - rd.x *= -1.; - trace_lazer(ro, rd, ior, 1); -} - -vec3 render(vec2 frag_coords, vec2 resolution, uint frame) { - vec2 uv = (frag_coords / resolution + -0.5) * 2.0 / - vec2(resolution.y / resolution.x, 1); - uv += (rand() - 0.5) * 2.0 / resolution; - - rng_initialize(frag_coords, frame); - float bayer_jitter = get_bayer_from_coord(frag_coords); - - vec3 lazer_start = vec3(18., 0., 0.); - vec3 lazer_dir = normalize(vec3(-1., sin(3.4) * 0.07, 0)); - /* lazer_dir = normalize(vec3(-1., sin(time) * 0.07, 0)); */ - - float ior = rand() * 2.0 - 1.0; - ior = bayer_jitter * 2.0 - 1.0; - vec3 diff = 1.3 - vec3(1. + ior, 0.45 + abs(ior), 1. - ior); - - trace_lasers(lazer_start, lazer_dir, ior); - - vec3 s = vec3(0., 0., -10.); - vec3 r = normalize(vec3(uv, 1.)); - - float rg = rand(); - rg = mix(rg, bayer_jitter, 0.5); - float mumu = mix(rg, 1., 0.95); - vec3 p = s; - float side2 = 1.; - for (int i = 0; i < 90; ++i) { - float d = abs(scene_with_lasers(p)); - if (d < 0.001) { - r = process_hit(d, r, p, side2, ior); - } - if (d > 100.) break; - p += r * d * mumu; - /* p += nrand3(0.005, r) * d; */ - } - - vec3 lazer = diff * ATT; - vec3 n = norm(p); - vec3 color = vec3(0.); - vec3 light_dir = normalize(vec3(1.)); - float shade = dot(light_dir, n); - float amb = 0.2 * (mix(max(shade, 0.), shade * 0.5 + 0.5, .05)); - color = mix(vec3(amb), lazer * 1., vec3(0.9)); - /* color = lazer * 1.; */ - - return color; -} diff --git a/examples/laser/shaders/shader.comp b/examples/laser/shaders/shader.comp deleted file mode 100644 index ffbc89a..0000000 --- a/examples/laser/shaders/shader.comp +++ /dev/null @@ -1,42 +0,0 @@ -#version 460 - -#include - -layout(std430, push_constant) uniform PushConstant { - vec3 pos; - float time; - vec2 resolution; - vec2 mouse; - bool mouse_pressed; - uint frame; - float time_delta; - float record_period; -} pc; - -layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in; - -layout (binding = 0, rgba8) uniform image2D previous_frame; -layout (binding = 1, rgba8) uniform image2D generic_texture; -layout (binding = 2, rgba8) uniform image2D dummy_texture; - -layout (binding = 3, rgba32f) uniform image2D float_texture1; -layout (binding = 4, rgba32f) uniform image2D float_texture2; - -void main() { - if (gl_GlobalInvocationID.x >= pc.resolution.x || - gl_GlobalInvocationID.y >= pc.resolution.y) { - return; - } - -#ifdef COMPUTE_ROUTINE - time = pc.time; - - vec3 color = render(gl_GlobalInvocationID.xy, pc.resolution, pc.frame); - - vec3 last_frame_color = imageLoad(float_texture1, ivec2(gl_GlobalInvocationID.xy)).rgb; - color = mix(last_frame_color, color, 1. / float(pc.frame + 1)); - /* color = mix(last_frame_color, color, 0.5); */ - - imageStore(float_texture1, ivec2(gl_GlobalInvocationID.xy), vec4(color, 1.)); -#endif -} diff --git a/examples/laser/shaders/shader.frag b/examples/laser/shaders/shader.frag deleted file mode 100644 index aaa9dcb..0000000 --- a/examples/laser/shaders/shader.frag +++ /dev/null @@ -1,56 +0,0 @@ -#version 460 - -// In the beginning, colours never existed. There's nothing that was done before you... - -#include - -layout(location = 0) in vec2 in_uv; -layout(location = 0) out vec4 out_color; - -layout(set = 0, binding = 0) uniform sampler2D previous_frame; -layout(set = 0, binding = 1) uniform sampler2D generic_texture; -layout(set = 0, binding = 2) uniform sampler2D dummy_texture; -#define T(t) (texture(t, vec2(in_uv.x, -in_uv.y))) -#define T_off(t,off) (texture(t, vec2(in_uv.x + off.x, -(in_uv.y + off.y)))) - -layout(set = 0, binding = 3) uniform sampler2D float_texture1; -layout(set = 0, binding = 4) uniform sampler2D float_texture2; - -layout(std430, push_constant) uniform PushConstant { - vec3 pos; - float time; - vec2 resolution; - vec2 mouse; - bool mouse_pressed; - uint frame; - float time_delta; - float record_period; -} pc; - -vec3 vignette(vec3 color, vec2 q, float v) { - color *= 0.3 + 0.8 * pow(16.0 * q.x * q.y * (1.0 - q.x) * (1.0 - q.y), v); - return color; -} - -vec3 desaturate(in vec3 c, in float a) { - float l = dot(c, vec3(1. / 3.)); - return mix(c, vec3(l), a); -} - -void main() { - time = pc.time; - - vec3 color = vec3(0.); - -#ifdef COMPUTE_ROUTINE - { - color = texture(float_texture1, in_uv).rgb; - } -#else - color = render(in_uv * pc.resolution, pc.resolution, pc.frame); -#endif - - color = desaturate(color, -0.8); - color = vignette(color, in_uv, 1.2); - out_color = vec4(color, 1.0); -} diff --git a/examples/laser/shaders/shader.vert b/examples/laser/shaders/shader.vert deleted file mode 100644 index 9d9e662..0000000 --- a/examples/laser/shaders/shader.vert +++ /dev/null @@ -1,19 +0,0 @@ -#version 460 - -layout(location = 0) out vec2 out_uv; - -layout(std430, push_constant) uniform PushConstant { - vec3 pos; - float time; - vec2 resolution; - vec2 mouse; - bool mouse_pressed; - uint frame; - float time_delta; - float record_period; -} pc; - -void main() { - out_uv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); - gl_Position = vec4(out_uv * 2.0f + -1.0f, 0.0, 1.0); -} diff --git a/examples/line_segment/line-segment.png b/examples/line_segment/line-segment.png deleted file mode 100644 index 6d07531..0000000 Binary files a/examples/line_segment/line-segment.png and /dev/null differ diff --git a/examples/line_segment/shaders/prelude.glsl b/examples/line_segment/shaders/prelude.glsl deleted file mode 100644 index e69de29..0000000 diff --git a/examples/line_segment/shaders/shader.comp b/examples/line_segment/shaders/shader.comp deleted file mode 100644 index 0eb105b..0000000 --- a/examples/line_segment/shaders/shader.comp +++ /dev/null @@ -1,27 +0,0 @@ -#version 460 - -layout(std430, push_constant) uniform PushConstant { - vec3 pos; - float time; - vec2 resolution; - vec2 mouse; - bool mouse_pressed; - uint frame; - float time_delta; - float record_period; -} pc; - -layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in; - -layout (binding = 0, rgba8) uniform image2D previous_frame; -layout (binding = 1, rgba8) uniform image2D generic_texture; -layout (binding = 2, rgba8) uniform image2D dummy_texture; -layout (binding = 3, rgba32f) uniform image2D float_texture1; -layout (binding = 4, rgba32f) uniform image2D float_texture2; - -void main() { - if (gl_GlobalInvocationID.x >= pc.resolution.x || - gl_GlobalInvocationID.y >= pc.resolution.y) { - return; - } -} diff --git a/examples/line_segment/shaders/shader.frag b/examples/line_segment/shaders/shader.frag deleted file mode 100644 index 283ac4d..0000000 --- a/examples/line_segment/shaders/shader.frag +++ /dev/null @@ -1,54 +0,0 @@ -#version 460 - -// Signed distance and line segment by Inigo Quilez -// Segment: https://www.shadertoy.com/view/3tdSDj -// and many more here: http://www.iquilezles.org/www/articles/distfunctions2d/distfunctions2d.htm - -layout(location = 0) in vec2 uv; -layout(location = 0) out vec4 out_color; - -layout(set = 0, binding = 0) uniform texture2D prev_frame; -layout(set = 0, binding = 1) uniform texture2D generic_texture; -layout(set = 0, binding = 2) uniform texture2D dummy_texture; -layout(set = 0, binding = 3) uniform texture2D float_texture1; -layout(set = 0, binding = 4) uniform texture2D float_texture2; -layout(set = 1, binding = 0) uniform sampler tex_sampler; -#define T(tex, uv_coord) (texture(sampler2D(tex, tex_sampler), uv_coord)) -#define Tuv(tex) (T(tex, vec2(in_uv.x, -in_uv.y))) -#define T_off(tex, off) (T(tex, vec2(in_uv.x + off.x, -(in_uv.y + off.y)))) - - -layout(std430, push_constant) uniform PushConstant { - vec3 pos; - float time; - vec2 resolution; - vec2 mouse; - bool mouse_pressed; - uint frame; - float time_delta; - float record_period; -} pc; - -float line_segment(in vec2 p, in vec2 a, in vec2 b) { - vec2 ba = b - a; - vec2 pa = p - a; - float h = clamp(dot(pa, ba) / dot(ba, ba), 0., 1.); - return length(pa - h * ba); -} - -void main() { - vec2 pos = (uv + -0.5) * 2.0 / vec2(pc.resolution.y / pc.resolution.x, 1); - - vec2 v1 = vec2(-2.0, -1.0); - vec2 v2 = cos(pc.time + vec2(-8., 3.) + 1.1) - 1.; - float thickness = .2 * (.5 + .5 * sin(pc.time * 1.)); - - float d = line_segment(pos, v1, v2) - thickness; - - vec3 color = vec3(1.) - sign(d) * vec3(0., 0., 0.); - color *= 1.5 - exp(.5 * abs(d)); - color *= .5 + .3 * cos(120. * d); - color = mix(color, vec3(1.), 1. - smoothstep(.0, .015, abs(d))); - - out_color = vec4(color, 1.); -} diff --git a/examples/line_segment/shaders/shader.vert b/examples/line_segment/shaders/shader.vert deleted file mode 100644 index fce64f4..0000000 --- a/examples/line_segment/shaders/shader.vert +++ /dev/null @@ -1,20 +0,0 @@ -#version 460 - -layout(location = 0) out vec2 out_uv; - -layout(std430, push_constant) uniform PushConstant { - vec3 pos; - float time; - vec2 resolution; - vec2 mouse; - bool mouse_pressed; - uint frame; - float time_delta; - float record_period; -} pc; - -void main() { - out_uv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); - gl_Position = vec4(out_uv * 2.0f + -1.0f, 0.0, 1.0); - out_uv = (out_uv + -0.5) * 2.0 / vec2(pc.resolution.y / pc.resolution.x, 1); -} diff --git a/examples/menger_sponge/shaders/prelude.glsl b/examples/menger_sponge/shaders/prelude.glsl deleted file mode 100644 index d3a59f7..0000000 --- a/examples/menger_sponge/shaders/prelude.glsl +++ /dev/null @@ -1,118 +0,0 @@ -#define PI 3.14159265359 -#define TWOPI 6.28318530718 - -const vec3 EPS = vec3(0., 0.01, 0.001); -const float HIT_DIST = EPS.z; -const int MAX_STEPS = 90; -const float MISS_DIST = 500.0; - -const float WIDTH = 2.0; -const float HALF_WIDTH = 1.0; - -float worldSDF(vec3 rayPos); - -vec2 ray_march(vec3 rayPos, vec3 rayDir) { - float dist = 0.0; - - for(int i = 0; i < MAX_STEPS; i++) { - vec3 pos = rayPos + (dist * rayDir); - float posToScene = worldSDF(pos); - dist += posToScene; - if(abs(posToScene) < HIT_DIST) return vec2(dist, i); - if(posToScene > MISS_DIST) break; - } - - return vec2(-dist, MAX_STEPS); -} - - -float crossSDF(vec3 rayPos) { - const vec3 corner = vec3(HALF_WIDTH); - vec3 ray = abs(rayPos); - vec3 cornerToRay = ray - corner; - float minComp = min(min(cornerToRay.x, cornerToRay.y), cornerToRay.z); - float maxComp = max(max(cornerToRay.x, cornerToRay.y), cornerToRay.z); - float midComp = cornerToRay.x + cornerToRay.y + cornerToRay.z - - minComp - maxComp; - vec2 closestOutsidePoint = max(vec2(minComp, midComp), 0.0); - vec2 closestInsidePoint = min(vec2(midComp, maxComp), 0.0); - return (midComp > 0.0) ? length(closestOutsidePoint) : -length(closestInsidePoint); -} - -float cubeSDF(vec3 rayPos) { - const vec3 corner = vec3(HALF_WIDTH); - vec3 ray = abs(rayPos); - vec3 cornerToRay = ray - corner; - float cornerToRayMaxComponent = max(max(cornerToRay.x, cornerToRay.y), cornerToRay.z); - float distToInsideRay = min(cornerToRayMaxComponent, 0.0); - vec3 closestToOusideRay = max(cornerToRay, 0.0); - return length(closestToOusideRay) + distToInsideRay; -} - -float mengerSpongeSDF(vec3 rayPos, int numIterations) { - float spongeCube = cubeSDF(rayPos); - if (spongeCube > HIT_DIST) return spongeCube; - float mengerSpongeDist = spongeCube; - - float scale = 1.0; - for(int i = 0; i < numIterations; ++i) { - float boxedWidth = WIDTH / scale; - float translation = boxedWidth / 2.0; - vec3 ray = rayPos + translation; - ray = mod(ray, boxedWidth); - ray -= boxedWidth / 2.0; - ray *= scale; - float crossesDist = crossSDF(ray * 3.0); - scale *= 3.0; - crossesDist /= scale; - mengerSpongeDist = max(mengerSpongeDist, -crossesDist); - } - - return mengerSpongeDist; -} - -float squareSDF(vec2 rayPos) { - const vec2 corner = vec2(HALF_WIDTH); - vec2 ray = abs(rayPos.xy); - vec2 cornerToRay = ray - corner; - float cornerToRayMaxComponent = max(cornerToRay.x, cornerToRay.y); - float distToInsideRay = min(cornerToRayMaxComponent, 0.0); - vec2 closestToOusideRay = max(cornerToRay, 0.0); - return length(closestToOusideRay) + distToInsideRay; -} - -float sphereSDF(vec3 rayPosition, vec3 sphereCenterPosition, float radius) { - vec3 centerToRay = rayPosition - sphereCenterPosition; - float distToCenter = length(centerToRay); - return distToCenter - radius; -} - -float sphereSDF(vec3 rayPos, float radius) { - return length(rayPos) - radius; -} - -float sphereSDF(vec3 rayPos) { - return length(rayPos) - HALF_WIDTH; -} - -float yplaneSDF(vec3 rayPos) { - return abs(rayPos.y); -} - -mat2 rotate(float angle) { - float sine = sin(angle); - float cosine = cos(angle); - return mat2(cosine, -sine, sine, cosine); -} - -vec3 enlight(in vec3 at, vec3 normal, vec3 diffuse, vec3 l_color, vec3 l_pos) { - vec3 l_dir = l_pos - at; - return diffuse * l_color * max(0., dot(normal, normalize(l_dir))) / - dot(l_dir, l_dir); -} - -vec3 wnormal(in vec3 p) { - return normalize(vec3(worldSDF(p + EPS.yxx) - worldSDF(p - EPS.yxx), - worldSDF(p + EPS.xyx) - worldSDF(p - EPS.xyx), - worldSDF(p + EPS.xxy) - worldSDF(p - EPS.xxy))); -} diff --git a/examples/menger_sponge/shaders/shader.comp b/examples/menger_sponge/shaders/shader.comp deleted file mode 100644 index 0eb105b..0000000 --- a/examples/menger_sponge/shaders/shader.comp +++ /dev/null @@ -1,27 +0,0 @@ -#version 460 - -layout(std430, push_constant) uniform PushConstant { - vec3 pos; - float time; - vec2 resolution; - vec2 mouse; - bool mouse_pressed; - uint frame; - float time_delta; - float record_period; -} pc; - -layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in; - -layout (binding = 0, rgba8) uniform image2D previous_frame; -layout (binding = 1, rgba8) uniform image2D generic_texture; -layout (binding = 2, rgba8) uniform image2D dummy_texture; -layout (binding = 3, rgba32f) uniform image2D float_texture1; -layout (binding = 4, rgba32f) uniform image2D float_texture2; - -void main() { - if (gl_GlobalInvocationID.x >= pc.resolution.x || - gl_GlobalInvocationID.y >= pc.resolution.y) { - return; - } -} diff --git a/examples/menger_sponge/shaders/shader.frag b/examples/menger_sponge/shaders/shader.frag deleted file mode 100644 index 6bf1ec4..0000000 --- a/examples/menger_sponge/shaders/shader.frag +++ /dev/null @@ -1,75 +0,0 @@ -#version 460 - -// In the beginning, colours never existed. There's nothing that was done before you... - -#include - -layout(location = 0) in vec2 uv; -layout(location = 0) out vec4 out_color; - -layout(set = 0, binding = 0) uniform texture2D prev_frame; -layout(set = 0, binding = 1) uniform texture2D generic_texture; -layout(set = 0, binding = 2) uniform texture2D dummy_texture; -layout(set = 0, binding = 3) uniform texture2D float_texture1; -layout(set = 0, binding = 4) uniform texture2D float_texture2; -layout(set = 1, binding = 0) uniform sampler tex_sampler; -#define T(tex, uv_coord) (texture(sampler2D(tex, tex_sampler), uv_coord)) -#define Tuv(tex) (T(tex, vec2(in_uv.x, -in_uv.y))) -#define T_off(tex, off) (T(tex, vec2(in_uv.x + off.x, -(in_uv.y + off.y)))) - -layout(std430, push_constant) uniform PushConstant { - vec3 pos; - float time; - vec2 resolution; - vec2 mouse; - bool mouse_pressed; - uint frame; - float time_delta; - float record_period; -} pc; - -const vec3 missColor = vec3(0.0002); -const float SPHERE_SCALE = 3.0; - -float worldSDF(in vec3 pos) { - float scale = SPHERE_SCALE; - float menger_sponge = mengerSpongeSDF(pos / scale, 9) * scale; - - float dist = menger_sponge; - - return dist; -} - -void main() { - vec2 m = (pc.mouse - 0.5) * 2.0 * PI; - m = pc.mouse; - m.y *= -1; - - m = vec2(0.43, 0.63); - m = (m - 0.5) * 2.0 * PI; - m.y *= -1; - - vec3 ray_pos = vec3(3.5, 4.5, 9.0); - ray_pos.z += m.y * 10; - ray_pos.y += m.x * 10; - - vec3 ray_dir = vec3(uv, -1.0); - - ray_dir.xz *= rotate(radians(-25.0)); - ray_dir.yz *= rotate(radians(-25.0)); - ray_dir.yx *= rotate(radians(-6.0)); - - ray_dir = normalize(ray_dir); - - vec2 dist = ray_march(ray_pos, ray_dir); - - if (dist.x > 0.0) { - vec3 col = vec3(1.0 - (dist.y / float(MAX_STEPS))); - // col = mix(1. - col, col, smoothstep(0.5, 2.0, 0.4 + sprm*4)); - out_color = vec4(col, 1.0); - } else { - out_color = vec4(missColor, 1.0); - } - - out_color = vec4(vec3(pow(out_color.rgb, vec3(1 / 0.36))), 1.0); -} diff --git a/examples/menger_sponge/shaders/shader.vert b/examples/menger_sponge/shaders/shader.vert deleted file mode 100644 index fce64f4..0000000 --- a/examples/menger_sponge/shaders/shader.vert +++ /dev/null @@ -1,20 +0,0 @@ -#version 460 - -layout(location = 0) out vec2 out_uv; - -layout(std430, push_constant) uniform PushConstant { - vec3 pos; - float time; - vec2 resolution; - vec2 mouse; - bool mouse_pressed; - uint frame; - float time_delta; - float record_period; -} pc; - -void main() { - out_uv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); - gl_Position = vec4(out_uv * 2.0f + -1.0f, 0.0, 1.0); - out_uv = (out_uv + -0.5) * 2.0 / vec2(pc.resolution.y / pc.resolution.x, 1); -} diff --git a/examples/menger_sponge/sponge.jpg b/examples/menger_sponge/sponge.jpg deleted file mode 100644 index eb0f003..0000000 Binary files a/examples/menger_sponge/sponge.jpg and /dev/null differ diff --git a/examples/path_tracer/path_tracer.png b/examples/path_tracer/path_tracer.png deleted file mode 100644 index b958125..0000000 Binary files a/examples/path_tracer/path_tracer.png and /dev/null differ diff --git a/examples/path_tracer/shaders/prelude.glsl b/examples/path_tracer/shaders/prelude.glsl deleted file mode 100644 index 76c7aef..0000000 --- a/examples/path_tracer/shaders/prelude.glsl +++ /dev/null @@ -1,53 +0,0 @@ -const float EXPOSURE = 0.5; - -vec3 less_than(vec3 f, float value) { - return vec3((f.x < value) ? 1.0f : 0.0f, (f.y < value) ? 1.0f : 0.0f, - (f.z < value) ? 1.0f : 0.0f); -} - -vec3 linear_to_srgb(vec3 rgb) { - rgb = clamp(rgb, 0.0f, 1.0f); - - return mix(pow(rgb, vec3(1.0f / 2.4f)) * 1.055f - 0.055f, rgb * 12.92f, - less_than(rgb, 0.0031308f)); -} - -vec3 srgb_to_linear(vec3 rgb) { - rgb = clamp(rgb, 0.0f, 1.0f); - - return mix(pow(((rgb + 0.055f) / 1.055f), vec3(2.4f)), rgb / 12.92f, - less_than(rgb, 0.04045f)); -} - -// ACES tone mapping curve fit to go from HDR to LDR -//https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/ -vec3 ACESFilm(vec3 x) { - float a = 2.51f; - float b = 0.03f; - float c = 2.43f; - float d = 0.59f; - float e = 0.14f; - return clamp((x * (a * x + b)) / (x * (c * x + d) + e), 0.0f, 1.0f); -} - -float fresnel_refelect_amount(float n1, - float n2, - vec3 normal, - vec3 incident, - float f0, - float f90) { - float r0 = (n1 - n2) / (n1 + n2); - r0 *= r0; - float cosx = -dot(normal, incident); - if (n1 > n2) { - float n = n1 / n2; - float sin_t2 = n * n * (1.0 - cosx * cosx); - if (sin_t2 > 1.0) { - return f90; - } - cosx = sqrt(1.0 - sin_t2); - } - float x = 1.0 - cosx; - float ret = r0 + (1.0 - r0) * x * x * x * x * x; - return mix(f0, f90, ret); -} diff --git a/examples/path_tracer/shaders/shader.comp b/examples/path_tracer/shaders/shader.comp deleted file mode 100644 index 7ccb78d..0000000 --- a/examples/path_tracer/shaders/shader.comp +++ /dev/null @@ -1,645 +0,0 @@ -#version 460 - -#include - -layout(std430, push_constant) uniform PushConstant { - vec3 pos; - float time; - vec2 resolution; - vec2 mouse; - bool mouse_pressed; - uint frame; - float time_delta; - float record_period; -} pc; - -layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in; - -layout (binding = 0, rgba8) uniform image2D previous_frame; -layout (binding = 1, rgba8) uniform image2D generic_texture; -layout (binding = 2, rgba8) uniform image2D dummy_texture; - -layout (binding = 3, rgba32f) uniform image2D float_texture1; -layout (binding = 4, rgba32f) uniform image2D float_texture2; - -const float SKYBOX_BRIGHTNESS_MULTIPLIER = 0.25; -const float MINIMUM_RAY_HIT_TIME = 0.1; -const float SUPER_FAR = 10000.; -const float FOV_DEGREES = 90.; -const float PI = 3.14159265359; -const float TWO_PI = 2.0 * PI; -const int NUM_BOUNCES = 8; -const float RAY_NORMAL_NUDGE = 0.01; -const int NUM_RENDERS_PER_FRAME = 2; - -const float MIN_CAMERA_ANGLE = 0.01; -const float MAX_CAMERA_ANGLE = PI - 0.01; -const vec3 CAMERA_AT = vec3(0.0, 0.0, 0.); -const float CAMERA_DISTANCE = 20.0; - -#define SCENE 0 - -uvec4 s0, s1; -ivec2 pixel; - -void rng_initialize(vec2 p, uint frame) { - pixel = ivec2(p); - - //white noise seed - s0 = uvec4(p, uint(frame), uint(p.x) + uint(p.y)); - - //blue noise seed - s1 = uvec4(frame, frame * 15843, frame * 31 + 4566, frame * 2345 + 58585); -} - -// https://www.pcg-random.org/ -uvec4 pcg4d(inout uvec4 v) { - v = v * 1664525u + 1013904223u; - v.x += v.y*v.w; v.y += v.z*v.x; v.z += v.x*v.y; v.w += v.y*v.z; - v = v ^ (v >> 16u); - v.x += v.y*v.w; v.y += v.z*v.x; v.z += v.x*v.y; v.w += v.y*v.z; - return v; -} -float rand() { return float(pcg4d(s0).x) / float(0xffffffffu); } -vec2 rand2() { return vec2(pcg4d(s0).xy) / float(0xffffffffu); } -vec3 rand3() { return vec3(pcg4d(s0).xyz) / float(0xffffffffu); } -vec4 rand4() { return vec4(pcg4d(s0)) / float(0xffffffffu); } - -vec2 nrand2(float sigma, vec2 mean) { - vec2 Z = rand2(); - return mean + sigma * sqrt(-2.0 * log(Z.x)) * - vec2(cos(TWO_PI * Z.y), sin(TWO_PI * Z.y)); -} - -vec3 nrand3(float sigma, vec3 mean) { - vec4 Z = rand4(); - return mean + - sigma * sqrt(-2.0 * log(Z.xxy)) * - vec3(cos(TWO_PI * Z.z), sin(TWO_PI * Z.z), cos(TWO_PI * Z.w)); -} - -float random_float01(inout uint state) { - return rand(); -} - -vec3 random_unit_vector(inout uint state) { - float z = random_float01(state) * 2.0f - 1.0f; - float a = random_float01(state) * TWO_PI; - float r = sqrt(1.0f - z * z); - float x = r * cos(a); - float y = r * sin(a); - return vec3(x, y, z); -} - -vec3 udir(vec2 rng) { - vec2 r = vec2(2. * PI * rng.x, acos(2. * rng.y - 1.)); - vec2 c = cos(r), s = sin(r); - return vec3(c.x * s.y, s.x * s.y, c.y); -} - -struct Material { - vec3 albedo; - vec3 emissive; - vec3 specular_color; - float specular_chance; - float specular_roughness; - float ior; - vec3 refraction_color; - float refraction_chance; - float refraction_roughness; -}; - -Material get_zeroed_material() { - Material ret; - ret.albedo = vec3(0.0f, 0.0f, 0.0f); - ret.emissive = vec3(0.0f, 0.0f, 0.0f); - ret.specular_chance = 0.0f; - ret.specular_roughness = 0.0f; - ret.specular_color = vec3(0.0f, 0.0f, 0.0f); - ret.ior = 1.0f; - ret.refraction_chance = 0.0f; - ret.refraction_roughness = 0.0f; - ret.refraction_color = vec3(0.0f, 0.0f, 0.0f); - return ret; -} - -struct RayHitInfo { - bool from_inside; - float dist; - vec3 normal; - Material material; -}; - -float scalar_triple(vec3 u, vec3 v, vec3 w) { - return dot(cross(u, v), w); -} - -bool test_quad_trace(in vec3 ray_pos, in vec3 ray_dir, - inout RayHitInfo info, - in vec3 a, in vec3 b, in vec3 c, in vec3 d) { - vec3 normal = normalize(cross(c - a, c - b)); - if (dot(normal, ray_dir) > 0.0) { - normal *= -1.; - - vec3 temp = d; - d = a; - a = temp; - - temp = b; - b = c; - c = temp; - } - - vec3 p = ray_pos; - vec3 q = ray_pos + ray_dir; - vec3 pq = q - p; - vec3 pa = a - p; - vec3 pb = b - p; - vec3 pc = c - p; - - vec3 m = cross(pc, pq); - float v = dot(pa, m); - vec3 intersect_pos = vec3(0.); - if (v >= 0.0) { - float u = -dot(pb, m); - if (u < 0.0) - return false; - float w = scalar_triple(pq, pb, pa); - if (w < 0.0) - return false; - float denom = 1.0 / (u + v + w); - u *= denom; v *= denom; w *= denom; - intersect_pos = u * a + v * b + w * c; - } else { - vec3 pd = d - p; - float u = dot(pd, m); - if (u < 0.0) - return false; - float w = scalar_triple(pq, pa, pd); - if (w < 0.0) - return false; - v = -v; - float denom = 1.0 / (u + v + w); - u *= denom; v *= denom; w *= denom; - intersect_pos = u * a + v * d + w * c; - } - - float dist = 0.0; - if (abs(ray_dir.x) > 0.1) { - dist = (intersect_pos.x - ray_pos.x) / ray_dir.x; - } else if (abs(ray_dir.y) > 0.1) { - dist = (intersect_pos.y - ray_pos.y) / ray_dir.y; - } else { - dist = (intersect_pos.z - ray_pos.z) / ray_dir.z; - } - - if (dist > MINIMUM_RAY_HIT_TIME && dist < info.dist) { - info.from_inside = false; - info.dist = dist; - info.normal = normal; - return true; - } - return false; -} - -bool test_sphere_trace(in vec3 ray_pos, in vec3 ray_dir, inout RayHitInfo info, in vec4 sphere) { - vec3 m = ray_pos - sphere.xyz; - float b = dot(m, ray_dir); - float c = dot(m, m) - sphere.w * sphere.w; - - if (c > 0. && b > 0.0) { - return false; - } - - float discr = b * b - c; - if (discr < 0.0) { - return false; - } - - bool from_inside = false; - float dist = -b - sqrt(discr); - if (dist < 0.0) { - from_inside = true; - dist = -b + sqrt(discr); - } - - if (dist > MINIMUM_RAY_HIT_TIME && dist < info.dist) { - info.from_inside = from_inside; - info.dist = dist; - info.normal = - normalize((ray_pos + ray_dir * dist) - sphere.xyz) * (from_inside ? -1.0 : 1.0); - return true; - } - return false; -} - -void test_scene_trace(in vec3 ray_pos, in vec3 ray_dir, inout RayHitInfo hit_info) { - // floor - { - vec3 A = vec3(-25.0f, -12.5f, 5.0f); - vec3 B = vec3(25.0f, -12.5f, 5.0f); - vec3 C = vec3(25.0f, -12.5f, -5.0f); - vec3 D = vec3(-25.0f, -12.5f, -5.0f); - if (test_quad_trace(ray_pos, ray_dir, hit_info, A, B, C, D)) { - hit_info.material = get_zeroed_material(); - hit_info.material.albedo = vec3(0.7f, 0.7f, 0.7f); - } - } - - // striped background - { - vec3 A = vec3(-25.0f, -1.5f, 5.0f); - vec3 B = vec3(25.0f, -1.5f, 5.0f); - vec3 C = vec3(25.0f, -10.5f, 5.0f); - vec3 D = vec3(-25.0f, -10.5f, 5.0f); - if (test_quad_trace(ray_pos, ray_dir, hit_info, A, B, C, D)) { - hit_info.material = get_zeroed_material(); - - vec3 hitPos = ray_pos + ray_dir * hit_info.dist; - - float shade = floor(mod(hitPos.x, 1.0f) * 2.0f); - hit_info.material.albedo = vec3(shade, shade, shade); - } - } - - // cieling piece above light - { - vec3 A = vec3(-7.5f, 12.5f, 5.0f); - vec3 B = vec3(7.5f, 12.5f, 5.0f); - vec3 C = vec3(7.5f, 12.5f, -5.0f); - vec3 D = vec3(-7.5f, 12.5f, -5.0f); - if (test_quad_trace(ray_pos, ray_dir, hit_info, A, B, C, D)) { - hit_info.material = get_zeroed_material(); - hit_info.material.albedo = vec3(0.7f, 0.7f, 0.7f); - } - } - - // light - { - vec3 A = vec3(-5.0f, 12.4f, 2.5f); - vec3 B = vec3(5.0f, 12.4f, 2.5f); - vec3 C = vec3(5.0f, 12.4f, -2.5f); - vec3 D = vec3(-5.0f, 12.4f, -2.5f); - if (test_quad_trace(ray_pos, ray_dir, hit_info, A, B, C, D)) { - hit_info.material = get_zeroed_material(); - hit_info.material.emissive = vec3(1.0f, 0.9f, 0.7f) * 20.0f; - } - } - -#if SCENE == 0 - - const int NUM_SPHERES = 7; - for (int sphere_index = 0; sphere_index < NUM_SPHERES; ++sphere_index) { - if (test_sphere_trace(ray_pos, ray_dir, hit_info, - vec4(-18.0f + 6.0f * float(sphere_index), -8.0f, 00.0f, 2.8f))) { - float r = float(sphere_index) / float(NUM_SPHERES - 1) * 0.5f; - - hit_info.material = get_zeroed_material(); - hit_info.material.albedo = vec3(0.9f, 0.25f, 0.25f); - hit_info.material.emissive = vec3(0.0f, 0.0f, 0.0f); - hit_info.material.specular_chance = 0.02f; - hit_info.material.specular_roughness = r; - hit_info.material.specular_color = vec3(1.0f, 1.0f, 1.0f) * 0.8f; - hit_info.material.ior = 1.1f; - hit_info.material.refraction_chance = 1.0f; - hit_info.material.refraction_roughness = r; - hit_info.material.refraction_color = vec3(0.0f, 0.5f, 1.0f); - } - } - -#elif SCENE == 1 - - const int NUM_SPHERES = 7; - for (int sphere_index = 0; sphere_index < NUM_SPHERES; ++sphere_index) { - if (test_sphere_trace(ray_pos, ray_dir, hit_info, - vec4(-18.0f + 6.0f * float(sphere_index), -8.0f, 0.0f, 2.8f))) { - float ior = 1.0f + 0.5f * float(sphere_index) / float(NUM_SPHERES - 1); - - hit_info.material = get_zeroed_material(); - hit_info.material.albedo = vec3(0.9f, 0.25f, 0.25f); - hit_info.material.emissive = vec3(0.0f, 0.0f, 0.0f); - hit_info.material.specular_chance = 0.02f; - hit_info.material.specular_roughness = 0.0f; - hit_info.material.specular_color = vec3(1.0f, 1.0f, 1.0f) * 0.8f; - hit_info.material.ior = ior; - hit_info.material.refraction_chance = 1.0f; - hit_info.material.refraction_roughness = 0.0f; - } - } - -#elif SCENE == 2 - - const int NUM_SPHERES = 7; - for (int sphere_index = 0; sphere_index < NUM_SPHERES; ++sphere_index) { - if (test_sphere_trace(ray_pos, ray_dir, hit_info, - vec4(-18.0f + 6.0f * float(sphere_index), -8.0f, 0.0f, 2.8f))) { - float ior = 1.0f + 1.0f * float(sphere_index) / float(NUM_SPHERES - 1); - - hit_info.material = get_zeroed_material(); - hit_info.material.albedo = vec3(0.9f, 0.25f, 0.25f); - hit_info.material.emissive = vec3(0.0f, 0.0f, 0.0f); - hit_info.material.specular_chance = 0.02f; - hit_info.material.specular_roughness = 0.0f; - hit_info.material.specular_color = vec3(1.0f, 1.0f, 1.0f) * 0.8f; - hit_info.material.ior = ior; - hit_info.material.refraction_chance = 0.0f; - } - } - -#elif SCENE == 3 - - const int NUM_SPHERES = 7; - for (int sphere_index = 0; sphere_index < NUM_SPHERES; ++sphere_index) { - if (test_sphere_trace(ray_pos, ray_dir, hit_info, - vec4(-18.0f + 6.0f * float(sphere_index), -8.0f, 0.0f, 2.8f))) { - float absorb = float(sphere_index) / float(NUM_SPHERES - 1); - - hit_info.material = get_zeroed_material(); - hit_info.material.albedo = vec3(0.9f, 0.25f, 0.25f); - hit_info.material.emissive = vec3(0.0f, 0.0f, 0.0f); - hit_info.material.specular_chance = 0.02f; - hit_info.material.specular_roughness = 0.0f; - hit_info.material.specular_color = vec3(1.0f, 1.0f, 1.0f) * 0.8f; - hit_info.material.ior = 1.1f; - hit_info.material.refraction_chance = 1.0f; - hit_info.material.refraction_roughness = 0.0f; - hit_info.material.refraction_color = vec3(1.0f, 2.0f, 3.0f) * absorb; - } - } - -#elif SCENE == 4 - - const int NUM_SPHERES = 7; - for (int sphere_index = 0; sphere_index < NUM_SPHERES; ++sphere_index) { - if (test_sphere_trace(ray_pos, ray_dir, hit_info, - vec4(-18.0f + 6.0f * float(sphere_index), - -9.0f + 0.75f * float(sphere_index), 0.0f, 2.8f))) { - hit_info.material = get_zeroed_material(); - hit_info.material.albedo = vec3(0.9f, 0.25f, 0.25f); - hit_info.material.emissive = vec3(0.0f, 0.0f, 0.0f); - hit_info.material.specular_chance = 0.02f; - hit_info.material.specular_roughness = 0.0f; - hit_info.material.specular_color = vec3(1.0f, 1.0f, 1.0f) * 0.8f; - hit_info.material.ior = 1.5f; - hit_info.material.refraction_chance = 1.0f; - hit_info.material.refraction_roughness = 0.0f; - } - } - -#elif SCENE == 5 - - const int NUM_SPHERES = 7; - for (int sphere_index = 0; sphere_index < NUM_SPHERES; ++sphere_index) { - if (test_sphere_trace(ray_pos, ray_dir, hit_info, - vec4(-18.0f + 6.0f * float(sphere_index), -9.0f, 0.0f, 2.8f))) { - float transparency = float(sphere_index) / float(NUM_SPHERES - 1); - - hit_info.material = get_zeroed_material(); - hit_info.material.albedo = vec3(0.9f, 0.25f, 0.25f); - hit_info.material.emissive = vec3(0.0f, 0.0f, 0.0f); - hit_info.material.specular_chance = 0.02f; - hit_info.material.specular_roughness = 0.0f; - hit_info.material.specular_color = vec3(1.0f, 1.0f, 1.0f) * 0.8f; - hit_info.material.ior = 1.1f; - hit_info.material.refraction_chance = 1.0f - transparency; - hit_info.material.refraction_roughness = 0.0f; - } - } - -#elif SCENE == 6 - - const int NUM_SPHERES = 7; - for (int sphere_index = 0; sphere_index < NUM_SPHERES; ++sphere_index) { - if (test_sphere_trace(ray_pos, ray_dir, hit_info, - vec4(-18.0f + 6.0f * float(sphere_index), -8.0f, 00.0f, 2.8f))) { - float r = float(sphere_index) / float(NUM_SPHERES - 1) * 0.5f; - - hit_info.material = get_zeroed_material(); - hit_info.material.albedo = vec3(0.9f, 0.25f, 0.25f); - hit_info.material.emissive = vec3(0.0f, 0.0f, 0.0f); - hit_info.material.specular_chance = 0.02f; - hit_info.material.specular_roughness = r; - hit_info.material.specular_color = vec3(1.0f, 1.0f, 1.0f) * 0.8f; - hit_info.material.ior = 1.1f; - hit_info.material.refraction_chance = 1.0f; - hit_info.material.refraction_roughness = r; - hit_info.material.refraction_color = vec3(0.0f, 0.0f, 0.0f); - } - } - -#endif -} - -void advance_ray(inout vec3 ray_pos, inout vec3 ray_dir, inout vec3 throughput, inout RayHitInfo hit_info, - inout vec3 ret, inout uint rng_state) { - if (hit_info.from_inside) { - throughput *= exp(-hit_info.material.refraction_color * hit_info.dist); - } - - float specular_chance = hit_info.material.specular_chance; - float refraction_chance = hit_info.material.refraction_chance; - - float ray_probability = 1.0; - if (specular_chance > 0.0) { - specular_chance = - fresnel_refelect_amount(hit_info.from_inside ? hit_info.material.ior : 1.0, - !hit_info.from_inside ? hit_info.material.ior : 1.0, ray_dir, - hit_info.normal, hit_info.material.specular_chance, 1.0); - - float chance_multiplier = - (1.0 - specular_chance) / (1.0 - hit_info.material.specular_chance); - refraction_chance *= chance_multiplier; - } - - float do_specular = 0.0; - float do_refraction = 0.0; - float ray_select_roll = random_float01(rng_state); - if (specular_chance > 0.0 && ray_select_roll < specular_chance) { - do_specular = 1.0; - ray_probability = specular_chance; - } else if (refraction_chance > 0.0 && ray_select_roll < specular_chance + refraction_chance) { - do_refraction = 1.0; - ray_probability = refraction_chance; - } else { - ray_probability = 1.0 - (specular_chance + refraction_chance); - } - - ray_probability = max(ray_probability, 0.001); - - if (do_refraction == 1.0) { - ray_pos = (ray_pos + ray_dir * hit_info.dist) - hit_info.normal * RAY_NORMAL_NUDGE; - } else { - ray_pos = (ray_pos + ray_dir * hit_info.dist) + hit_info.normal * RAY_NORMAL_NUDGE; - } - - vec3 diffuse_ray_dir = normalize(hit_info.normal + random_unit_vector(rng_state)); - - vec3 specular_ray_dir = reflect(ray_dir, hit_info.normal); - specular_ray_dir = - normalize(mix(specular_ray_dir, diffuse_ray_dir, - hit_info.material.specular_roughness * hit_info.material.specular_roughness)); - vec3 refraction_ray_dir = - refract(ray_dir, hit_info.normal, - hit_info.from_inside ? hit_info.material.ior : 1.0 / hit_info.material.ior); - refraction_ray_dir = normalize( - mix(refraction_ray_dir, normalize(-hit_info.normal + random_unit_vector(rng_state)), - hit_info.material.refraction_roughness * hit_info.material.refraction_roughness)); - - ray_dir = mix(diffuse_ray_dir, specular_ray_dir, do_specular); - ray_dir = mix(ray_dir, refraction_ray_dir, do_refraction); - - ret += hit_info.material.emissive; - ret *= throughput; - // ret += diff * atm * 0.1; - - if (do_refraction == 0.0) { - throughput *= mix(hit_info.material.albedo, hit_info.material.specular_color, do_specular); - } - - throughput *= mix(hit_info.material.albedo, hit_info.material.specular_color, do_specular); - - throughput /= ray_probability; -} - -void processHit(inout vec3 ro, inout vec3 rd, inout vec3 col, - inout vec3 att, float ior, RayHitInfo res) { - Material m = get_zeroed_material(); - - col += att * res.material.emissive; - att *= res.material.albedo; - vec3 normal = res.normal; - ro = ro + rd * res.dist; - float inside = float(res.from_inside); - - vec3 matn = normalize(nrand3(0.005, normal * inside)); - vec3 newrd = refract(rd, matn, pow(ior, -inside)); - if (length(newrd) > 0.5) // not total internal reflection - { - inside = -inside; - rd = newrd; - } else { - rd = reflect(rd, matn); - } -} - -vec3 get_color_for_ray(in vec3 start_ray_pos, in vec3 start_ray_dir, inout uint rng_state) { - vec3 ret = vec3(0.0); - vec3 throughput = vec3(1.0); - vec3 ray_pos = start_ray_pos; - vec3 ray_dir = start_ray_dir; - - for (int bounce_index = 0; bounce_index <= NUM_BOUNCES; ++bounce_index) { - RayHitInfo hit_info; - hit_info.material = get_zeroed_material(); - hit_info.dist = SUPER_FAR; - hit_info.from_inside = false; - - test_scene_trace(ray_pos, ray_dir, hit_info); - - if (hit_info.dist == SUPER_FAR) { - vec3 pos = (ray_pos + ray_dir * hit_info.dist) * 0.01; - float background = - 1. - float((int(pos.x) ^ int(pos.y)) % 9) * SKYBOX_BRIGHTNESS_MULTIPLIER; - ret += srgb_to_linear(vec3(background)) * 0.5 * throughput; - break; - } - - advance_ray(ray_pos, ray_dir, throughput, hit_info, ret, rng_state); - - { - float p = max(throughput.r, max(throughput.g, throughput.b)); - if (random_float01(rng_state) > p) - break; - throughput *= 1.0 / p; - } - } - - return ret; -} - -mat3 camera_rotation(vec2 m) { - m.y = -m.y; - - vec2 s = sin(m); - vec2 c = cos(m); - mat3 rotX = mat3(1.0, 0.0, 0.0, 0.0, c.y, s.y, 0.0, -s.y, c.y); - mat3 rotY = mat3(c.x, 0.0, -s.x, 0.0, 1.0, 0.0, s.x, 0.0, c.x); - - return rotY * rotX; -} - -void get_camera_vectors(out vec3 camera_pos, - out vec3 camera_fwd, - out vec3 camera_up, - out vec3 camera_right) { - vec2 mouse; - mouse.x = imageLoad(float_texture2, ivec2(0, 0)).x; - mouse.y = imageLoad(float_texture2, ivec2(1, 0)).x; - if (dot(mouse, vec2(1.0, 1.0)) == 0.0) { - camera_pos = vec3(0.0, 0.0, -CAMERA_DISTANCE); - camera_fwd = vec3(0.0, 0.0, 1.0); - camera_up = vec3(0.0, 1.0, 0.0); - camera_right = vec3(1.0, 0.0, 0.0); - return; - } - - float angle_x = mouse.x * 16. / float(pc.resolution.x); - float angle_y = - mix(MIN_CAMERA_ANGLE, MAX_CAMERA_ANGLE, mouse.y / float(pc.resolution.y)) - PI / 2.; - - camera_pos.x = sin(angle_x) * sin(angle_y) * CAMERA_DISTANCE; - camera_pos.y = -cos(angle_y) * CAMERA_DISTANCE; - camera_pos.z = cos(angle_x) * sin(angle_y) * CAMERA_DISTANCE; - - camera_pos += CAMERA_AT; - - camera_fwd = normalize(CAMERA_AT - camera_pos); - camera_right = normalize(cross(vec3(0.0, 1.0, 0.0), camera_fwd)); - camera_up = normalize(cross(camera_fwd, camera_right)); -} - -vec2 mouse = pc.mouse; - -void main() { - if (gl_GlobalInvocationID.x >= pc.resolution.x || gl_GlobalInvocationID.y >= pc.resolution.y) { - return; - } - - if (pc.mouse_pressed) { - vec2 mouse = (pc.mouse * 0.5 + 1) * pc.resolution; - imageStore(float_texture2, ivec2(0, 0), vec4(mouse.x, 0., 0., 0.)); - imageStore(float_texture2, ivec2(1, 0), vec4(mouse.y, 0., 0., 0.)); - } - - rng_initialize(gl_GlobalInvocationID.xy, pc.frame); - - vec2 frag_coord = gl_GlobalInvocationID.xy; - uint rng_state = uint(uint(frag_coord.x) * uint(1973) + uint(frag_coord.y) * uint(9277) + - pc.frame * uint(26699)) | uint(1); - - vec2 jitter = vec2(random_float01(rng_state), random_float01(rng_state)) - 0.5; - - vec3 camera_pos, camera_fwd, camera_up, camera_right; - get_camera_vectors(camera_pos, camera_fwd, camera_up, camera_right); - vec3 ray_dir; - { - vec2 screen = ((frag_coord + jitter) / pc.resolution.xy + -0.5) * 2.0 * - vec2(pc.resolution.x / pc.resolution.y, 1); - - camera_pos += pc.pos * 20.; - - float camera_distance = tan(FOV_DEGREES * 0.5 * PI / 180.0); - ray_dir = vec3(screen, camera_distance); - ray_dir = normalize(mat3(camera_right, camera_up, camera_fwd) * ray_dir); - } - - vec3 color = vec3(0.0); - for (int i = 0; i < NUM_RENDERS_PER_FRAME; ++i) { - color += get_color_for_ray(camera_pos, ray_dir, rng_state) / float(NUM_RENDERS_PER_FRAME); - } - - vec3 last_frame_color = imageLoad(float_texture1, ivec2(frag_coord)).rgb; - color = mix(last_frame_color, color, 1.0 / float(pc.frame + 1)); - - imageStore(float_texture1, ivec2(frag_coord), vec4(color, 1.)); -} diff --git a/examples/path_tracer/shaders/shader.frag b/examples/path_tracer/shaders/shader.frag deleted file mode 100644 index f88dd9c..0000000 --- a/examples/path_tracer/shaders/shader.frag +++ /dev/null @@ -1,42 +0,0 @@ -#version 460 - -#include - -// In the beginning, colours never existed. There's nothing that was done before you... - -/* - Big credits to the example made by demofox - https://blog.demofox.org/2020/05/25/casual-shadertoy-path-tracing-1-basic-camera-diffuse-emissive/ -*/ - -layout(location = 0) in vec2 in_uv; -layout(location = 0) out vec4 out_color; - -layout(set = 0, binding = 0) uniform texture2D prev_frame; -layout(set = 0, binding = 1) uniform texture2D generic_texture; -layout(set = 0, binding = 2) uniform texture2D dummy_texture; -layout(set = 0, binding = 3) uniform texture2D float_texture1; -layout(set = 0, binding = 4) uniform texture2D float_texture2; -layout(set = 1, binding = 0) uniform sampler tex_sampler; -#define T(tex, uv_coord) (texture(sampler2D(tex, tex_sampler), uv_coord)) -#define Tuv(tex) (T(tex, in_uv)) -#define T_off(tex, off) (T(tex, vec2(in_uv.x + off.x, -(in_uv.y + off.y)))) - -layout(std430, push_constant) uniform PushConstant { - vec3 pos; - float time; - vec2 resolution; - vec2 mouse; - bool mouse_pressed; - uint frame; - float time_delta; - float record_period; -} pc; - -void main() { - vec3 color = Tuv(float_texture1).rgb; - color *= EXPOSURE; - color = ACESFilm(color); - color = linear_to_srgb(color); - out_color = vec4(color, 1.0); -} diff --git a/examples/path_tracer/shaders/shader.vert b/examples/path_tracer/shaders/shader.vert deleted file mode 100644 index 9d9e662..0000000 --- a/examples/path_tracer/shaders/shader.vert +++ /dev/null @@ -1,19 +0,0 @@ -#version 460 - -layout(location = 0) out vec2 out_uv; - -layout(std430, push_constant) uniform PushConstant { - vec3 pos; - float time; - vec2 resolution; - vec2 mouse; - bool mouse_pressed; - uint frame; - float time_delta; - float record_period; -} pc; - -void main() { - out_uv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); - gl_Position = vec4(out_uv * 2.0f + -1.0f, 0.0, 1.0); -} diff --git a/examples/slices/shaders/prelude.glsl b/examples/slices/shaders/prelude.glsl deleted file mode 100644 index e69de29..0000000 diff --git a/examples/slices/shaders/shader.comp b/examples/slices/shaders/shader.comp deleted file mode 100644 index 0e3e1a8..0000000 --- a/examples/slices/shaders/shader.comp +++ /dev/null @@ -1,54 +0,0 @@ -#version 460 - -layout(std430, push_constant) uniform PushConstant { - vec3 pos; - float time; - vec2 resolution; - vec2 mouse; - bool mouse_pressed; - uint frame; - float time_delta; - float record_period; -} pc; - -layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in; - -layout (binding = 0, rgba8) uniform image2D previous_frame; -layout (binding = 1, rgba8) uniform image2D generic_texture; -layout (binding = 2, rgba8) uniform image2D dummy_texture; - -layout (binding = 3, rgba32f) uniform image2D float_texture1; -layout (binding = 4, rgba32f) uniform image2D float_texture2; - -uvec4 s0, s1; -ivec2 pixel; - -void rng_initialize(vec2 p, uint frame) { - pixel = ivec2(p); - - //white noise seed - s0 = uvec4(p, uint(frame), uint(p.x) + uint(p.y)); - - //blue noise seed - s1 = uvec4(frame, frame * 15843, frame * 31 + 4566, frame * 2345 + 58585); -} - -// https://www.pcg-random.org/ -uvec4 pcg4d(inout uvec4 v) { - v = v * 1664525u + 1013904223u; - v.x += v.y*v.w; v.y += v.z*v.x; v.z += v.x*v.y; v.w += v.y*v.z; - v = v ^ (v >> 16u); - v.x += v.y*v.w; v.y += v.z*v.x; v.z += v.x*v.y; v.w += v.y*v.z; - return v; -} -vec4 rand4() { return vec4(pcg4d(s0)) / float(0xffffffffu); } - -void main() { - if (gl_GlobalInvocationID.x >= pc.resolution.x || - gl_GlobalInvocationID.y >= pc.resolution.y) { - return; - } - - rng_initialize(gl_GlobalInvocationID.xy, pc.frame); - imageStore(float_texture1, ivec2(gl_GlobalInvocationID.xy), rand4()); -} diff --git a/examples/slices/shaders/shader.frag b/examples/slices/shaders/shader.frag deleted file mode 100644 index 4f70cc6..0000000 --- a/examples/slices/shaders/shader.frag +++ /dev/null @@ -1,277 +0,0 @@ -#version 460 - -// In the beginning, colours never existed. There's nothing that was done before you... - -layout(location = 0) in vec2 in_uv; -layout(location = 0) out vec4 out_color; - -layout(set = 0, binding = 0) uniform texture2D prev_frame; -layout(set = 0, binding = 1) uniform texture2D generic_texture; -layout(set = 0, binding = 2) uniform texture2D dummy_texture; -layout(set = 0, binding = 3) uniform texture2D float_texture1; -layout(set = 0, binding = 4) uniform texture2D float_texture2; -layout(set = 1, binding = 0) uniform sampler tex_sampler; -#define T(tex, uv_coord) (texture(sampler2D(tex, tex_sampler), uv_coord)) -#define Tuv(tex) (T(tex, in_uv)) -#define T_off(tex, off) (T(tex, vec2(in_uv.x + off.x, -(in_uv.y + off.y)))) - -layout(std430, push_constant) uniform PushConstant { - vec3 pos; - float time; - vec2 resolution; - vec2 mouse; - bool mouse_pressed; - uint frame; - float time_delta; - float record_period; -} pc; - -const vec3 EPS = vec3(0., 0.01, 0.0001); -const float PI = acos(-1.); -const float TAU = 2. * PI; - -// https://jbaker.graphics/writings/DEC.html -float sd_dodecahedron(vec3 p, float radius) { - const float phi = 1.61803398875; - const vec3 n = normalize(vec3(phi, 1, 0)); - - p = abs(p / radius); - float a = dot(p, n.xyz); - float b = dot(p, n.zxy); - float c = dot(p, n.yzx); - return (max(max(a, b), c) - n.x) * radius; -} -float sd_icosahedron(vec3 p, float radius){ - const float q = 2.61803398875; - const vec3 n1 = normalize(vec3(q, 1, 0)); - const vec3 n2 = vec3(0.57735026919); - - p = abs(p / radius); - float a = dot(p, n1.xyz); - float b = dot(p, n1.zxy); - float c = dot(p, n1.yzx); - float d = dot(p, n2) - n1.x; - return max(max(max(a, b), c) - n1.x, d) * radius; -} -float sd_icosahestar(vec3 p){ - float radius = 1.5; - return min(sd_dodecahedron(p, radius), sd_icosahedron(p.zyx, radius)); -} - -const int NUM_CUTS = 5; -vec3 CUT_DIR[NUM_CUTS]; -float CUT_WIDTH[NUM_CUTS]; -float CUT_OFFSET[NUM_CUTS]; - -void setup_cuts() { - CUT_DIR[0] = normalize(vec3(0., 1., 0.9)); - CUT_DIR[1] = normalize(vec3(1., 0., 0.)); - CUT_DIR[2] = normalize(vec3(0., 0.6, 0.)); - CUT_DIR[3] = normalize(vec3(-1., 0.5, 0.1)); - CUT_DIR[4] = normalize(vec3(-1., 1., 0.)); - - CUT_WIDTH[0] = 0.1; - CUT_WIDTH[1] = 0.2; - CUT_WIDTH[2] = 0.2; - CUT_WIDTH[3] = 0.2; - CUT_WIDTH[4] = 0.6; - - CUT_OFFSET[0] = 0.1; - CUT_OFFSET[1] = -0.2; - CUT_OFFSET[2] = 0.03; - CUT_OFFSET[3] = -0.3; - CUT_OFFSET[4] = 0.; -} - -struct Cut { - vec3 off; - float d; - float sign; -}; - -Cut op_cut(vec3 p, vec3 n, float w, float width) { - float dt = dot(p, n) - w; - float dcut = abs(dt) - width; - float s = sign(dt); - return Cut(width * n * s, dcut, s); -} - -Cut merge_cuts(Cut a, Cut b) { - // Sign computing is not right as expected, - // but I didn't stumble on this problem yet - return Cut(a.off + b.off, min(a.d, b.d), a.sign * b.sign); -} - -Cut dummy_cut() { - return Cut(vec3(0.), 9999., 1.); -} - -// https://suricrasia.online/demoscene/functions/ blackle is a qt >:3c -vec3 erot(vec3 p, vec3 ax, float ro) { - return mix(dot(ax, p) * ax, p, cos(ro)) + cross(ax, p) * sin(ro); -} - -// https://easings.net/#easeInOutBack -float ease_in_out_back(float x){ - const float c1 = 1.70158; - const float c2 = c1 * 1.525; - - return x < 0.5 - ? (pow(2. * x, 2.) * ((c2 + 1.) * 2. * x - c2)) / 2. - : (pow(2. * x - 2., 2.) * ((c2 + 1.) * (x * 2. - 2.) + c2) + 2.) / 2.; -} - -float map(vec3 p) { - float time = mod(pc.time / 14., 1.); - float dist = 999.; - - float trig_wave = min(time, 1. - time); - float saddle = 4 * trig_wave - 0.5; - - Cut cut = dummy_cut(); - for (int i = NUM_CUTS - 1; i >= 0; --i) { - float harm = saddle * float(NUM_CUTS) - float(i); - float delay = 0.4; - float release = clamp((harm - delay) / (1. - delay), 0., 1.); - release = 0.50 - 0.5 * cos(release); - if (release == 0.) continue; - - Cut current_cut = - op_cut(p, CUT_DIR[i], CUT_OFFSET[i], CUT_WIDTH[i] * release); - cut = merge_cuts(cut, current_cut); - // Adjust position in the direction of cut - p -= current_cut.off; - - // Rotate space on the last cut - int last_cut = NUM_CUTS - 1; - if (i == last_cut) { - float rot_dir = current_cut.sign; - p = erot(p, CUT_DIR[last_cut], - rot_dir * ease_in_out_back(release) * 2. * TAU); - } - } - - dist = sd_icosahestar(p); - dist = max(dist, -cut.d); - - return dist; -} - -mat3 get_camera(vec3 eye, vec3 at) { - vec3 zaxis = normalize(at - eye); - vec3 xaxis = normalize(cross(zaxis, vec3(0., 1., 0.))); - vec3 yaxis = cross(xaxis, zaxis); - return mat3(xaxis, yaxis, zaxis); -} - -vec3 get_normal(vec3 p, float r) { - mat3 k = mat3(p, p, p) - mat3(r); - return normalize(vec3(map(p)) - vec3(map(k[0]), map(k[1]), map(k[2]))); -} - -vec3 sky(vec3 rd) { - vec3 col = vec3(0.); - col+=smoothstep(0.2,1.5,dot(rd, normalize(vec3(0.,-1.,0.)))) * 0.1*vec3(0.67843,0.67451,0.709); - col+=smoothstep(.2,1.0, dot(rd, normalize(vec3(0,1,-3)))) * 0.2 * vec3(0.3647,0.2902,0.63137); - col+=smoothstep(-0.4,0.4, dot(rd, normalize(vec3(0.9,0.2,0.6)))) * 0.2 * vec3(0.1,0.4,0.3); - col+=smoothstep(-0.4,0.4, dot(rd + vec3(0.0,0.7,0.0), normalize(vec3(0.0,-0.2,0.0)))) * - vec3(0.1, 0.0, 0.3) * 0.1; - return col; -} - -//https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/ -vec3 ACESFilm(vec3 x){ - return clamp((x * (2.51 * x + 0.03)) / (x * (2.43 * x + 0.59) + 0.14), 0.0, 1.0); -} - -void main() { - vec2 uv = (in_uv + -0.5) * 2.0 * vec2(pc.resolution.x / pc.resolution.y, 1); - float time = pc.time; - - setup_cuts(); - - vec3 target = vec3 (0., 0., 0.); - float an = TAU * time / 20.; - vec3 ro = target + 4. * vec3(cos(an), .6, sin(an)); - mat3 cam = get_camera(ro, target); - float zoom = 1.; - vec3 rd = cam * vec3(uv, zoom); - - const float cone_radius = .7071 / (pc.resolution.y * zoom); - - float coverage = -1.0; - vec3 cover_dir = vec3(0.); - - const float aperture = .05; - const float focus = 3.4; - - vec3 col = vec3(0.); - - float t = 0.; - for (int i = 0; i < 70; ++i) { - const float radius = t * cone_radius + aperture * abs(t - focus); - vec3 pos = ro + t * rd; - float dist = map(pos); - - if (dist < radius) { - vec3 normal = get_normal(pos, radius); - - vec3 albedo = vec3(.15); - // if the normal not looking outside of the sphere - // so it's inner plane and should be colored - if (dot(pos, normal) < 0.5) { - albedo = vec3(2.5, 0.0, 0.0); - } - - vec3 ambient = - vec3(.1) * smoothstep(.7, 2.0, length(pos.xz) + abs(pos.y)); - vec3 directional = - 3.0 * vec3(1, .1, .13) * - max(dot(normal, normalize(vec3(-2, -2, -1))), .0); - directional *= - smoothstep(.5, 1.5, dot(pos, normalize(vec3(1, 1, -1)))); - - float fresnel = pow(1.0 - abs(dot(normal, rd)), 5.0); - fresnel = mix(.03, 1.0, fresnel); - - vec3 reflection = sky(reflect(rd, normal)); - - vec3 sample_color = mix(albedo * (ambient + directional), - reflection, vec3(fresnel)); - - // bottom light - { - float dif = 0.02 * clamp(0.5 - 0.5 * normal.y, 0., 1.); - sample_color += dif; - } - - float new_coverage = -dist / radius; - vec3 new_coverage_dir = normalize(normal - dot(normal, rd) * rd); - - new_coverage += - (1.0 + coverage) * (.5 - .5 * dot(new_coverage_dir, cover_dir)); - new_coverage = min(new_coverage, 1.0); - - if (new_coverage > coverage) { - col += sample_color * (new_coverage - coverage) * .5; - - cover_dir = - normalize(mix(new_coverage_dir, cover_dir, - (coverage + 1.0) / (new_coverage + 1.0))); - coverage = new_coverage; - } - } - t += max(dist, radius * .5); - if (dist < -radius || coverage > 1.0) - break; - } - col += (1.0 - coverage) * .5 * sky(rd); - - // Tonemapping - col = ACESFilm(col); - - vec2 frag_coord = in_uv * pc.resolution; - col += sin(frag_coord.x * 314.98) * sin(frag_coord.y * 551.98) / 1024.0; - - out_color = vec4(col, 1.0); -} diff --git a/examples/slices/shaders/shader.vert b/examples/slices/shaders/shader.vert deleted file mode 100644 index 9d9e662..0000000 --- a/examples/slices/shaders/shader.vert +++ /dev/null @@ -1,19 +0,0 @@ -#version 460 - -layout(location = 0) out vec2 out_uv; - -layout(std430, push_constant) uniform PushConstant { - vec3 pos; - float time; - vec2 resolution; - vec2 mouse; - bool mouse_pressed; - uint frame; - float time_delta; - float record_period; -} pc; - -void main() { - out_uv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); - gl_Position = vec4(out_uv * 2.0f + -1.0f, 0.0, 1.0); -} diff --git a/examples/slices/slices.png b/examples/slices/slices.png deleted file mode 100644 index 82245c1..0000000 Binary files a/examples/slices/slices.png and /dev/null differ diff --git a/pilka_ash/Cargo.lock b/pilka_ash/Cargo.lock deleted file mode 100644 index f9c07de..0000000 --- a/pilka_ash/Cargo.lock +++ /dev/null @@ -1,470 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "anyhow" -version = "1.0.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28ae2b3dec75a406790005a200b1bd89785afc02517a00ca99ecfe093ee9e6cf" - -[[package]] -name = "ash" -version = "0.33.1+1.2.186" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4207a81da2432b483058334763ac2381d00342ec3bdf02d413c4d986a610d874" -dependencies = [ - "libloading", -] - -[[package]] -name = "ash" -version = "0.35.2+1.2.203" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f6a491bcad4563b355ac2bb6e3f09d5e1c5d628710c7156e901dad0c416075e" - -[[package]] -name = "ash" -version = "0.37.0+1.3.209" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "006ca68e0f2b03f22d6fa9f2860f85aed430d257fec20f8879b2145e7c7ae1a6" - -[[package]] -name = "ash-molten" -version = "0.12.0+1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46b51f10940e9e2022ff1cecbc73ba848d0edda13084f2063980546e945b0e7b" -dependencies = [ - "anyhow", - "ash 0.35.2+1.2.203", - "plist", - "serde", -] - -[[package]] -name = "ash-window" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e199a4119a1695c8d865b3f5d6c1ee164370c0c5bc91c8284cf79b0f0be78ba" -dependencies = [ - "ash 0.37.0+1.3.209", - "raw-window-handle 0.3.4", - "raw-window-metal", -] - -[[package]] -name = "autocfg" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" - -[[package]] -name = "base64" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "block" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" - -[[package]] -name = "bytemuck" -version = "1.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdead85bdec19c194affaeeb670c0e41fe23de31459efd1c174d049269cf02cc" -dependencies = [ - "bytemuck_derive", -] - -[[package]] -name = "bytemuck_derive" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562e382481975bc61d11275ac5e62a19abd00b0547d99516a415336f183dcd0e" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "cocoa" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63902e9223530efb4e26ccd0cf55ec30d592d3b42e21a28defc42a9586e832" -dependencies = [ - "bitflags", - "block", - "cocoa-foundation", - "core-foundation", - "core-graphics", - "foreign-types", - "libc", - "objc", -] - -[[package]] -name = "cocoa-foundation" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318" -dependencies = [ - "bitflags", - "block", - "core-foundation", - "core-graphics-types", - "foreign-types", - "libc", - "objc", -] - -[[package]] -name = "core-foundation" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" - -[[package]] -name = "core-graphics" -version = "0.22.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "269f35f69b542b80e736a20a89a05215c0ce80c2c03c514abb2e318b78379d86" -dependencies = [ - "bitflags", - "core-foundation", - "core-graphics-types", - "foreign-types", - "libc", -] - -[[package]] -name = "core-graphics-types" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" -dependencies = [ - "bitflags", - "core-foundation", - "foreign-types", - "libc", -] - -[[package]] -name = "cty" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" - -[[package]] -name = "indexmap" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "ktx" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0112c5d660975a0c6e068c0901b9178d9aeeb62106eac227cbab2502955ea9f8" -dependencies = [ - "byteorder", -] - -[[package]] -name = "libc" -version = "0.2.101" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21" - -[[package]] -name = "libloading" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f84d96438c15fcd6c3f244c8fce01d1e2b9c6b5623e9c711dc9286d8fc92d6a" -dependencies = [ - "cfg-if", - "winapi", -] - -[[package]] -name = "line-wrap" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9" -dependencies = [ - "safemem", -] - -[[package]] -name = "malloc_buf" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" -dependencies = [ - "libc", -] - -[[package]] -name = "num-integer" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" -dependencies = [ - "autocfg", -] - -[[package]] -name = "objc" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" -dependencies = [ - "malloc_buf", -] - -[[package]] -name = "once_cell" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" - -[[package]] -name = "pilka_ash" -version = "0.7.7" -dependencies = [ - "ash 0.33.1+1.2.186", - "ash-molten", - "ash-window", - "bytemuck", - "ktx", - "pilka_types", - "puffin", - "raw-window-handle 0.4.3", -] - -[[package]] -name = "pilka_types" -version = "0.7.0" -dependencies = [ - "bytemuck", -] - -[[package]] -name = "plist" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a38d026d73eeaf2ade76309d0c65db5a35ecf649e3cec428db316243ea9d6711" -dependencies = [ - "base64", - "chrono", - "indexmap", - "line-wrap", - "serde", - "xml-rs", -] - -[[package]] -name = "proc-macro2" -version = "1.0.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "puffin" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "addd5c604612d1d36d3605d37621bacb1772c2247e2f176b6a464c71f71ec40e" -dependencies = [ - "byteorder", - "once_cell", -] - -[[package]] -name = "quote" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "raw-window-handle" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28f55143d0548dad60bb4fbdc835a3d7ac6acc3324506450c5fdd6e42903a76" -dependencies = [ - "libc", - "raw-window-handle 0.4.3", -] - -[[package]] -name = "raw-window-handle" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b800beb9b6e7d2df1fe337c9e3d04e3af22a124460fb4c30fcc22c9117cefb41" -dependencies = [ - "cty", -] - -[[package]] -name = "raw-window-metal" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cd21ed1cdef7f1b1579b972148ba6058b5b545959a14d91ea83c4f0ea9f289b" -dependencies = [ - "cocoa", - "core-graphics", - "objc", - "raw-window-handle 0.3.4", -] - -[[package]] -name = "safemem" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" - -[[package]] -name = "serde" -version = "1.0.130" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.130" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "syn" -version = "1.0.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "unicode-xid" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "xml-rs" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" diff --git a/pilka_ash/Cargo.toml b/pilka_ash/Cargo.toml deleted file mode 100644 index cfc773e..0000000 --- a/pilka_ash/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "pilka_ash" -version = "0.7.11" -authors = ["Alex Komissarov "] -edition = "2021" -license = "MIT" -description = "Homebrew and probably-not-so-great vulkan renderer" -repository = "https://github.com/pudnax/pilka/" -readme = "README.md" -keywords = ["graphics", "glsl", "shaders", "creative", "vulkan"] -exclude = [".gitignore", ".github", "screenshots", "recordings", "shader_dump"] -categories = ["command-line-utilities", "graphics", "rendering"] - -[badges] -appveyor = { repository = "https://github.com/pudnax/pilka", branch = "master", service = "github" } -maintenance = { status = "experimental" } - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -ash = "0.37.0" -ash-molten = "0.13.0" -ash-window = "0.12.0" -raw-window-handle = "0.5.0" -bytemuck = { version = "1.12.1", features = ["derive"] } -ktx = "0.3.2" -pilka_types = { version = "0.7.1", path = "../pilka_types" } -puffin = "0.13.3" diff --git a/pilka_ash/README.md b/pilka_ash/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/pilka_ash/src/lib.rs b/pilka_ash/src/lib.rs deleted file mode 100644 index 4de1990..0000000 --- a/pilka_ash/src/lib.rs +++ /dev/null @@ -1,24 +0,0 @@ -#![warn(unsafe_op_in_unsafe_fn)] -#![allow( - // We use loops for getting early-out of scope without closures. - clippy::never_loop, - // We don't use syntax sugar where it's not necessary. - clippy::match_like_matches_macro, - // Redundant matching is more explicit. - clippy::redundant_pattern_matching, - // Explicit lifetimes are often easier to reason about. - clippy::needless_lifetimes, - // No need for defaults in the internal types. - clippy::new_without_default, - // For some reason `rustc` can warn about these in const generics even - // though they are required. - unused_braces, -)] -#![warn(trivial_casts, trivial_numeric_casts, unused_extern_crates)] - -mod renderer; -pub use renderer::AshRender; - -mod pvk; -pub use ash::*; -pub use pvk::*; diff --git a/pilka_ash/src/pvk/command_pool.rs b/pilka_ash/src/pvk/command_pool.rs deleted file mode 100644 index 4830ad1..0000000 --- a/pilka_ash/src/pvk/command_pool.rs +++ /dev/null @@ -1,74 +0,0 @@ -use super::device::{RawDevice, VkDevice}; -use ash::{prelude::VkResult, vk}; -use std::sync::Arc; - -// -// Otherwise the pool will keep on growing until you run out of memory -pub struct VkCommandPool { - pub pool: vk::CommandPool, - pub active_command: usize, - pub command_buffers: Vec, - pub fences: Vec, - pub device: Arc, -} - -impl VkCommandPool { - // TODO: Make `record_submit_commandbuffer` method unmutable - pub fn record_submit_commandbuffer( - &mut self, - device: &VkDevice, - submit_queue: vk::Queue, - wait_mask: &[vk::PipelineStageFlags], - wait_semaphores: &[vk::Semaphore], - signal_semaphores: &[vk::Semaphore], - f: F, - ) -> VkResult<()> { - let submit_fence = self.fences[self.active_command]; - let command_buffer = self.command_buffers[self.active_command]; - - unsafe { device.wait_for_fences(&[submit_fence], true, std::u64::MAX) }?; - unsafe { device.reset_fences(&[submit_fence]) }?; - - unsafe { - device.reset_command_buffer( - command_buffer, - vk::CommandBufferResetFlags::RELEASE_RESOURCES, - ) - }?; - - let command_buffer_begin_info = vk::CommandBufferBeginInfo::builder() - .flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT); - - unsafe { device.begin_command_buffer(command_buffer, &command_buffer_begin_info) }?; - - f(device, command_buffer); - - unsafe { device.end_command_buffer(command_buffer) }?; - - let command_buffers = [command_buffer]; - - let submit_info = vk::SubmitInfo::builder() - .wait_semaphores(wait_semaphores) - .wait_dst_stage_mask(wait_mask) - .command_buffers(&command_buffers) - .signal_semaphores(signal_semaphores); - - unsafe { device.queue_submit(submit_queue, &[submit_info.build()], submit_fence) }?; - - self.active_command = (self.active_command + 1) % self.fences.len(); - - Ok(()) - } -} - -impl Drop for VkCommandPool { - fn drop(&mut self) { - unsafe { - for &fence in &self.fences { - self.device.destroy_fence(fence, None); - } - - self.device.destroy_command_pool(self.pool, None); - } - } -} diff --git a/pilka_ash/src/pvk/device.rs b/pilka_ash/src/pvk/device.rs deleted file mode 100644 index 928a2cd..0000000 --- a/pilka_ash/src/pvk/device.rs +++ /dev/null @@ -1,659 +0,0 @@ -use ash::{extensions::khr, prelude::VkResult, vk, Device}; -use std::sync::Arc; - -use super::{ - command_pool::VkCommandPool, - instance::{VkInstance, VkQueues}, - renderpass_and_pipeline::VkRenderPass, - surface::VkSurface, - swapchain::VkSwapchain, - utils, -}; - -pub struct VkDevice { - pub physical_device: vk::PhysicalDevice, - pub memory_properties: vk::PhysicalDeviceMemoryProperties, - pub device: Arc, - pub instance: Arc, -} - -pub struct RawDevice { - device: Device, -} - -impl std::fmt::Debug for RawDevice { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "RawDevice btw") - } -} - -impl RawDevice { - pub fn new(device: Device) -> Self { - Self { device } - } - - pub fn handle(&self) -> vk::Device { - self.device.handle() - } -} - -impl std::ops::Deref for RawDevice { - type Target = Device; - - fn deref(&self) -> &Self::Target { - &self.device - } -} - -#[derive(Debug)] -pub struct VkDeviceProperties { - pub memory: vk::PhysicalDeviceMemoryProperties, - pub features: vk::PhysicalDeviceFeatures, - pub properties: vk::PhysicalDeviceProperties, -} - -impl std::ops::Deref for VkDevice { - type Target = ash::Device; - - fn deref(&self) -> &Self::Target { - &self.device.device - } -} - -impl VkDevice { - pub fn get_device_properties(&self, instance: &VkInstance) -> VkDeviceProperties { - let (properties, features, memory) = unsafe { - let properties = instance - .instance - .get_physical_device_properties(self.physical_device); - let features = instance - .instance - .get_physical_device_features(self.physical_device); - let memory = instance - .instance - .get_physical_device_memory_properties(self.physical_device); - (properties, features, memory) - }; - - VkDeviceProperties { - memory, - features, - properties, - } - } - - pub fn create_fence(&self, signaled: bool) -> VkResult { - let device = &self.device; - let mut flags = vk::FenceCreateFlags::empty(); - if signaled { - flags |= vk::FenceCreateFlags::SIGNALED; - } - unsafe { device.create_fence(&vk::FenceCreateInfo::builder().flags(flags).build(), None) } - } - - pub fn create_semaphore(&self) -> VkResult { - let device = &self.device; - unsafe { device.create_semaphore(&vk::SemaphoreCreateInfo::default(), None) } - } - - pub fn create_vk_command_pool( - &self, - queue_family_index: u32, - num_command_buffers: u32, - ) -> VkResult { - let pool_create_info = vk::CommandPoolCreateInfo::builder() - .flags(vk::CommandPoolCreateFlags::RESET_COMMAND_BUFFER) - .queue_family_index(queue_family_index); - - let pool = unsafe { self.create_command_pool(&pool_create_info, None) }?; - - let command_buffer_allocate_info = vk::CommandBufferAllocateInfo::builder() - .command_buffer_count(num_command_buffers) - .command_pool(pool) - .level(vk::CommandBufferLevel::PRIMARY); - - let command_buffers = - unsafe { self.allocate_command_buffers(&command_buffer_allocate_info) }?; - - let fences: Result<_, _> = (0..num_command_buffers) - .map(|_| self.create_fence(true)) - .collect(); - let fences = fences?; - - Ok(VkCommandPool { - pool, - command_buffers, - fences, - device: self.device.clone(), - active_command: 0, - }) - } - - pub fn create_vk_render_pass(&self, format: vk::Format) -> VkResult { - let renderpass_attachments = [vk::AttachmentDescription::builder() - .format(format) - .initial_layout(vk::ImageLayout::PRESENT_SRC_KHR) - .samples(vk::SampleCountFlags::TYPE_1) - .load_op(vk::AttachmentLoadOp::LOAD) - .store_op(vk::AttachmentStoreOp::STORE) - .final_layout(vk::ImageLayout::PRESENT_SRC_KHR) - .build()]; - let color_attachment_refs = [vk::AttachmentReference::builder() - .attachment(0) - .layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL) - .build()]; - - let dependencies = [vk::SubpassDependency::builder() - .src_subpass(vk::SUBPASS_EXTERNAL) - .src_stage_mask(vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT) - .dst_subpass(0) - .dst_stage_mask(vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT) - .dst_access_mask( - vk::AccessFlags::COLOR_ATTACHMENT_READ | vk::AccessFlags::COLOR_ATTACHMENT_WRITE, - ) - .build()]; - - let subpasses = [vk::SubpassDescription::builder() - .color_attachments(&color_attachment_refs) - .pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS) - .build()]; - - // Depth textute? Never heard about it. - let renderpass_create_info = vk::RenderPassCreateInfo::builder() - .attachments(&renderpass_attachments) - .subpasses(&subpasses) - .dependencies(&dependencies); - - let renderpass = unsafe { - self.device - .create_render_pass(&renderpass_create_info, None) - }?; - - Ok(VkRenderPass { - render_pass: renderpass, - device: self.device.clone(), - }) - } - - pub fn create_swapchain( - &self, - swapchain_loader: khr::Swapchain, - surface: &VkSurface, - queues: &VkQueues, - ) -> VkResult { - let surface_capabilities = surface.get_capabilities(self)?; - - let desired_image_count = { - let n = surface_capabilities.min_image_count + 3; - n.min(surface_capabilities.max_image_count).max(n) - }; - - let present_mode = surface - .get_present_modes(self)? - .iter() - .cloned() - .find(|&mode| mode == vk::PresentModeKHR::FIFO) - .unwrap_or(vk::PresentModeKHR::FIFO); - - let surface_format = { - let acceptable_formats = { - [ - vk::Format::R8G8B8_SRGB, - vk::Format::B8G8R8_SRGB, - vk::Format::R8G8B8A8_SRGB, - vk::Format::B8G8R8A8_SRGB, - vk::Format::A8B8G8R8_SRGB_PACK32, - ] - }; - surface - .get_formats(self)? - .into_iter() - .find(|sfmt| acceptable_formats.contains(&sfmt.format)) - .expect("Unable to find suitable surface format.") - }; - let format = surface_format.format; - - let pre_transform = if surface_capabilities - .supported_transforms - .contains(vk::SurfaceTransformFlagsKHR::IDENTITY) - { - vk::SurfaceTransformFlagsKHR::IDENTITY - } else { - surface_capabilities.current_transform - }; - - let graphics_queue_family_index = [queues.graphics_queue.index]; - // We've choosed `COLOR_ATTACHMENT` for the same reason like with queue family. - let swapchain_usage = - vk::ImageUsageFlags::COLOR_ATTACHMENT | vk::ImageUsageFlags::TRANSFER_SRC; - let extent = surface_capabilities.current_extent; - let swapchain_create_info = vk::SwapchainCreateInfoKHR::builder() - .surface(surface.surface) - .image_format(format) - .image_usage(swapchain_usage) - .image_extent(extent) - .image_color_space(surface_format.color_space) - .min_image_count(desired_image_count) - .image_array_layers(surface_capabilities.max_image_array_layers) - .queue_family_indices(&graphics_queue_family_index) - .image_sharing_mode(vk::SharingMode::EXCLUSIVE) - .pre_transform(pre_transform) - .composite_alpha(surface_capabilities.supported_composite_alpha) - .present_mode(present_mode) - .clipped(true); - - let swapchain = unsafe { swapchain_loader.create_swapchain(&swapchain_create_info, None)? }; - - let present_images = unsafe { swapchain_loader.get_swapchain_images(swapchain)? }; - let present_image_views = VkSwapchain::create_image_views(&present_images, format, self)?; - - Ok(VkSwapchain { - swapchain, - swapchain_loader, - format, - images: present_images, - image_views: present_image_views, - device: self.device.clone(), - info: swapchain_create_info.build(), - }) - } - - pub fn alloc_memory( - &self, - memory_properties: &vk::PhysicalDeviceMemoryProperties, - allocation_reqs: vk::MemoryRequirements, - flags: vk::MemoryPropertyFlags, - ) -> VkResult { - let memory_type_index = - utils::find_memory_type_index(&allocation_reqs, memory_properties, flags).unwrap(); - let alloc_info = vk::MemoryAllocateInfo::builder() - .allocation_size(allocation_reqs.size) - .memory_type_index(memory_type_index); - unsafe { self.device.allocate_memory(&alloc_info, None) } - } - - pub fn flush_cmd_buffer( - &self, - cmd_buffer: &vk::CommandBuffer, - queue: &vk::Queue, - pool: &vk::CommandPool, - free: bool, - ) -> VkResult<()> { - unsafe { self.end_command_buffer(*cmd_buffer) }?; - - let command_buffers = [*cmd_buffer]; - let submit_info = vk::SubmitInfo::builder().command_buffers(&command_buffers); - - let fence = self.create_fence(false)?; - - let submits = [submit_info.build()]; - unsafe { self.queue_submit(*queue, &submits, fence) }?; - - let fences = [fence]; - unsafe { self.wait_for_fences(&fences, true, !0) }?; - - unsafe { self.destroy_fence(fence, None) }; - - if free { - unsafe { self.free_command_buffers(*pool, &command_buffers) }; - } - - Ok(()) - } - - #[allow(clippy::too_many_arguments)] - pub fn set_image_layout_with_subresource( - &self, - cmd_buffer: vk::CommandBuffer, - image: vk::Image, - old_layout: vk::ImageLayout, - new_layout: vk::ImageLayout, - subresource_range: vk::ImageSubresourceRange, - src_stage_mask: vk::PipelineStageFlags, - dst_stage_mask: vk::PipelineStageFlags, - src_queue_family_index: Option, - dst_queue_family_index: Option, - ) { - let mut image_memory_barrier = vk::ImageMemoryBarrier::builder() - .src_queue_family_index(src_queue_family_index.unwrap_or(0)) - .dst_queue_family_index(dst_queue_family_index.unwrap_or(0)) - .old_layout(old_layout) - .new_layout(new_layout) - .image(image) - .subresource_range(subresource_range); - - use vk::{AccessFlags, ImageLayout}; - image_memory_barrier.src_access_mask = match old_layout { - ImageLayout::UNDEFINED => AccessFlags::empty(), - ImageLayout::PREINITIALIZED => AccessFlags::HOST_WRITE, - ImageLayout::COLOR_ATTACHMENT_OPTIMAL => AccessFlags::COLOR_ATTACHMENT_WRITE, - ImageLayout::PRESENT_SRC_KHR => AccessFlags::MEMORY_WRITE, - ImageLayout::GENERAL => AccessFlags::MEMORY_READ, - ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL => { - AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE - } - ImageLayout::TRANSFER_SRC_OPTIMAL => AccessFlags::TRANSFER_READ, - ImageLayout::TRANSFER_DST_OPTIMAL => AccessFlags::TRANSFER_WRITE, - // ImageLayout::SHADER_READ_ONLY_OPTIMAL => AccessFlags::SHADER_READ, - ImageLayout::SHADER_READ_ONLY_OPTIMAL => { - AccessFlags::MEMORY_READ | AccessFlags::MEMORY_WRITE - } - _ => AccessFlags::empty(), - }; - - image_memory_barrier.dst_access_mask = match new_layout { - ImageLayout::TRANSFER_DST_OPTIMAL => AccessFlags::TRANSFER_WRITE, - ImageLayout::TRANSFER_SRC_OPTIMAL => AccessFlags::TRANSFER_READ, - ImageLayout::COLOR_ATTACHMENT_OPTIMAL => AccessFlags::COLOR_ATTACHMENT_WRITE, - ImageLayout::GENERAL => AccessFlags::MEMORY_READ, - ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL => { - image_memory_barrier.dst_access_mask | AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE - } - ImageLayout::SHADER_READ_ONLY_OPTIMAL => { - // if image_memory_barrier.src_access_mask.is_empty() - // && old_layout != ImageLayout::UNDEFINED - // { - // image_memory_barrier.src_access_mask = - // AccessFlags::HOST_WRITE | AccessFlags::TRANSFER_WRITE; - // } - // AccessFlags::SHADER_READ | AccessFlags::MEMORY_READ | AccessFlags::MEMORY_WRITE - AccessFlags::MEMORY_READ | AccessFlags::MEMORY_WRITE - } - ImageLayout::PRESENT_SRC_KHR => AccessFlags::MEMORY_WRITE, - _ => AccessFlags::empty(), - }; - - let image_barriers = [image_memory_barrier.build()]; - unsafe { - self.cmd_pipeline_barrier( - cmd_buffer, - src_stage_mask, - dst_stage_mask, - vk::DependencyFlags::empty(), - &[], - &[], - &image_barriers, - ); - } - } - - pub fn set_image_layout( - &self, - cmd_buffer: vk::CommandBuffer, - image: vk::Image, - old_layout: vk::ImageLayout, - new_layout: vk::ImageLayout, - src_stage_mask: vk::PipelineStageFlags, - dst_stage_mask: vk::PipelineStageFlags, - ) { - let subresource_range = vk::ImageSubresourceRange { - aspect_mask: vk::ImageAspectFlags::COLOR, - base_mip_level: 0, - level_count: 1, - base_array_layer: 0, - layer_count: 1, - }; - self.set_image_layout_with_subresource( - cmd_buffer, - image, - old_layout, - new_layout, - subresource_range, - src_stage_mask, - dst_stage_mask, - None, - None, - ); - } - - pub fn set_image_layout_all_commands( - &self, - cmd_buffer: vk::CommandBuffer, - image: vk::Image, - old_layout: vk::ImageLayout, - new_layout: vk::ImageLayout, - ) { - self.set_image_layout( - cmd_buffer, - image, - old_layout, - new_layout, - vk::PipelineStageFlags::ALL_COMMANDS, - vk::PipelineStageFlags::ALL_COMMANDS, - ); - } - - pub fn copy_image( - &self, - command_buffer: vk::CommandBuffer, - src_image: vk::Image, - dst_image: vk::Image, - extent: vk::Extent3D, - ) { - let zero_offset = vk::Offset3D::default(); - let copy_area = vk::ImageCopy::builder() - .src_subresource(vk::ImageSubresourceLayers { - aspect_mask: vk::ImageAspectFlags::COLOR, - mip_level: 0, - base_array_layer: 0, - layer_count: 1, - }) - .src_offset(zero_offset) - .dst_subresource(vk::ImageSubresourceLayers { - aspect_mask: vk::ImageAspectFlags::COLOR, - mip_level: 0, - base_array_layer: 0, - layer_count: 1, - }) - .dst_offset(zero_offset) - .extent(extent) - .build(); - unsafe { - self.cmd_copy_image( - command_buffer, - src_image, - vk::ImageLayout::TRANSFER_SRC_OPTIMAL, - dst_image, - vk::ImageLayout::TRANSFER_DST_OPTIMAL, - &[copy_area], - ) - }; - } - - pub fn blit_image( - &self, - command_buffer: vk::CommandBuffer, - src_image: vk::Image, - src_image_layout: vk::ImageLayout, - dst_image: vk::Image, - dst_image_layout: vk::ImageLayout, - extent: vk::Extent3D, - ) { - self.set_image_layout( - command_buffer, - src_image, - src_image_layout, - vk::ImageLayout::TRANSFER_SRC_OPTIMAL, - vk::PipelineStageFlags::TOP_OF_PIPE, - vk::PipelineStageFlags::TRANSFER, - ); - self.set_image_layout( - command_buffer, - dst_image, - dst_image_layout, - vk::ImageLayout::TRANSFER_DST_OPTIMAL, - vk::PipelineStageFlags::TOP_OF_PIPE, - vk::PipelineStageFlags::TRANSFER, - ); - let offset = [ - vk::Offset3D { x: 0, y: 0, z: 0 }, - vk::Offset3D { - x: extent.width as i32, - y: extent.height as i32, - z: extent.depth as i32, - }, - ]; - let blit_region = [vk::ImageBlit::builder() - .src_subresource(vk::ImageSubresourceLayers { - aspect_mask: vk::ImageAspectFlags::COLOR, - base_array_layer: 0, - layer_count: 1, - mip_level: 0, - }) - .dst_subresource(vk::ImageSubresourceLayers { - aspect_mask: vk::ImageAspectFlags::COLOR, - base_array_layer: 0, - layer_count: 1, - mip_level: 0, - }) - .src_offsets(offset) - .dst_offsets(offset) - .build()]; - - unsafe { - self.device.cmd_blit_image( - command_buffer, - src_image, - vk::ImageLayout::TRANSFER_SRC_OPTIMAL, - dst_image, - vk::ImageLayout::TRANSFER_DST_OPTIMAL, - blit_region.as_ref(), - vk::Filter::NEAREST, - ) - }; - self.set_image_layout( - command_buffer, - dst_image, - vk::ImageLayout::TRANSFER_DST_OPTIMAL, - dst_image_layout, - vk::PipelineStageFlags::TRANSFER, - vk::PipelineStageFlags::ALL_GRAPHICS, - ); - self.set_image_layout( - command_buffer, - src_image, - vk::ImageLayout::TRANSFER_SRC_OPTIMAL, - src_image_layout, - vk::PipelineStageFlags::TRANSFER, - vk::PipelineStageFlags::ALL_GRAPHICS, - ); - } - - pub fn create_vk_buffer_from_slice( - &self, - usage_flags: vk::BufferUsageFlags, - memory_prop_flags: vk::MemoryPropertyFlags, - data: &[T], - ) -> VkResult> { - let size = (data.len() * std::mem::size_of::()) as u64; - let mut buffer = self.create_vk_buffer(usage_flags, memory_prop_flags, size)?; - buffer.mapped = { - let tmp = unsafe { - std::slice::from_raw_parts_mut::( - self.map_memory(buffer.memory, 0, size, vk::MemoryMapFlags::empty())? as _, - data.len(), - ) - }; - unsafe { std::ptr::copy_nonoverlapping(data.as_ptr(), tmp.as_mut_ptr(), data.len()) }; - Some(tmp) - }; - Ok(buffer) - } - - pub fn create_vk_buffer( - &self, - usage_flags: vk::BufferUsageFlags, - memory_prop_flags: vk::MemoryPropertyFlags, - size: vk::DeviceSize, - ) -> VkResult> { - let buffer_create_info = vk::BufferCreateInfo::builder() - .size(size) - .usage(usage_flags); - let buffer = unsafe { self.create_buffer(&buffer_create_info, None) }?; - - let memory_reqs = unsafe { self.get_buffer_memory_requirements(buffer) }; - - let memory_type_index = - utils::find_memory_type_index(&memory_reqs, &self.memory_properties, memory_prop_flags) - .unwrap(); - let mut mem_alloc_flags = vk::MemoryAllocateFlagsInfoKHR::default(); - let alloc_info = vk::MemoryAllocateInfo::builder() - .allocation_size(memory_reqs.size) - .memory_type_index(memory_type_index) - .push_next({ - if usage_flags.contains(vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS) { - mem_alloc_flags.flags = vk::MemoryAllocateFlagsKHR::DEVICE_ADDRESS_KHR; - } - &mut mem_alloc_flags - }); - let buffer_memory = unsafe { self.device.allocate_memory(&alloc_info, None) }?; - - let descriptor = vk::DescriptorBufferInfo::builder() - .offset(0) - .buffer(buffer) - .range(vk::WHOLE_SIZE) - .build(); - - unsafe { self.bind_buffer_memory(buffer, buffer_memory, 0) }?; - - Ok(VkBuffer { - buffer, - memory: buffer_memory, - mem_reqs: memory_reqs, - descriptor, - mapped: None, - }) - } - - pub fn name_semaphore(&self, object: vk::Semaphore, name: &str) -> VkResult<()> { - self.instance - .name_object(self, object, vk::ObjectType::SEMAPHORE, name) - } - pub fn name_image(&self, object: vk::Image, name: &str) -> VkResult<()> { - self.instance - .name_object(self, object, vk::ObjectType::IMAGE, name) - } - pub fn name_queue(&self, object: vk::Queue, name: &str) -> VkResult<()> { - self.instance - .name_object(self, object, vk::ObjectType::QUEUE, name) - } -} - -pub struct VkBuffer<'a, T> { - buffer: vk::Buffer, - memory: vk::DeviceMemory, - mem_reqs: vk::MemoryRequirements, - descriptor: vk::DescriptorBufferInfo, - mapped: Option<&'a mut [T]>, -} - -impl VkBuffer<'_, T> { - pub fn map(&mut self, device: &VkDevice) -> VkResult<()> { - self.mapped = { - let size = self.mem_reqs.size; - let tmp = unsafe { - std::slice::from_raw_parts_mut::( - device.map_memory(self.memory, 0, size, vk::MemoryMapFlags::empty())? as _, - size as usize, - ) - }; - Some(tmp) - }; - Ok(()) - } -} - -impl<'a, T> VkBuffer<'a, T> { - fn destroy(&mut self, device: &VkDevice) { - unsafe { - device.free_memory(self.memory, None); - device.destroy_buffer(self.buffer, None); - } - } -} - -impl Drop for RawDevice { - fn drop(&mut self) { - unsafe { self.device.destroy_device(None) }; - } -} diff --git a/pilka_ash/src/pvk/image.rs b/pilka_ash/src/pvk/image.rs deleted file mode 100644 index 64a08c6..0000000 --- a/pilka_ash/src/pvk/image.rs +++ /dev/null @@ -1,8 +0,0 @@ -use ash::vk; - -pub struct VkImage { - image: vk::Image, - image_memory: vk::DeviceMemory, - image_view: vk::ImageView, - extent: vk::Extent2D, -} diff --git a/pilka_ash/src/pvk/instance.rs b/pilka_ash/src/pvk/instance.rs deleted file mode 100644 index f4aae34..0000000 --- a/pilka_ash/src/pvk/instance.rs +++ /dev/null @@ -1,394 +0,0 @@ -use super::{ - device::{RawDevice, VkDevice, VkDeviceProperties}, - surface::VkSurface, -}; -use ash::{ - extensions::{ - ext::DebugUtils, - khr::{Surface, Swapchain}, - }, - prelude::VkResult, - vk::{self, Handle}, -}; - -use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle}; - -use std::{ffi::CStr, ops::Deref, os::raw::c_char, sync::Arc}; - -#[allow(unused_macros)] -macro_rules! offset_of { - ($base:path, $field:ident) => {{ - #[allow(unused_unsafe)] - unsafe { - let b: $base = std::mem::zeroed(); - (&b.$field as *const _ as isize) - (&b as *const _ as isize) - } - }}; -} - -/// The entry point for vulkan application. -pub struct VkInstance { - #[cfg(not(target_os = "macos"))] - pub entry: ash::Entry, - #[cfg(target_os = "macos")] - pub entry: ash_molten::Entry, - pub instance: ash::Instance, - validation_layers: Vec<*const i8>, - _dbg_loader: ash::extensions::ext::DebugUtils, - _dbg_callbk: vk::DebugUtilsMessengerEXT, -} - -impl VkInstance { - pub fn new( - validation_layers: &[&str], - extention_names: &[*const c_char], - ) -> Result, Box> { - let entry = unsafe { ash::Entry::load()? }; - - #[cfg(target_os = "macos")] - let entry = ash_molten::MoltenEntry::load()?; - - // Enumerate available vulkan API version and set 1.0.0 otherwise. - let version = match entry.try_enumerate_instance_version()? { - Some(version) => version, - None => vk::make_api_version(1, 0, 0, 0), - }; - - let available_layers = entry.enumerate_instance_layer_properties()?; - let validation_layers = validation_layers - .iter() - .map(|s| unsafe { CStr::from_ptr(s.as_ptr() as *const i8) }) - .filter_map(|lyr| { - available_layers - .iter() - .find(|x| unsafe { CStr::from_ptr(x.layer_name.as_ptr()) } == lyr) - .map(|_| lyr.as_ptr()) - .or_else(|| { - eprintln!( - "Unable to find layer: {}, have you installed the Vulkan SDK?", - lyr.to_string_lossy() - ); - None - }) - }) - .collect::>(); - - let available_exts = entry.enumerate_instance_extension_properties(None)?; - let extensions = [DebugUtils::name().as_ptr()] - .iter() - .chain(extention_names) - .map(|&s| unsafe { CStr::from_ptr(s) }) - .filter_map(|ext| { - available_exts - .iter() - .find(|x| unsafe { CStr::from_ptr(x.extension_name.as_ptr()) } == ext) - .map(|_| ext.as_ptr()) - .or_else(|| { - println!( - "Unable to find extension: {}, have you installed the Vulkan SDK?", - ext.to_string_lossy() - ); - None - }) - }) - .collect::>(); - - let app_info = vk::ApplicationInfo::builder() - .application_name(unsafe { CStr::from_ptr("Pilka".as_ptr() as *const i8) }) - .engine_name(unsafe { CStr::from_ptr("Pilka Engine".as_ptr() as *const i8) }) - .engine_version(vk::make_api_version(1, 1, 0, 0)) - .api_version(version); - - // let mut additional_instance_features = vk::ValidationFeaturesEXT::builder() - // .enabled_validation_features(&[vk::ValidationFeatureEnableEXT::BEST_PRACTICES]); - - let instance_info = vk::InstanceCreateInfo::builder() - // .push_next(&mut additional_instance_features) - .application_info(&app_info) - .enabled_layer_names(&validation_layers) - .enabled_extension_names(&extensions); - - let instance = unsafe { entry.create_instance(&instance_info, None) }?; - - let (_dbg_loader, _dbg_callbk) = { - let dbg_info = vk::DebugUtilsMessengerCreateInfoEXT::builder() - .message_severity( - vk::DebugUtilsMessageSeverityFlagsEXT::ERROR - // | vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE - // | vk::DebugUtilsMessageSeverityFlagsEXT::INFO - | vk::DebugUtilsMessageSeverityFlagsEXT::WARNING, - ) - .message_type( - vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE - | vk::DebugUtilsMessageTypeFlagsEXT::GENERAL - | vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE, - ) - .pfn_user_callback(Some(vulkan_debug_callback)); - let dbg_loader = DebugUtils::new(&entry, &instance); - let dbg_callbk = unsafe { dbg_loader.create_debug_utils_messenger(&dbg_info, None)? }; - (dbg_loader, dbg_callbk) - }; - - Ok(Arc::new(Self { - entry, - instance, - validation_layers, - _dbg_loader, - _dbg_callbk, - })) - } - - /// Make surface and surface loader. - pub fn create_surface( - &self, - window: &W, - ) -> VkResult { - let surface = unsafe { - ash_window::create_surface( - &self.entry, - &self.instance, - window.raw_display_handle(), - window.raw_window_handle(), - None, - ) - }?; - let surface_loader = Surface::new(&self.entry, &self.instance); - - Ok(VkSurface { - surface, - surface_loader, - }) - } - - pub fn create_device_and_queues( - self: Arc, - surface: Option<&VkSurface>, - ) -> VkResult<(VkDevice, VkDeviceProperties, VkQueues)> { - // Acuire all availble device for this machine. - let physical_devices = unsafe { self.enumerate_physical_devices() }?; - - // Choose physical device assuming that we want to choose discrete GPU. - let (physical_device, device_properties, device_features) = { - let mut chosen = Err(vk::Result::ERROR_INITIALIZATION_FAILED); - for p in physical_devices { - let properties = unsafe { self.get_physical_device_properties(p) }; - let features = unsafe { self.get_physical_device_features(p) }; - if properties.device_type == vk::PhysicalDeviceType::DISCRETE_GPU { - chosen = Ok((p, properties, features)); - } - } - chosen - }?; - let device_extension_name_pointers = match surface { - Some(_) => vec![Swapchain::name().as_ptr()], - None => vec![], - }; - let memory = unsafe { self.get_physical_device_memory_properties(physical_device) }; - - let queue_families = self.create_queue_families(physical_device, surface)?; - - let graphics_queue_index = queue_families.graphics_q_index.unwrap_or(0); - let transfer_queue_index = queue_families.transfer_q_index.unwrap_or(0); - let compute_queue_index = queue_families.compute_q_index.unwrap_or(0); - - let priorities = [1.0f32]; - - // TODO: Don't allocate for such a thing - let mut queue_infos = vec![ - vk::DeviceQueueCreateInfo::builder() - .queue_family_index(graphics_queue_index) - .queue_priorities(&priorities) - .build(), - vk::DeviceQueueCreateInfo::builder() - .queue_family_index(transfer_queue_index) - .queue_priorities(&priorities) - .build(), - ]; - if compute_queue_index != graphics_queue_index { - queue_infos.push( - vk::DeviceQueueCreateInfo::builder() - .queue_family_index(compute_queue_index) - .queue_priorities(&priorities) - .build(), - ); - } - - let device_info = vk::DeviceCreateInfo::builder() - .enabled_layer_names(&self.validation_layers) - .enabled_extension_names(&device_extension_name_pointers) - .enabled_features(&device_features) - .queue_create_infos(&queue_infos); - - let device = unsafe { self.create_device(physical_device, &device_info, None) }?; - let graphics_queue = unsafe { device.get_device_queue(graphics_queue_index, 0) }; - let transfer_queue = unsafe { device.get_device_queue(transfer_queue_index, 0) }; - let compute_queue = unsafe { device.get_device_queue(compute_queue_index, 0) }; - - let device = Arc::new(RawDevice::new(device)); - let memory_properties = - unsafe { self.get_physical_device_memory_properties(physical_device) }; - - Ok(( - VkDevice { - instance: self.clone(), - device, - physical_device, - memory_properties, - }, - VkDeviceProperties { - memory, - properties: device_properties, - features: device_features, - }, - VkQueues { - graphics_queue: VkQueue::new(graphics_queue, graphics_queue_index), - transfer_queue: VkQueue::new(transfer_queue, transfer_queue_index), - compute_queue: VkQueue::new(compute_queue, compute_queue_index), - }, - )) - } - - fn create_queue_families( - &self, - physical_device: vk::PhysicalDevice, - surface: Option<&VkSurface>, - ) -> Result { - // Choose graphics and transfer queue families. - let queuefamilyproperties = - unsafe { self.get_physical_device_queue_family_properties(physical_device) }; - let mut found_graphics_q_index = None; - let mut found_transfer_q_index = None; - let mut found_compute_q_index = None; - for (index, qfam) in queuefamilyproperties.iter().enumerate() { - if qfam.queue_count > 0 - && qfam.queue_flags.contains(vk::QueueFlags::GRAPHICS) - && if let Some(surface) = surface { - unsafe { - surface.surface_loader.get_physical_device_surface_support( - physical_device, - index as u32, - surface.surface, - ) - }? - } else { - true - } - { - found_graphics_q_index = Some(index as u32); - } - - if qfam.queue_count > 0 - && qfam.queue_flags.contains(vk::QueueFlags::TRANSFER) - && (found_transfer_q_index.is_none() - || !qfam.queue_flags.contains(vk::QueueFlags::GRAPHICS)) - { - found_transfer_q_index = Some(index as u32); - } - - // TODO(#8): Make search for compute queue smarter. - if qfam.queue_count > 0 && qfam.queue_flags.contains(vk::QueueFlags::COMPUTE) { - let index = Some(index as u32); - match (found_compute_q_index, qfam.queue_flags) { - (_, vk::QueueFlags::COMPUTE) => found_compute_q_index = index, - (None, _) => found_compute_q_index = index, - _ => {} - } - } - } - - Ok(QueueFamilies { - graphics_q_index: found_graphics_q_index, - transfer_q_index: found_transfer_q_index, - compute_q_index: found_compute_q_index, - }) - } - - pub fn create_swapchain_loader(&self, device: &VkDevice) -> Swapchain { - Swapchain::new(&self.instance, device.device.as_ref().deref()) - } - - pub fn name_object( - &self, - device: &VkDevice, - object: impl Handle, - object_type: vk::ObjectType, - name: &str, - ) -> VkResult<()> { - let name = std::ffi::CString::new(name).unwrap(); - let name_info = vk::DebugUtilsObjectNameInfoEXT::builder() - .object_type(object_type) - .object_name(name.as_c_str()) - .object_handle(object.as_raw()); - unsafe { - self._dbg_loader - .debug_utils_set_object_name(device.handle(), &name_info) - } - } -} - -impl std::ops::Deref for VkInstance { - type Target = ash::Instance; - - fn deref(&self) -> &Self::Target { - &self.instance - } -} - -impl std::ops::DerefMut for VkInstance { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.instance - } -} - -impl Drop for VkInstance { - fn drop(&mut self) { - unsafe { - self._dbg_loader - .destroy_debug_utils_messenger(self._dbg_callbk, None) - }; - unsafe { self.instance.destroy_instance(None) }; - } -} - -unsafe extern "system" fn vulkan_debug_callback( - message_severity: vk::DebugUtilsMessageSeverityFlagsEXT, - message_type: vk::DebugUtilsMessageTypeFlagsEXT, - p_callback_data: *const vk::DebugUtilsMessengerCallbackDataEXT, - _user_data: *mut std::os::raw::c_void, -) -> vk::Bool32 { - let callback_data = &unsafe { *p_callback_data }; - let message = unsafe { CStr::from_ptr(callback_data.p_message) }.to_string_lossy(); - - println!( - "{:?}:\n{:?} : {}\n", - message_severity, message_type, message, - ); - - vk::FALSE -} - -#[derive(Debug)] -pub struct VkQueue { - pub queue: vk::Queue, - pub index: u32, -} - -impl VkQueue { - fn new(queue: vk::Queue, index: u32) -> Self { - Self { queue, index } - } -} - -#[derive(Debug)] -pub struct VkQueues { - pub graphics_queue: VkQueue, - pub transfer_queue: VkQueue, - pub compute_queue: VkQueue, -} - -#[derive(Copy, Clone)] -struct QueueFamilies { - graphics_q_index: Option, - transfer_q_index: Option, - compute_q_index: Option, -} diff --git a/pilka_ash/src/pvk/mod.rs b/pilka_ash/src/pvk/mod.rs deleted file mode 100644 index b8f4e90..0000000 --- a/pilka_ash/src/pvk/mod.rs +++ /dev/null @@ -1,23 +0,0 @@ -#![allow(dead_code)] - -mod command_pool; -mod device; -mod image; -mod instance; -mod renderpass_and_pipeline; -mod surface; -mod swapchain; -mod texture; -pub mod utils; - -pub use command_pool::VkCommandPool; -pub use device::{VkDevice, VkDeviceProperties}; -pub use instance::{VkInstance, VkQueue, VkQueues}; -pub use renderpass_and_pipeline::{ - Pipeline, PipelineDescriptor, VkComputePipeline, VkGraphicsPipeline, VkRenderPass, -}; - -pub use surface::VkSurface; -pub use swapchain::VkSwapchain; - -pub use raw_window_handle::HasRawWindowHandle; diff --git a/pilka_ash/src/pvk/renderpass_and_pipeline.rs b/pilka_ash/src/pvk/renderpass_and_pipeline.rs deleted file mode 100644 index 61621c1..0000000 --- a/pilka_ash/src/pvk/renderpass_and_pipeline.rs +++ /dev/null @@ -1,320 +0,0 @@ -use crate::VkDevice; - -use super::device::RawDevice; -use ash::{ - prelude::VkResult, - vk::{self, ShaderModule}, -}; -use std::{ffi::CString, sync::Arc}; - -use super::instance::VkQueues; - -#[derive(Debug)] -pub enum Pipeline { - Graphics(VkGraphicsPipeline), - Compute(VkComputePipeline), -} - -pub struct VkRenderPass { - pub render_pass: vk::RenderPass, - pub device: Arc, -} - -impl std::ops::Deref for VkRenderPass { - type Target = vk::RenderPass; - - fn deref(&self) -> &Self::Target { - &self.render_pass - } -} - -impl std::ops::DerefMut for VkRenderPass { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.render_pass - } -} - -impl Drop for VkRenderPass { - fn drop(&mut self) { - unsafe { self.device.destroy_render_pass(self.render_pass, None) }; - } -} - -pub struct PipelineDescriptor { - pub color_blend_attachments: Box<[vk::PipelineColorBlendAttachmentState]>, - pub dynamic_state_info: vk::PipelineDynamicStateCreateInfo, - pub dynamic_state: Box<[vk::DynamicState]>, - pub vertex_module: ShaderModule, - pub vertex_entry_point: CString, - pub fragment_module: ShaderModule, - pub fragment_entry_point: CString, - pub vertex_input: vk::PipelineVertexInputStateCreateInfo, - pub input_assembly: vk::PipelineInputAssemblyStateCreateInfo, - pub rasterization: vk::PipelineRasterizationStateCreateInfo, - pub multisample: vk::PipelineMultisampleStateCreateInfo, - pub depth_stencil: vk::PipelineDepthStencilStateCreateInfo, - pub color_blend: vk::PipelineColorBlendStateCreateInfo, -} - -impl PipelineDescriptor { - pub fn new( - vertex_module: ShaderModule, - vertex_entry_point: CString, - fragment_module: ShaderModule, - fragment_entry_point: CString, - ) -> Self { - let noop_stencil_state = vk::StencilOpState { - fail_op: vk::StencilOp::KEEP, - pass_op: vk::StencilOp::KEEP, - depth_fail_op: vk::StencilOp::KEEP, - compare_op: vk::CompareOp::ALWAYS, - ..Default::default() - }; - let depth_stencil = vk::PipelineDepthStencilStateCreateInfo { - depth_test_enable: 0, - depth_write_enable: 0, - depth_compare_op: vk::CompareOp::ALWAYS, - front: noop_stencil_state, - back: noop_stencil_state, - max_depth_bounds: 1.0, - ..Default::default() - }; - - let vertex_input = vk::PipelineVertexInputStateCreateInfo { - vertex_attribute_description_count: 0, - vertex_binding_description_count: 0, - // vertex_attribute_description_count: vertex_input_attribute_descriptions.len() - // as u32, - // p_vertex_attribute_descriptions: vertex_input_attribute_descriptions.as_ptr(), - // vertex_binding_description_count: vertex_input_binding_descriptions.len() as u32, - // p_vertex_binding_descriptions: vertex_input_binding_descriptions.as_ptr(), - ..Default::default() - }; - - let input_assembly = vk::PipelineInputAssemblyStateCreateInfo { - topology: vk::PrimitiveTopology::TRIANGLE_LIST, - ..Default::default() - }; - - let rasterization = vk::PipelineRasterizationStateCreateInfo { - front_face: vk::FrontFace::COUNTER_CLOCKWISE, - line_width: 1.0, - polygon_mode: vk::PolygonMode::FILL, - cull_mode: vk::CullModeFlags::BACK, - ..Default::default() - }; - let multisample = vk::PipelineMultisampleStateCreateInfo { - rasterization_samples: vk::SampleCountFlags::TYPE_1, - ..Default::default() - }; - - let color_blend_attachments = Box::new([vk::PipelineColorBlendAttachmentState { - blend_enable: 0, - src_color_blend_factor: vk::BlendFactor::SRC_COLOR, - dst_color_blend_factor: vk::BlendFactor::ONE_MINUS_DST_COLOR, - color_blend_op: vk::BlendOp::ADD, - src_alpha_blend_factor: vk::BlendFactor::ZERO, - dst_alpha_blend_factor: vk::BlendFactor::ZERO, - alpha_blend_op: vk::BlendOp::ADD, - color_write_mask: vk::ColorComponentFlags::R - | vk::ColorComponentFlags::G - | vk::ColorComponentFlags::B - | vk::ColorComponentFlags::A, - }]); - let color_blend = vk::PipelineColorBlendStateCreateInfo::builder() - .logic_op(vk::LogicOp::CLEAR) - .attachments(color_blend_attachments.as_ref()) - .build(); - - let dynamic_state = Box::new([vk::DynamicState::VIEWPORT, vk::DynamicState::SCISSOR]); - let dynamic_state_info = vk::PipelineDynamicStateCreateInfo::builder() - .dynamic_states(dynamic_state.as_ref()) - .build(); - - Self { - color_blend_attachments, - dynamic_state_info, - dynamic_state, - vertex_module, - vertex_entry_point, - fragment_module, - fragment_entry_point, - vertex_input, - input_assembly, - rasterization, - multisample, - depth_stencil, - color_blend, - } - } -} - -#[derive(Debug)] -pub struct VkGraphicsPipeline { - pub pipeline: vk::Pipeline, - pub pipeline_layout: vk::PipelineLayout, - pub dynamic_state: Box<[vk::DynamicState]>, - pub descriptor_set_layouts: Vec, - pub device: Arc, -} - -impl VkGraphicsPipeline { - #[allow(clippy::too_many_arguments)] - pub fn new( - pipeline_cache: vk::PipelineCache, - pipeline_layout: vk::PipelineLayout, - descriptor_set_layouts: Vec, - desc: PipelineDescriptor, - render_pass: &VkRenderPass, - device: &VkDevice, - ) -> VkResult { - let viewport = vk::PipelineViewportStateCreateInfo::builder() - .viewports(&[vk::Viewport::default()]) - .scissors(&[vk::Rect2D::default()]) - .build(); - - let vertex_stage = vk::PipelineShaderStageCreateInfo::builder() - .module(desc.vertex_module) - .stage(vk::ShaderStageFlags::VERTEX) - .name(desc.vertex_entry_point.as_c_str()) - .build(); - let fragment_stage = vk::PipelineShaderStageCreateInfo::builder() - .module(desc.fragment_module) - .stage(vk::ShaderStageFlags::FRAGMENT) - .name(desc.fragment_entry_point.as_c_str()) - .build(); - let stages = [vertex_stage, fragment_stage]; - - let pipeline_info = vk::GraphicsPipelineCreateInfo::builder() - .stages(&stages) - .vertex_input_state(&desc.vertex_input) - .input_assembly_state(&desc.input_assembly) - .rasterization_state(&desc.rasterization) - .multisample_state(&desc.multisample) - .depth_stencil_state(&desc.depth_stencil) - .color_blend_state(&desc.color_blend) - .dynamic_state(&desc.dynamic_state_info) - .viewport_state(&viewport) - .layout(pipeline_layout) - .render_pass(render_pass.render_pass); - - let pipeline = unsafe { - device.create_graphics_pipelines(pipeline_cache, &[pipeline_info.build()], None) - } - .expect("Unable to create graphics pipeline") - .pop() - .unwrap(); - - Ok(VkGraphicsPipeline { - pipeline, - pipeline_layout, - dynamic_state: desc.dynamic_state, - descriptor_set_layouts, - device: device.device.clone(), - }) - } -} - -impl Drop for VkGraphicsPipeline { - fn drop(&mut self) { - unsafe { - for desc_set_layout in &self.descriptor_set_layouts { - self.device - .destroy_descriptor_set_layout(*desc_set_layout, None); - } - - self.device.destroy_pipeline(self.pipeline, None); - - self.device - .destroy_pipeline_layout(self.pipeline_layout, None); - } - } -} - -#[derive(Debug)] -pub struct VkComputePipeline { - pub pipeline: vk::Pipeline, - pub pipeline_layout: vk::PipelineLayout, - pub descriptor_set_layouts: Vec, - pub command_pool: vk::CommandPool, - pub command_buffer: vk::CommandBuffer, - pub semaphore: vk::Semaphore, - // pub cs_info: ShaderInfo, - pub device: Arc, -} - -impl VkComputePipeline { - pub fn new( - device: &VkDevice, - queues: &VkQueues, - pipeline_layout: vk::PipelineLayout, - descriptor_set_layouts: Vec, - shader_stage: vk::PipelineShaderStageCreateInfo, - ) -> VkResult { - let pipeline_info = vk::ComputePipelineCreateInfo::builder() - .stage(shader_stage) - .layout(pipeline_layout); - - let pipeline = unsafe { - device.create_compute_pipelines( - vk::PipelineCache::null(), - &[pipeline_info.build()], - None, - ) - } - .expect("Unable to create graphics pipeline") - .pop() - .unwrap(); - - let command_pool_create_info = vk::CommandPoolCreateInfo::builder() - .flags(vk::CommandPoolCreateFlags::RESET_COMMAND_BUFFER) - .queue_family_index(queues.compute_queue.index); - let command_pool = unsafe { device.create_command_pool(&command_pool_create_info, None) }?; - - let command_buffer_create_info = vk::CommandBufferAllocateInfo::builder() - .command_buffer_count(1) - .command_pool(command_pool) - .level(vk::CommandBufferLevel::PRIMARY); - let command_buffer = - unsafe { device.allocate_command_buffers(&command_buffer_create_info) }?[0]; - - let semaphore = device.create_semaphore()?; - device.name_semaphore(semaphore, "Compute Semaphore")?; - - // let signal_semaphores = [semaphore]; - // let submits = [vk::SubmitInfo::builder() - // .signal_semaphores(&signal_semaphores) - // .build()]; - // unsafe { device.queue_submit(queues.compute_queue.queue, &submits, vk::Fence::null()) }?; - // unsafe { device.queue_wait_idle(queues.compute_queue.queue) }?; - - Ok(Self { - pipeline, - pipeline_layout, - descriptor_set_layouts, - command_pool, - command_buffer, - semaphore, - // cs_info, - device: device.device.clone(), - }) - } -} - -impl Drop for VkComputePipeline { - fn drop(&mut self) { - unsafe { - self.device.destroy_semaphore(self.semaphore, None); - self.device.destroy_command_pool(self.command_pool, None); - for desc_set_layout in &self.descriptor_set_layouts { - self.device - .destroy_descriptor_set_layout(*desc_set_layout, None); - } - - self.device.destroy_pipeline(self.pipeline, None); - - self.device - .destroy_pipeline_layout(self.pipeline_layout, None); - } - } -} diff --git a/pilka_ash/src/pvk/surface.rs b/pilka_ash/src/pvk/surface.rs deleted file mode 100644 index a34681b..0000000 --- a/pilka_ash/src/pvk/surface.rs +++ /dev/null @@ -1,69 +0,0 @@ -use super::device::VkDevice; -use ash::{extensions::khr::Surface, prelude::VkResult, vk}; - -pub struct VkSurface { - pub surface: vk::SurfaceKHR, - pub surface_loader: Surface, -} - -impl VkSurface { - pub fn get_capabilities(&self, device: &VkDevice) -> VkResult { - unsafe { - self.surface_loader - .get_physical_device_surface_capabilities(device.physical_device, self.surface) - } - } - - pub fn get_present_modes(&self, device: &VkDevice) -> VkResult> { - unsafe { - self.surface_loader - .get_physical_device_surface_present_modes(device.physical_device, self.surface) - } - } - - pub fn get_formats(&self, device: &VkDevice) -> VkResult> { - unsafe { - self.surface_loader - .get_physical_device_surface_formats(device.physical_device, self.surface) - } - } - - pub fn get_physical_device_surface_support( - &self, - device: &VkDevice, - queue_family_index: usize, - ) -> VkResult { - unsafe { - self.surface_loader.get_physical_device_surface_support( - device.physical_device, - queue_family_index as u32, - self.surface, - ) - } - } - - pub fn resolution(&self, device: &VkDevice) -> VkResult { - Ok(self.get_capabilities(device)?.current_extent) - // match surface_capabilities.current_extent.width { - // std::u32::MAX => { - // let window_inner = self.window.inner_size(); - // vk::Extent2D { - // width: window_inner.width, - // height: window_inner.height, - // } - // } - // _ => surface_capabilities.current_extent, - // } - } - - pub fn resolution_slice(&self, device: &VkDevice) -> VkResult<[f32; 2]> { - let vk::Extent2D { width, height } = self.resolution(device)?; - Ok([width as f32, height as f32]) - } -} - -impl Drop for VkSurface { - fn drop(&mut self) { - unsafe { self.surface_loader.destroy_surface(self.surface, None) }; - } -} diff --git a/pilka_ash/src/pvk/swapchain.rs b/pilka_ash/src/pvk/swapchain.rs deleted file mode 100644 index 67de181..0000000 --- a/pilka_ash/src/pvk/swapchain.rs +++ /dev/null @@ -1,129 +0,0 @@ -use super::{ - device::{RawDevice, VkDevice}, - renderpass_and_pipeline::VkRenderPass, -}; -use ash::{extensions::khr::Swapchain, prelude::VkResult, vk}; -use std::sync::Arc; - -pub struct VkSwapchain { - pub swapchain: vk::SwapchainKHR, - pub swapchain_loader: Swapchain, - pub images: Vec, - pub image_views: Vec, - pub format: vk::Format, - pub info: vk::SwapchainCreateInfoKHR, - pub device: Arc, -} - -impl VkSwapchain { - pub fn format(&self) -> vk::Format { - self.format - } - - pub fn recreate_swapchain( - &mut self, - (width, height): (u32, u32), - device: &VkDevice, - ) -> VkResult<()> { - self.info.image_extent = vk::Extent2D { width, height }; - // I have to destroy old swapchaing to be able switch between - // different backends - // - // self.info.old_swapchain = self.swapchain; - unsafe { - self.swapchain_loader - .destroy_swapchain(self.swapchain, None); - } - for &image_view in self.image_views.iter() { - unsafe { self.device.destroy_image_view(image_view, None) }; - } - - self.swapchain = unsafe { self.swapchain_loader.create_swapchain(&self.info, None) }?; - self.images = unsafe { self.swapchain_loader.get_swapchain_images(self.swapchain)? }; - self.image_views = Self::create_image_views(&self.images, self.info.image_format, device)?; - - Ok(()) - } - - pub fn create_image_views( - images: &[vk::Image], - format: vk::Format, - device: &VkDevice, - ) -> VkResult> { - images - .iter() - .map(|&image| { - let create_view_info = vk::ImageViewCreateInfo::builder() - .view_type(vk::ImageViewType::TYPE_2D) - .format(format) - .components(vk::ComponentMapping { - // Why not BGRA? - r: vk::ComponentSwizzle::R, - g: vk::ComponentSwizzle::G, - b: vk::ComponentSwizzle::B, - a: vk::ComponentSwizzle::A, - }) - .subresource_range(vk::ImageSubresourceRange { - aspect_mask: vk::ImageAspectFlags::COLOR, - base_mip_level: 0, - level_count: 1, - base_array_layer: 0, - layer_count: 1, - }) - .image(image); - unsafe { device.create_image_view(&create_view_info, None) } - }) - .collect::>>() - } - - pub fn create_framebuffers( - &self, - (width, height): (u32, u32), - render_pass: &VkRenderPass, - device: &VkDevice, - ) -> VkResult> { - self.image_views - .iter() - .map(|&present_image_view| { - Self::create_framebuffer( - &[present_image_view], - (width, height), - render_pass, - device, - ) - }) - .collect() - } - - pub fn create_framebuffer( - image_views: &[vk::ImageView], - (width, height): (u32, u32), - render_pass: &VkRenderPass, - device: &VkDevice, - ) -> VkResult { - let framebuffer_attachments = image_views; - unsafe { - device.create_framebuffer( - &vk::FramebufferCreateInfo::builder() - .render_pass(render_pass.render_pass) - .attachments(framebuffer_attachments) - .width(width) - .height(height) - .layers(1), - None, - ) - } - } -} - -impl Drop for VkSwapchain { - fn drop(&mut self) { - unsafe { - for &image_view in self.image_views.iter() { - self.device.destroy_image_view(image_view, None); - } - self.swapchain_loader - .destroy_swapchain(self.swapchain, None) - }; - } -} diff --git a/pilka_ash/src/pvk/texture.rs b/pilka_ash/src/pvk/texture.rs deleted file mode 100644 index 98718af..0000000 --- a/pilka_ash/src/pvk/texture.rs +++ /dev/null @@ -1,411 +0,0 @@ -use super::{ - device::{RawDevice, VkDevice}, - instance::{VkInstance, VkQueues}, -}; -use ash::vk; - -use ash::prelude::VkResult; -use ktx::{Ktx, KtxInfo}; -use std::path::Path; -use std::sync::Arc; - -pub struct VkTexture { - device: Arc, - image: vk::Image, - view: vk::ImageView, - image_layout: vk::ImageLayout, - memory: vk::DeviceMemory, - width: u32, - height: u32, - mip_levels: u32, - layer_count: u32, - descriptor: vk::DescriptorImageInfo, - sampler: vk::Sampler, -} - -impl VkTexture { - #[allow(clippy::too_many_arguments)] - pub fn from_ktx>( - filename: P, - instance: &VkInstance, - device: &VkDevice, - format: vk::Format, - command_pool: &vk::CommandPool, - copy_queue: &vk::Queue, - image_usage_flags: vk::ImageUsageFlags, - image_layout: vk::ImageLayout, - ) -> Result> { - let ktx_image = Ktx::new(std::fs::read(filename)?); - - let ktx_image_width = ktx_image.pixel_width(); - let ktx_image_height = ktx_image.pixel_height(); - let mip_levels = ktx_image.mipmap_levels(); - - let ktx_texture = ktx_image.textures().flatten().copied().collect::>(); - let ktx_texture_size = ktx_texture.len() as u64; - let ktx_offsets: Vec = ktx_image - .textures() - .map(|tex| tex.len()) - .scan(0, |state, x| { - *state += x; - Some(*state as _) - }) - .collect(); - - let memory_properties = - unsafe { instance.get_physical_device_memory_properties(device.physical_device) }; - - let cmd_buffer_allocate_info = vk::CommandBufferAllocateInfo::builder() - .command_pool(*command_pool) - .level(vk::CommandBufferLevel::PRIMARY) - .command_buffer_count(1); - let copy_cmd = unsafe { device.allocate_command_buffers(&cmd_buffer_allocate_info) }?[0]; - - // Flags? - let begin_info = vk::CommandBufferBeginInfo::builder(); - unsafe { device.begin_command_buffer(copy_cmd, &begin_info) }?; - - let buffer_create_info = vk::BufferCreateInfo::builder() - .size(ktx_texture_size) - .usage(vk::BufferUsageFlags::TRANSFER_SRC) - .sharing_mode(vk::SharingMode::EXCLUSIVE); - let staging_buffer = unsafe { device.create_buffer(&buffer_create_info, None) }?; - - let staging_buffer_mem_reqs = - unsafe { device.get_buffer_memory_requirements(staging_buffer) }; - - let staging_buffer_memory = device.alloc_memory( - &memory_properties, - staging_buffer_mem_reqs, - vk::MemoryPropertyFlags::HOST_VISIBLE - | vk::MemoryPropertyFlags::HOST_COHERENT - | vk::MemoryPropertyFlags::HOST_CACHED, - )?; - unsafe { device.bind_buffer_memory(staging_buffer, staging_buffer_memory, 0) }?; - - let data = unsafe { - std::slice::from_raw_parts_mut( - device.map_memory( - staging_buffer_memory, - 0, - staging_buffer_mem_reqs.size, - vk::MemoryMapFlags::empty(), - )? as *mut u8, - staging_buffer_mem_reqs.size as usize, - ) - }; - data.copy_from_slice(&ktx_texture); - unsafe { device.unmap_memory(staging_buffer_memory) }; - - let buffer_copy_regions: Vec<_> = (0..mip_levels) - .map(|i| { - vk::BufferImageCopy::builder() - .image_subresource( - vk::ImageSubresourceLayers::builder() - .aspect_mask(vk::ImageAspectFlags::COLOR) - .mip_level(i) - .base_array_layer(0) - .layer_count(1) - .build(), - ) - .image_extent(vk::Extent3D { - width: 1.max(ktx_image_width >> i), - height: 1.max(ktx_image_height >> i), - depth: 1, - }) - .buffer_offset(ktx_offsets[i as usize]) - .build() - }) - .collect(); - - let image_create_info = vk::ImageCreateInfo::builder() - .image_type(vk::ImageType::TYPE_2D) - .format(format) - .mip_levels(mip_levels) - .array_layers(1) - .samples(vk::SampleCountFlags::TYPE_1) - .tiling(vk::ImageTiling::OPTIMAL) - .sharing_mode(vk::SharingMode::EXCLUSIVE) - .initial_layout(vk::ImageLayout::UNDEFINED) - .extent(vk::Extent3D { - width: ktx_image_width, - height: ktx_image_height, - depth: 1, - }) - .usage(image_usage_flags | vk::ImageUsageFlags::TRANSFER_DST); - - let image = unsafe { device.create_image(&image_create_info, None) }?; - let image_mem_reqs = unsafe { device.get_image_memory_requirements(image) }; - - let image_memory = device.alloc_memory( - &memory_properties, - image_mem_reqs, - vk::MemoryPropertyFlags::DEVICE_LOCAL, - )?; - unsafe { device.bind_image_memory(image, image_memory, 0) }?; - - let subresource_range = vk::ImageSubresourceRange::builder() - .aspect_mask(vk::ImageAspectFlags::COLOR) - .base_mip_level(0) - .level_count(mip_levels) - .layer_count(1) - .build(); - - device.set_image_layout_with_subresource( - copy_cmd, - image, - vk::ImageLayout::UNDEFINED, - vk::ImageLayout::TRANSFER_DST_OPTIMAL, - subresource_range, - vk::PipelineStageFlags::ALL_COMMANDS, - vk::PipelineStageFlags::ALL_COMMANDS, - None, - None, - ); - - unsafe { - device.cmd_copy_buffer_to_image( - copy_cmd, - staging_buffer, - image, - vk::ImageLayout::TRANSFER_DST_OPTIMAL, - &buffer_copy_regions, - ) - }; - - device.set_image_layout_with_subresource( - copy_cmd, - image, - vk::ImageLayout::TRANSFER_DST_OPTIMAL, - image_layout, - subresource_range, - vk::PipelineStageFlags::ALL_COMMANDS, - vk::PipelineStageFlags::ALL_COMMANDS, - None, - None, - ); - - device.flush_cmd_buffer(©_cmd, copy_queue, command_pool, true)?; - - unsafe { - device.free_memory(staging_buffer_memory, None); - device.destroy_buffer(staging_buffer, None); - } - - let sampler_create_info = vk::SamplerCreateInfo::builder() - .mag_filter(vk::Filter::LINEAR) - .min_filter(vk::Filter::LINEAR) - .mipmap_mode(vk::SamplerMipmapMode::LINEAR) - .address_mode_u(vk::SamplerAddressMode::REPEAT) - .address_mode_v(vk::SamplerAddressMode::REPEAT) - .address_mode_w(vk::SamplerAddressMode::REPEAT) - .mip_lod_bias(0.) - .compare_op(vk::CompareOp::NEVER) - .min_lod(0.) - .max_lod(mip_levels as _) - .max_anisotropy(1.0) - .anisotropy_enable(false) - .border_color(vk::BorderColor::FLOAT_OPAQUE_WHITE); - let sampler = unsafe { device.create_sampler(&sampler_create_info, None) }?; - - let view_create_info = vk::ImageViewCreateInfo::builder() - .view_type(vk::ImageViewType::TYPE_2D) - .format(format) - .components(vk::ComponentMapping { - r: vk::ComponentSwizzle::R, - g: vk::ComponentSwizzle::G, - b: vk::ComponentSwizzle::B, - a: vk::ComponentSwizzle::A, - }) - .subresource_range( - vk::ImageSubresourceRange::builder() - .aspect_mask(vk::ImageAspectFlags::COLOR) - .base_mip_level(0) - .level_count(mip_levels) - .base_array_layer(0) - .layer_count(1) - .build(), - ) - .image(image); - let image_view = unsafe { device.create_image_view(&view_create_info, None) }?; - - let descriptor = vk::DescriptorImageInfo::builder() - .sampler(sampler) - .image_view(image_view) - .image_layout(image_layout) - .build(); - - Ok(Self { - device: Arc::clone(&device.device), - image, - view: image_view, - image_layout, - memory: image_memory, - width: ktx_image_width, - height: ktx_image_width, - mip_levels, - layer_count: 1, - sampler, - descriptor, - }) - } - - pub fn new( - instance: &VkInstance, - device: &VkDevice, - width: u32, - height: u32, - command_pool: &vk::CommandPool, - queues: &VkQueues, - format: vk::Format, - ) -> VkResult { - let memory_properties = - unsafe { instance.get_physical_device_memory_properties(device.physical_device) }; - - let mut queue_indices = vec![]; - let sharing_concurrent = queues.graphics_queue.index != queues.compute_queue.index; - let image_create_info = vk::ImageCreateInfo::builder() - .image_type(vk::ImageType::TYPE_2D) - .format(format) - .mip_levels(1) - .array_layers(1) - .samples(vk::SampleCountFlags::TYPE_1) - .tiling(vk::ImageTiling::OPTIMAL) - .initial_layout(vk::ImageLayout::UNDEFINED) - .extent(vk::Extent3D { - width, - height, - depth: 1, - }) - .sharing_mode(if sharing_concurrent { - vk::SharingMode::CONCURRENT - } else { - vk::SharingMode::EXCLUSIVE - }) - .queue_family_indices({ - if sharing_concurrent { - queue_indices.extend_from_slice(&[ - queues.graphics_queue.index, - queues.compute_queue.index, - ]); - } - &queue_indices - }) - .usage(vk::ImageUsageFlags::SAMPLED | vk::ImageUsageFlags::STORAGE); - - let image = unsafe { device.create_image(&image_create_info, None) }?; - let image_mem_reqs = unsafe { device.get_image_memory_requirements(image) }; - - let image_memory = device.alloc_memory( - &memory_properties, - image_mem_reqs, - vk::MemoryPropertyFlags::DEVICE_LOCAL, - )?; - unsafe { device.bind_image_memory(image, image_memory, 0) }?; - - let cmd_buffer_allocate_info = vk::CommandBufferAllocateInfo::builder() - .command_pool(*command_pool) - .level(vk::CommandBufferLevel::PRIMARY) - .command_buffer_count(1); - let layout_cmd = unsafe { device.allocate_command_buffers(&cmd_buffer_allocate_info) }?[0]; - - let begin_info = vk::CommandBufferBeginInfo::builder(); - unsafe { device.begin_command_buffer(layout_cmd, &begin_info) }?; - - let image_layout = vk::ImageLayout::GENERAL; - let subresource_range = vk::ImageSubresourceRange::builder() - .aspect_mask(vk::ImageAspectFlags::COLOR) - .base_mip_level(0) - .level_count(1) - .base_array_layer(0) - .layer_count(1) - .build(); - device.set_image_layout_with_subresource( - layout_cmd, - image, - vk::ImageLayout::UNDEFINED, - image_layout, - subresource_range, - vk::PipelineStageFlags::ALL_COMMANDS, - vk::PipelineStageFlags::ALL_COMMANDS, - None, - None, - ); - - device.flush_cmd_buffer( - &layout_cmd, - &queues.graphics_queue.queue, - command_pool, - true, - )?; - - let sampler_create_info = vk::SamplerCreateInfo::builder() - .mag_filter(vk::Filter::LINEAR) - .min_filter(vk::Filter::LINEAR) - .mipmap_mode(vk::SamplerMipmapMode::LINEAR) - .address_mode_u(vk::SamplerAddressMode::CLAMP_TO_BORDER) - .address_mode_v(vk::SamplerAddressMode::CLAMP_TO_BORDER) - .address_mode_w(vk::SamplerAddressMode::CLAMP_TO_BORDER) - .mip_lod_bias(0.) - .compare_op(vk::CompareOp::NEVER) - .min_lod(0.) - // Duh - .max_lod(1.) - .max_anisotropy(1.0) - .anisotropy_enable(false) - .border_color(vk::BorderColor::FLOAT_OPAQUE_WHITE); - let sampler = unsafe { device.create_sampler(&sampler_create_info, None) }?; - - let view_create_info = vk::ImageViewCreateInfo::builder() - .view_type(vk::ImageViewType::TYPE_2D) - .format(format) - .components(vk::ComponentMapping { - r: vk::ComponentSwizzle::R, - g: vk::ComponentSwizzle::G, - b: vk::ComponentSwizzle::B, - a: vk::ComponentSwizzle::A, - }) - .subresource_range( - vk::ImageSubresourceRange::builder() - .aspect_mask(vk::ImageAspectFlags::COLOR) - .base_mip_level(0) - .level_count(1) - .base_array_layer(0) - .layer_count(1) - .build(), - ) - .image(image); - let image_view = unsafe { device.create_image_view(&view_create_info, None) }?; - - let descriptor = vk::DescriptorImageInfo::builder() - .sampler(sampler) - .image_view(image_view) - .image_layout(image_layout) - .build(); - - Ok(Self { - device: Arc::clone(&device.device), - image, - view: image_view, - image_layout, - memory: image_memory, - width, - height, - mip_levels: 1, - layer_count: 1, - sampler, - descriptor, - }) - } -} - -impl Drop for VkTexture { - fn drop(&mut self) { - unsafe { - self.device.destroy_image_view(self.view, None); - self.device.destroy_image(self.image, None); - self.device.destroy_sampler(self.sampler, None); - self.device.free_memory(self.memory, None); - } - } -} diff --git a/pilka_ash/src/pvk/utils.rs b/pilka_ash/src/pvk/utils.rs deleted file mode 100644 index b610e14..0000000 --- a/pilka_ash/src/pvk/utils.rs +++ /dev/null @@ -1,85 +0,0 @@ -use ash::vk; - -pub fn find_memory_type_index( - memory_req: &vk::MemoryRequirements, - memory_prop: &vk::PhysicalDeviceMemoryProperties, - flags: vk::MemoryPropertyFlags, -) -> Option { - memory_prop.memory_types[..memory_prop.memory_type_count as _] - .iter() - .enumerate() - .find(|(index, memory_type)| { - (1 << index) & memory_req.memory_type_bits != 0 - && (memory_type.property_flags & flags) == flags - }) - .map(|(index, _memory_type)| index as _) -} - -pub fn size_of_slice(slice: &[T]) -> usize { - std::mem::size_of::() * slice.len() -} - -#[macro_export] -macro_rules! any { - ($x:expr, $($y:expr),+ $(,)?) => { - { - false $(|| $x == $y)+ - } - }; -} - -#[macro_export] -macro_rules! include_str_from_outdir { - ($t: literal) => { - include_str!(concat!(env!("OUT_DIR"), $t)) - }; -} - -#[macro_export] -macro_rules! include_bytes_from_outdir { - ($t: literal) => { - include_bytes!(concat!(env!("OUT_DIR"), $t)) - }; -} - -#[macro_export] -macro_rules! include_spirv_from_outdir { - ($t: literal) => { - $crate::utils::make_spirv(crate::include_bytes_from_outdir!($t)) - }; -} - -#[macro_export] -macro_rules! tuple_as { - ($e:expr, ( $T0:ty, $T1:ty, $T2:ty, $T3:ty, $T4:ty, $T5:ty ) ) => { - ( - $e.0 as $T0, - $e.1 as $T1, - $e.2 as $T2, - $e.3 as $T3, - $e.4 as $T4, - $e.5 as $T5, - ) - }; - ($e:expr, ( $T0:ty, $T1:ty, $T2:ty, $T3:ty, $T4:ty ) ) => { - ( - $e.0 as $T0, - $e.1 as $T1, - $e.2 as $T2, - $e.3 as $T3, - $e.4 as $T4, - ) - }; - ($e:expr, ( $T0:ty, $T1:ty, $T2:ty, $T3:ty ) ) => { - ($e.0 as $T0, $e.1 as $T1, $e.2 as $T2, $e.3 as $T3) - }; - ($e:expr, ( $T0:ty, $T1:ty, $T2:ty ) ) => { - ($e.0 as $T0, $e.1 as $T1, $e.2 as $T2) - }; - ($e:expr, ( $T0:ty, $T1:ty ) ) => { - ($e.0 as $T0, $e.1 as $T1) - }; - ($e:expr, ( $T0:ty, ) ) => { - ($e.0 as $T0,) - }; -} diff --git a/pilka_ash/src/renderer.rs b/pilka_ash/src/renderer.rs deleted file mode 100644 index d80bde6..0000000 --- a/pilka_ash/src/renderer.rs +++ /dev/null @@ -1,1380 +0,0 @@ -mod images; -mod screenshot; - -use pilka_types::{ - dispatch_optimal_size, Frame, ImageDimentions, PushConstant, ShaderCreateInfo, Uniform, -}; -use raw_window_handle::HasRawDisplayHandle; - -use crate::pvk::*; -use ash::{ - prelude::VkResult, - vk::{self, Extent3D, SubresourceLayout}, -}; -use std::{borrow::Cow, ffi::CStr, fmt::Display}; - -use images::{FftTexture, VkTexture}; -use screenshot::ScreenshotCtx; - -fn graphics_desc_set_leyout(device: &VkDevice) -> VkResult> { - let descriptor_set_layout = { - let descriptor_set_layout_binding_descs = [ - vk::DescriptorSetLayoutBinding::builder() - .binding(0) - .descriptor_type(vk::DescriptorType::SAMPLED_IMAGE) - .descriptor_count(1) - .stage_flags(vk::ShaderStageFlags::FRAGMENT) - .build(), - vk::DescriptorSetLayoutBinding::builder() - .binding(1) - .descriptor_type(vk::DescriptorType::SAMPLED_IMAGE) - .descriptor_count(1) - .stage_flags(vk::ShaderStageFlags::FRAGMENT) - .build(), - vk::DescriptorSetLayoutBinding::builder() - .binding(2) - .descriptor_type(vk::DescriptorType::SAMPLED_IMAGE) - .descriptor_count(1) - .stage_flags(vk::ShaderStageFlags::FRAGMENT) - .build(), - vk::DescriptorSetLayoutBinding::builder() - .binding(3) - .descriptor_type(vk::DescriptorType::SAMPLED_IMAGE) - .descriptor_count(1) - .stage_flags(vk::ShaderStageFlags::FRAGMENT) - .build(), - vk::DescriptorSetLayoutBinding::builder() - .binding(4) - .descriptor_type(vk::DescriptorType::SAMPLED_IMAGE) - .descriptor_count(1) - .stage_flags(vk::ShaderStageFlags::FRAGMENT) - .build(), - ]; - let descriptor_set_layout_info = vk::DescriptorSetLayoutCreateInfo::builder() - .bindings(&descriptor_set_layout_binding_descs); - unsafe { device.create_descriptor_set_layout(&descriptor_set_layout_info, None) }? - }; - - let sampler_descriptor_set_layout = { - let descriptor_set_layout_binding_descs = [vk::DescriptorSetLayoutBinding::builder() - .binding(0) - .descriptor_type(vk::DescriptorType::SAMPLER) - .descriptor_count(1) - .stage_flags(vk::ShaderStageFlags::FRAGMENT) - .build()]; - let descriptor_set_layout_info = vk::DescriptorSetLayoutCreateInfo::builder() - .bindings(&descriptor_set_layout_binding_descs); - unsafe { device.create_descriptor_set_layout(&descriptor_set_layout_info, None) }? - }; - - let uniform_descriptor_set_layout = { - let descriptor_set_layout_binding_descs = [vk::DescriptorSetLayoutBinding::builder() - .binding(0) - .descriptor_type(vk::DescriptorType::UNIFORM_BUFFER) - .descriptor_count(1) - .stage_flags(vk::ShaderStageFlags::FRAGMENT | vk::ShaderStageFlags::VERTEX) - .build()]; - let descriptor_set_layout_info = vk::DescriptorSetLayoutCreateInfo::builder() - .bindings(&descriptor_set_layout_binding_descs); - unsafe { device.create_descriptor_set_layout(&descriptor_set_layout_info, None) }? - }; - - // let fft_descriptor_set_layout = { - // let descriptor_set_layout_binding_descs = [vk::DescriptorSetLayoutBinding::builder() - // .binding(0) - // .descriptor_type(vk::DescriptorType::SAMPLED_IMAGE) - // .descriptor_count(1) - // .stage_flags(vk::ShaderStageFlags::FRAGMENT) - // .build()]; - // let descriptor_set_layout_info = vk::DescriptorSetLayoutCreateInfo::builder() - // .bindings(&descriptor_set_layout_binding_descs); - // unsafe { device.create_descriptor_set_layout(&descriptor_set_layout_info, None) }? - // }; - - Ok(vec![ - descriptor_set_layout, - sampler_descriptor_set_layout, - uniform_descriptor_set_layout, - // fft_descriptor_set_layout, - ]) -} - -fn compute_desc_set_leyout(device: &VkDevice) -> VkResult> { - let descriptor_set_layout = { - let descriptor_set_layout_binding_descs = [ - vk::DescriptorSetLayoutBinding::builder() - .binding(0) - .descriptor_type(vk::DescriptorType::STORAGE_IMAGE) - .descriptor_count(1) - .stage_flags(vk::ShaderStageFlags::COMPUTE) - .build(), - vk::DescriptorSetLayoutBinding::builder() - .binding(1) - .descriptor_type(vk::DescriptorType::STORAGE_IMAGE) - .descriptor_count(1) - .stage_flags(vk::ShaderStageFlags::COMPUTE) - .build(), - vk::DescriptorSetLayoutBinding::builder() - .binding(2) - .descriptor_type(vk::DescriptorType::STORAGE_IMAGE) - .descriptor_count(1) - .stage_flags(vk::ShaderStageFlags::COMPUTE) - .build(), - vk::DescriptorSetLayoutBinding::builder() - .binding(3) - .descriptor_type(vk::DescriptorType::STORAGE_IMAGE) - .descriptor_count(1) - .stage_flags(vk::ShaderStageFlags::COMPUTE) - .build(), - vk::DescriptorSetLayoutBinding::builder() - .binding(4) - .descriptor_type(vk::DescriptorType::STORAGE_IMAGE) - .descriptor_count(1) - .stage_flags(vk::ShaderStageFlags::COMPUTE) - .build(), - ]; - let descriptor_set_layout_info = vk::DescriptorSetLayoutCreateInfo::builder() - .bindings(&descriptor_set_layout_binding_descs); - unsafe { device.create_descriptor_set_layout(&descriptor_set_layout_info, None) }? - }; - - let uniform_descriptor_set_layout = { - let descriptor_set_layout_binding_descs = [vk::DescriptorSetLayoutBinding::builder() - .binding(0) - .descriptor_type(vk::DescriptorType::UNIFORM_BUFFER) - .descriptor_count(1) - .stage_flags(vk::ShaderStageFlags::COMPUTE) - .build()]; - let descriptor_set_layout_info = vk::DescriptorSetLayoutCreateInfo::builder() - .bindings(&descriptor_set_layout_binding_descs); - unsafe { device.create_descriptor_set_layout(&descriptor_set_layout_info, None) }? - }; - - // let fft_descriptor_set_layout = { - // let descriptor_set_layout_binding_descs = [vk::DescriptorSetLayoutBinding::builder() - // .binding(0) - // .descriptor_type(vk::DescriptorType::STORAGE_IMAGE) - // .descriptor_count(1) - // .stage_flags(vk::ShaderStageFlags::COMPUTE) - // .build()]; - // let descriptor_set_layout_info = vk::DescriptorSetLayoutCreateInfo::builder() - // .bindings(&descriptor_set_layout_binding_descs); - // unsafe { device.create_descriptor_set_layout(&descriptor_set_layout_info, None) }? - // }; - - Ok(vec![ - descriptor_set_layout, - uniform_descriptor_set_layout, - // fft_descriptor_set_layout, - ]) -} - -/// The main struct that holds all render primitives -/// -/// Rust documentation states for FIFO drop order for struct fields. -/// Or in the other words it's the same order that they're declared. -pub struct AshRender<'a> { - pub paused: bool, - - descriptor_pool: vk::DescriptorPool, - pub descriptor_sets_render: Vec, - pub descriptor_sets_compute: Vec, - descriptor_set_layouts: Vec, - descriptor_set_layouts_compute: Vec, - - fft_texture: FftTexture<'a>, - - previous_frame: VkTexture, - generic_texture: VkTexture, - dummy_texture: VkTexture, - float_texture1: VkTexture, - float_texture2: VkTexture, - - sampler: vk::Sampler, - - pub screenshot_ctx: ScreenshotCtx<'a>, - pub push_constants_range: u32, - - pub scissors: vk::Rect2D, - pub viewport: vk::Viewport, - pub resolution: vk::Extent2D, - - pub rendering_complete_semaphore: vk::Semaphore, - pub present_complete_semaphore: vk::Semaphore, - pub command_pool: VkCommandPool, - pub command_pool_transfer: VkCommandPool, - - pub pipeline_cache: vk::PipelineCache, - pub pipelines: Vec, - pub render_pass: VkRenderPass, - - pub framebuffers: Vec, - pub swapchain: VkSwapchain, - pub surface: VkSurface, - - #[allow(dead_code)] - uniform: Uniform, - #[allow(dead_code)] - uniform_buffer: vk::Buffer, - #[allow(dead_code)] - uniform_memory: vk::DeviceMemory, - #[allow(dead_code)] - uniform_desc: vk::DescriptorBufferInfo, - uniform_buffer_ptr: *mut Uniform, - - pub device_properties: VkDeviceProperties, - - pub queues: VkQueues, - pub device: VkDevice, -} - -#[derive(Debug)] -pub struct RendererInfo { - pub device_name: String, - pub device_type: String, - pub vendor_name: String, - pub vulkan_version_name: String, -} - -impl Display for RendererInfo { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - writeln!(f, "Vendor name: {}", self.vendor_name)?; - writeln!(f, "Device name: {}", self.device_name)?; - writeln!(f, "Device type: {}", self.device_type)?; - writeln!(f, "Vulkan version: {}", self.vulkan_version_name)?; - Ok(()) - } -} - -impl<'a> AshRender<'a> { - pub fn get_info(&self) -> RendererInfo { - RendererInfo { - device_name: self.get_device_name().unwrap().to_string(), - device_type: self.get_device_type().to_string(), - vendor_name: self.get_vendor_name().to_string(), - vulkan_version_name: self.get_vulkan_version_name().unwrap().to_string(), - } - } - pub fn get_device_name(&self) -> Result<&str, std::str::Utf8Error> { - unsafe { CStr::from_ptr(self.device_properties.properties.device_name.as_ptr()) }.to_str() - } - pub fn get_device_type(&self) -> &str { - match self.device_properties.properties.device_type { - vk::PhysicalDeviceType::CPU => "CPU", - vk::PhysicalDeviceType::INTEGRATED_GPU => "INTEGRATED_GPU", - vk::PhysicalDeviceType::DISCRETE_GPU => "DISCRETE_GPU", - vk::PhysicalDeviceType::VIRTUAL_GPU => "VIRTUAL_GPU", - _ => "OTHER", - } - } - pub fn get_vendor_name(&self) -> &str { - match self.device_properties.properties.vendor_id { - 0x1002 => "AMD", - 0x1010 => "ImgTec", - 0x10DE => "NVIDIA Corporation", - 0x13B5 => "ARM", - 0x5143 => "Qualcomm", - 0x8086 => "INTEL Corporation", - _ => "Unknown vendor", - } - } - pub fn get_vulkan_version_name(&self) -> VkResult> { - let name = match self - .device - .instance - .entry - .try_enumerate_instance_version()? - { - Some(version) => { - let major = version >> 22; - let minor = (version >> 12) & 0x3ff; - let patch = version & 0xfff; - format!("{}.{}.{}", major, minor, patch).into() - } - None => "1.0.0".into(), - }; - Ok(name) - } - - pub fn new( - window: &W, - push_constants_range: u32, - ) -> Result> { - let validation_layers = if cfg!(debug_assertions) { - vec!["VK_LAYER_KHRONOS_validation\0"] - } else { - vec![] - }; - // let validation_layers = vec!["VK_LAYER_KHRONOS_validation\0"]; - let extention_names = - ash_window::enumerate_required_extensions(window.raw_display_handle())?; - - let instance = VkInstance::new(&validation_layers, extention_names)?; - - let surface = instance.create_surface(window)?; - - let (device, device_properties, queues) = - instance.create_device_and_queues(Some(&surface))?; - - device.name_queue(queues.graphics_queue.queue, "Graphics Queue")?; - device.name_queue(queues.transfer_queue.queue, "Transfer Queue")?; - device.name_queue(queues.compute_queue.queue, "Compute Queue")?; - - let surface_resolution = surface.resolution(&device)?; - - let swapchain_loader = device.instance.create_swapchain_loader(&device); - - let swapchain = device.create_swapchain(swapchain_loader, &surface, &queues)?; - - let command_pool_transfer = device - .create_vk_command_pool(queues.transfer_queue.index, swapchain.images.len() as u32)?; - - let mut command_pool = device - .create_vk_command_pool(queues.graphics_queue.index, swapchain.images.len() as u32)?; - for &image in &swapchain.images { - command_pool.record_submit_commandbuffer( - &device, - queues.graphics_queue.queue, - &[], - &[], - &[], - |device, command_buffer| { - device.set_image_layout( - command_buffer, - image, - vk::ImageLayout::UNDEFINED, - vk::ImageLayout::PRESENT_SRC_KHR, - vk::PipelineStageFlags::TRANSFER, - vk::PipelineStageFlags::TRANSFER, - ); - }, - )?; - } - - let render_pass = device.create_vk_render_pass(swapchain.format())?; - - let present_complete_semaphore = device.create_semaphore()?; - let rendering_complete_semaphore = device.create_semaphore()?; - - device.name_semaphore(present_complete_semaphore, "Present Compelete Semaphore")?; - device.name_semaphore(rendering_complete_semaphore, "Render Complete Semaphore")?; - - let framebuffers = swapchain.create_framebuffers( - (surface_resolution.width, surface_resolution.height), - &render_pass, - &device, - )?; - - let (viewport, scissors, extent) = { - let surface_resolution = surface.resolution(&device)?; - ( - vk::Viewport { - x: 0.0, - y: surface_resolution.height as f32, - width: surface_resolution.width as f32, - height: -(surface_resolution.height as f32), - min_depth: 0.0, - max_depth: 1.0, - }, - vk::Rect2D { - offset: vk::Offset2D { x: 0, y: 0 }, - extent: surface_resolution, - }, - surface_resolution, - ) - }; - - let pipeline_cache_create_info = vk::PipelineCacheCreateInfo::builder(); - let pipeline_cache = - unsafe { device.create_pipeline_cache(&pipeline_cache_create_info, None) }?; - - let mut need2steps = false; - let format_props = unsafe { - device - .instance - .get_physical_device_format_properties(device.physical_device, swapchain.format) - }; - let blit_linear = format_props - .linear_tiling_features - .contains(vk::FormatFeatureFlags::BLIT_DST); - let blit_optimal = format_props - .optimal_tiling_features - .contains(vk::FormatFeatureFlags::BLIT_DST); - if !blit_linear && blit_optimal { - need2steps = true - } - let screenshot_ctx = ScreenshotCtx::new( - &device, - &device_properties.memory, - &command_pool, - extent, - swapchain.format, - need2steps, - )?; - - let fft_texture = FftTexture::new(&device, &device_properties, &command_pool_transfer)?; - let screen_sized_texture = |format| -> VkResult { - let extent = vk::Extent3D { - width: extent.width, - height: extent.height, - depth: 1, - }; - let image_create_info = vk::ImageCreateInfo::builder() - .format(format) - .image_type(vk::ImageType::TYPE_2D) - .extent(extent) - .array_layers(1) - .mip_levels(1) - .samples(vk::SampleCountFlags::TYPE_1) - .tiling(vk::ImageTiling::OPTIMAL) - .usage( - vk::ImageUsageFlags::TRANSFER_DST - | vk::ImageUsageFlags::SAMPLED - | vk::ImageUsageFlags::STORAGE, - ) - .sharing_mode(vk::SharingMode::EXCLUSIVE) - .initial_layout(vk::ImageLayout::UNDEFINED); - let image_memory_flags = vk::MemoryPropertyFlags::DEVICE_LOCAL; - - let sampler_create_info = vk::SamplerCreateInfo::builder() - .mag_filter(vk::Filter::LINEAR) - .min_filter(vk::Filter::LINEAR) - .address_mode_u(vk::SamplerAddressMode::REPEAT) - .address_mode_v(vk::SamplerAddressMode::REPEAT) - .address_mode_w(vk::SamplerAddressMode::REPEAT) - .anisotropy_enable(false) - .max_anisotropy(0.); - - VkTexture::new( - &device, - &device_properties.memory, - &image_create_info, - image_memory_flags, - &sampler_create_info, - ) - }; - let previous_frame = screen_sized_texture(vk::Format::R8G8B8A8_UNORM)?; - let generic_texture = screen_sized_texture(vk::Format::R8G8B8A8_UNORM)?; - let dummy_texture = screen_sized_texture(vk::Format::R8G8B8A8_UNORM)?; - let float_texture1 = screen_sized_texture(vk::Format::R32G32B32A32_SFLOAT)?; - let float_texture2 = screen_sized_texture(vk::Format::R32G32B32A32_SFLOAT)?; - - let sampler = { - let sampler_create_info = vk::SamplerCreateInfo::builder() - .mag_filter(vk::Filter::LINEAR) - .min_filter(vk::Filter::LINEAR) - .address_mode_u(vk::SamplerAddressMode::REPEAT) - .address_mode_v(vk::SamplerAddressMode::REPEAT) - .address_mode_w(vk::SamplerAddressMode::REPEAT) - .anisotropy_enable(false) - .max_anisotropy(0.); - unsafe { device.create_sampler(&sampler_create_info, None) }? - }; - - device.name_image(previous_frame.image.image, "Previous Frame Texture")?; - device.name_image(generic_texture.image.image, "Generic Texture")?; - device.name_image(dummy_texture.image.image, "Dummy Texture")?; - device.name_image(float_texture1.image.image, "Float Texture 1")?; - device.name_image(float_texture2.image.image, "Float Texture 2")?; - device.name_image(fft_texture.texture.image.image, "FFT Texture")?; - { - let images = [ - previous_frame.image.image, - fft_texture.texture.image.image, - generic_texture.image.image, - dummy_texture.image.image, - float_texture1.image.image, - float_texture2.image.image, - ]; - command_pool.record_submit_commandbuffer( - &device, - queues.graphics_queue.queue, - &[], - &[], - &[], - |device, command_buffer| { - for &image in &images { - device.set_image_layout( - command_buffer, - image, - vk::ImageLayout::UNDEFINED, - vk::ImageLayout::GENERAL, - vk::PipelineStageFlags::TRANSFER, - vk::PipelineStageFlags::TRANSFER, - ); - } - }, - )?; - } - - let pool_sizes = [ - vk::DescriptorPoolSize { - ty: vk::DescriptorType::SAMPLED_IMAGE, - descriptor_count: 24, - }, - vk::DescriptorPoolSize { - ty: vk::DescriptorType::STORAGE_IMAGE, - descriptor_count: 16, - }, - vk::DescriptorPoolSize { - ty: vk::DescriptorType::SAMPLER, - descriptor_count: 16, - }, - vk::DescriptorPoolSize { - ty: vk::DescriptorType::UNIFORM_BUFFER, - descriptor_count: 16, - }, - ]; - let descriptor_pool_info = vk::DescriptorPoolCreateInfo::builder() - .max_sets(12) - .pool_sizes(&pool_sizes); - let descriptor_pool = - unsafe { device.create_descriptor_pool(&descriptor_pool_info, None) }?; - - let descriptor_set_layouts_graphics = graphics_desc_set_leyout(&device)?; - let descriptor_sets_render = { - let descriptor_set_allocate_info = vk::DescriptorSetAllocateInfo::builder() - .descriptor_pool(descriptor_pool) - .set_layouts(&descriptor_set_layouts_graphics); - unsafe { device.allocate_descriptor_sets(&descriptor_set_allocate_info) }? - }; - - let descriptor_set_layouts_compute = compute_desc_set_leyout(&device)?; - let descriptor_sets_compute = { - let descriptor_set_allocate_info = vk::DescriptorSetAllocateInfo::builder() - .descriptor_pool(descriptor_pool) - .set_layouts(&descriptor_set_layouts_compute); - unsafe { device.allocate_descriptor_sets(&descriptor_set_allocate_info) }? - }; - - let image_infos: &[&[vk::DescriptorImageInfo]] = &[ - &[ - vk::DescriptorImageInfo { - image_layout: vk::ImageLayout::GENERAL, - image_view: previous_frame.image_view, - sampler: previous_frame.sampler, - }, - vk::DescriptorImageInfo { - image_layout: vk::ImageLayout::GENERAL, - image_view: generic_texture.image_view, - sampler: generic_texture.sampler, - }, - vk::DescriptorImageInfo { - image_layout: vk::ImageLayout::GENERAL, - image_view: dummy_texture.image_view, - sampler: dummy_texture.sampler, - }, - vk::DescriptorImageInfo { - image_layout: vk::ImageLayout::GENERAL, - image_view: float_texture1.image_view, - sampler: float_texture1.sampler, - }, - vk::DescriptorImageInfo { - image_layout: vk::ImageLayout::GENERAL, - image_view: float_texture2.image_view, - sampler: float_texture2.sampler, - }, - ], - &[vk::DescriptorImageInfo { - sampler, - ..Default::default() - }], - // &[vk::DescriptorImageInfo { - // image_layout: vk::ImageLayout::GENERAL, - // image_view: fft_texture.texture.image_view, - // sampler: fft_texture.texture.sampler, - // }], - ]; - let desc_types = &[ - vk::DescriptorType::SAMPLED_IMAGE, - vk::DescriptorType::SAMPLER, - // vk::DescriptorType::SAMPLED_IMAGE, - ]; - - AshRender::update_image_bindings(&device, image_infos, desc_types, &descriptor_sets_render); - - let image_infos = &[ - image_infos[0], - /* image_infos[2] */ - ]; - let desc_types = &[ - vk::DescriptorType::STORAGE_IMAGE, - // vk::DescriptorType::STORAGE_IMAGE, - ]; - - AshRender::update_image_bindings( - &device, - image_infos, - desc_types, - &descriptor_sets_compute, - ); - - let uniform = Uniform::default(); - let (uniform_buffer, uniform_memory, uniform_desc, uniform_buffer_ptr) = { - let size = std::mem::size_of::() as _; - let usage_flags = vk::BufferUsageFlags::UNIFORM_BUFFER; - - let buffer_create_info = vk::BufferCreateInfo::builder() - .size(size) - .usage(usage_flags); - let buffer = unsafe { device.create_buffer(&buffer_create_info, None) }?; - - let memory_reqs = unsafe { device.get_buffer_memory_requirements(buffer) }; - - let memory_prop_flags = - vk::MemoryPropertyFlags::HOST_VISIBLE | vk::MemoryPropertyFlags::HOST_COHERENT; - - let memory_type_index = utils::find_memory_type_index( - &memory_reqs, - &device.memory_properties, - memory_prop_flags, - ) - .unwrap(); - let mut mem_alloc_flags = vk::MemoryAllocateFlagsInfoKHR::default(); - let alloc_info = vk::MemoryAllocateInfo::builder() - .allocation_size(memory_reqs.size) - .memory_type_index(memory_type_index) - .push_next({ - if usage_flags.contains(vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS) { - mem_alloc_flags.flags = vk::MemoryAllocateFlagsKHR::DEVICE_ADDRESS_KHR; - } - &mut mem_alloc_flags - }); - let buffer_memory = unsafe { device.device.allocate_memory(&alloc_info, None) }?; - - let descriptor = vk::DescriptorBufferInfo::builder() - .offset(0) - .buffer(buffer) - .range(vk::WHOLE_SIZE) - .build(); - - unsafe { device.bind_buffer_memory(buffer, buffer_memory, 0) }?; - - let mapped_ptr = - unsafe { device.map_memory(buffer_memory, 0, size, vk::MemoryMapFlags::empty()) }? - .cast(); - - (buffer, buffer_memory, descriptor, mapped_ptr) - }; - - unsafe { - device.update_descriptor_sets( - &[ - *vk::WriteDescriptorSet::builder() - .dst_set(descriptor_sets_compute[1]) - .dst_binding(0) - .dst_array_element(0) - .descriptor_type(vk::DescriptorType::UNIFORM_BUFFER) - .buffer_info(&[uniform_desc]), - *vk::WriteDescriptorSet::builder() - .dst_set(descriptor_sets_render[2]) - .dst_binding(0) - .dst_array_element(0) - .descriptor_type(vk::DescriptorType::UNIFORM_BUFFER) - .buffer_info(&[uniform_desc]), - ], - &[], - ); - } - - Ok(Self { - paused: false, - - device, - queues, - - device_properties, - - surface, - swapchain, - framebuffers, - - render_pass, - pipelines: vec![], - pipeline_cache, - - command_pool_transfer, - command_pool, - present_complete_semaphore, - rendering_complete_semaphore, - - viewport, - scissors, - resolution: extent, - - push_constants_range, - screenshot_ctx, - - sampler, - - float_texture1, - float_texture2, - previous_frame, - generic_texture, - dummy_texture, - - fft_texture, - - descriptor_pool, - descriptor_sets_render, - descriptor_sets_compute, - descriptor_set_layouts: descriptor_set_layouts_graphics, - descriptor_set_layouts_compute, - - uniform, - uniform_buffer, - uniform_memory, - uniform_desc, - uniform_buffer_ptr, - }) - } - - fn update_image_bindings( - device: &VkDevice, - image_infos: &[&[vk::DescriptorImageInfo]], - desc_types: &[vk::DescriptorType], - desc_sets: &[vk::DescriptorSet], - ) { - for (descset, (image_infos, &image_type)) in - desc_sets.iter().zip(image_infos.iter().zip(desc_types)) - { - for (i, image_info) in image_infos.iter().enumerate() { - unsafe { - device.update_descriptor_sets( - &[*vk::WriteDescriptorSet::builder() - .dst_set(*descset) - .dst_binding(i as _) - .dst_array_element(0) - .descriptor_type(image_type) - .image_info(&[*image_info])], - &[], - ) - }; - } - } - } - - pub fn render(&mut self, push_constant: PushConstant) -> VkResult<()> { - puffin::profile_function!(); - let (present_index, is_suboptimal) = match unsafe { - self.swapchain.swapchain_loader.acquire_next_image( - self.swapchain.swapchain, - std::u64::MAX, - self.present_complete_semaphore, - vk::Fence::null(), - ) - } { - Ok((index, check)) => (index, check), - Err(vk::Result::ERROR_OUT_OF_DATE_KHR) | Err(vk::Result::SUBOPTIMAL_KHR) => { - println!("Oooopsie~ Get out-of-date swapchain in first time"); - self.resize()?; - return Ok(()); - } - Err(e) => panic!("{}", e), - }; - if is_suboptimal { - self.resize()?; - } - - unsafe { *self.uniform_buffer_ptr = push_constant.into() }; - - let clear_values = [vk::ClearValue { - color: vk::ClearColorValue { - float32: [0.0, 0.0, 1.0, 0.0], - }, - }]; - - let extent = vk::Extent3D { - width: self.resolution.width, - height: self.resolution.height, - depth: 1, - }; - - let mut executed_compute_semaphores = vec![]; - - unsafe { self.device.queue_wait_idle(self.queues.compute_queue.queue) }?; - - for (i, undefined_pipeline) in self.pipelines.iter().enumerate() { - match undefined_pipeline { - Pipeline::Compute(ref pipeline) => { - puffin::profile_scope!("Compute Pass", format!("iteration {}", i).as_str()); - - let cmd_buf = pipeline.command_buffer; - unsafe { - self.device.reset_command_buffer( - cmd_buf, - vk::CommandBufferResetFlags::RELEASE_RESOURCES, - ) - }?; - unsafe { - let command_buffer_begin_info = vk::CommandBufferBeginInfo::builder() - .flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT); - self.device - .begin_command_buffer(cmd_buf, &command_buffer_begin_info)?; - - if self.paused { - { - puffin::profile_scope!( - "Blit to Prev Frame", - format!("iteratioin {}", i).as_str() - ); - self.device.blit_image( - cmd_buf, - self.swapchain.images[present_index as usize], - vk::ImageLayout::PRESENT_SRC_KHR, - self.previous_frame.image.image, - vk::ImageLayout::GENERAL, - extent, - ); - } - - self.device.cmd_bind_pipeline( - cmd_buf, - vk::PipelineBindPoint::COMPUTE, - pipeline.pipeline, - ); - self.device.cmd_push_constants( - cmd_buf, - pipeline.pipeline_layout, - vk::ShaderStageFlags::COMPUTE, - 0, - bytemuck::bytes_of(&push_constant), - ); - self.device.cmd_bind_descriptor_sets( - cmd_buf, - vk::PipelineBindPoint::COMPUTE, - pipeline.pipeline_layout, - 0, - &self.descriptor_sets_compute, - &[], - ); - - const SUBGROUP_SIZE: u32 = 16; - self.device.cmd_dispatch( - cmd_buf, - dispatch_optimal_size(extent.width, SUBGROUP_SIZE), - dispatch_optimal_size(extent.height, SUBGROUP_SIZE), - 1, - ); - } - self.device.end_command_buffer(cmd_buf)?; - - let command_buffers = [cmd_buf]; - let wait_semaphores = []; - let signal_semaphores = [pipeline.semaphore]; - let compute_submit_info = [vk::SubmitInfo::builder() - .command_buffers(&command_buffers) - .wait_dst_stage_mask(&[vk::PipelineStageFlags::COMPUTE_SHADER]) - .wait_semaphores(&wait_semaphores) - .signal_semaphores(&signal_semaphores) - .build()]; - self.device.queue_submit( - self.queues.compute_queue.queue, - &compute_submit_info, - vk::Fence::null(), - )?; - - executed_compute_semaphores.push(pipeline.semaphore); - } - } - Pipeline::Graphics(ref pipeline) => { - puffin::profile_scope!("Render Pass", format!("iteration {}", i).as_str()); - - let render_pass_begin_info = vk::RenderPassBeginInfo::builder() - .render_pass(*self.render_pass) - .framebuffer(self.framebuffers[present_index as usize]) - .render_area(vk::Rect2D { - offset: vk::Offset2D { x: 0, y: 0 }, - extent: self.surface.resolution(&self.device)?, - }) - .clear_values(&clear_values); - - let pipeline_layout = pipeline.pipeline_layout; - let wait_mask = &[vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT]; - // Start command queue - unsafe { - self.command_pool.record_submit_commandbuffer( - &self.device, - self.queues.graphics_queue.queue, - wait_mask, - &[ - executed_compute_semaphores.as_slice(), - &[self.present_complete_semaphore], - ] - .concat(), - &[self.rendering_complete_semaphore], - |device, draw_command_buffer| { - device.set_image_layout( - draw_command_buffer, - self.previous_frame.image.image, - vk::ImageLayout::GENERAL, - vk::ImageLayout::GENERAL, - vk::PipelineStageFlags::COMPUTE_SHADER, - vk::PipelineStageFlags::FRAGMENT_SHADER, - ); - - device.cmd_begin_render_pass( - draw_command_buffer, - &render_pass_begin_info, - vk::SubpassContents::INLINE, - ); - device.cmd_bind_pipeline( - draw_command_buffer, - vk::PipelineBindPoint::GRAPHICS, - pipeline.pipeline, - ); - device.cmd_set_viewport(draw_command_buffer, 0, &[self.viewport]); - device.cmd_set_scissor(draw_command_buffer, 0, &[self.scissors]); - device.cmd_bind_descriptor_sets( - draw_command_buffer, - vk::PipelineBindPoint::GRAPHICS, - pipeline.pipeline_layout, - 0, - &self.descriptor_sets_render, - &[], - ); - - device.cmd_push_constants( - draw_command_buffer, - pipeline_layout, - vk::ShaderStageFlags::ALL_GRAPHICS, - 0, - bytemuck::bytes_of(&push_constant), - ); - - // Or draw without the index buffer - device.cmd_draw(draw_command_buffer, 3, 1, 0, 0); - device.cmd_end_render_pass(draw_command_buffer); - - executed_compute_semaphores.clear(); - }, - )?; - } - } - } - } - - let wait_semaphores = [ - self.rendering_complete_semaphore, - self.present_complete_semaphore, - ]; - let swapchains = [self.swapchain.swapchain]; - let image_indices = [present_index]; - let present_info = vk::PresentInfoKHR::builder() - .wait_semaphores(&wait_semaphores) - .swapchains(&swapchains) - .image_indices(&image_indices); - match unsafe { - self.swapchain - .swapchain_loader - .queue_present(self.queues.graphics_queue.queue, &present_info) - } { - Ok(is_suboptimal) if is_suboptimal => { - self.resize()?; - } - Err(vk::Result::ERROR_OUT_OF_DATE_KHR) | Err(vk::Result::SUBOPTIMAL_KHR) => { - self.resize()?; - } - Ok(_) => {} - Err(e) => panic!("Unexpected error on presenting image: {}", e), - } - - Ok(()) - } - - // TODO(#17): Don't use `device_wait_idle` for resizing - // - // Probably Very bad! Consider waiting for approciate command buffers and fences - // (i have no much choice of them) or restrict the amount of resizing events. - pub fn resize(&mut self) -> VkResult<()> { - puffin::profile_function!(); - - unsafe { self.device.device_wait_idle() }?; - - self.resolution = self.surface.resolution(&self.device)?; - let vk::Extent2D { width, height } = self.resolution; - - self.viewport = vk::Viewport { - x: 0., - y: height as f32, - width: width as f32, - height: -(height as f32), - min_depth: 0.0, - max_depth: 1.0, - }; - self.scissors = vk::Rect2D { - offset: vk::Offset2D { x: 0, y: 0 }, - extent: vk::Extent2D { width, height }, - }; - - self.swapchain - .recreate_swapchain((width, height), &self.device)?; - - for &framebuffer in &self.framebuffers { - unsafe { self.device.destroy_framebuffer(framebuffer, None) }; - } - for (i, (framebuffer, present_image)) in self - .framebuffers - .iter_mut() - .zip(&self.swapchain.image_views) - .enumerate() - { - puffin::profile_scope!("Creating Framebuffers", format!("iteration {}", i).as_str()); - let new_framebuffer = VkSwapchain::create_framebuffer( - &[*present_image], - (width, height), - &self.render_pass, - &self.device, - )?; - - *framebuffer = new_framebuffer; - } - - for (i, &image) in self.swapchain.images.iter().enumerate() { - puffin::profile_scope!("Creating Images", format!("iteration {}", i).as_str()); - self.command_pool.record_submit_commandbuffer( - &self.device, - self.queues.graphics_queue.queue, - &[], - &[], - &[], - |device, command_buffer| { - device.set_image_layout( - command_buffer, - image, - vk::ImageLayout::UNDEFINED, - vk::ImageLayout::PRESENT_SRC_KHR, - vk::PipelineStageFlags::TRANSFER, - vk::PipelineStageFlags::TRANSFER, - ); - }, - )?; - } - - self.previous_frame - .resize(&self.device, &self.device_properties.memory, width, height)?; - self.generic_texture - .resize(&self.device, &self.device_properties.memory, width, height)?; - self.dummy_texture - .resize(&self.device, &self.device_properties.memory, width, height)?; - self.float_texture1 - .resize(&self.device, &self.device_properties.memory, width, height)?; - self.float_texture2 - .resize(&self.device, &self.device_properties.memory, width, height)?; - - self.device - .name_image(self.previous_frame.image.image, "Previous Frame Texture")?; - self.device - .name_image(self.generic_texture.image.image, "Generic Texture")?; - self.device - .name_image(self.dummy_texture.image.image, "Dummy Texture")?; - self.device - .name_image(self.float_texture1.image.image, "Float Texture 1")?; - self.device - .name_image(self.float_texture2.image.image, "Float Texture 2")?; - { - let images = [ - self.previous_frame.image.image, - self.generic_texture.image.image, - self.dummy_texture.image.image, - self.float_texture1.image.image, - self.float_texture2.image.image, - ]; - self.command_pool.record_submit_commandbuffer( - &self.device, - self.queues.graphics_queue.queue, - &[], - &[], - &[], - |device, command_buffer| { - for &image in &images { - device.set_image_layout( - command_buffer, - image, - vk::ImageLayout::UNDEFINED, - vk::ImageLayout::GENERAL, - vk::PipelineStageFlags::TRANSFER, - vk::PipelineStageFlags::TRANSFER, - ); - } - }, - )?; - } - - let image_infos = [ - vk::DescriptorImageInfo { - image_layout: vk::ImageLayout::GENERAL, - image_view: self.previous_frame.image_view, - sampler: self.previous_frame.sampler, - }, - vk::DescriptorImageInfo { - image_layout: vk::ImageLayout::GENERAL, - image_view: self.generic_texture.image_view, - sampler: self.generic_texture.sampler, - }, - vk::DescriptorImageInfo { - image_layout: vk::ImageLayout::GENERAL, - image_view: self.dummy_texture.image_view, - sampler: self.dummy_texture.sampler, - }, - vk::DescriptorImageInfo { - image_layout: vk::ImageLayout::GENERAL, - image_view: self.float_texture1.image_view, - sampler: self.float_texture1.sampler, - }, - vk::DescriptorImageInfo { - image_layout: vk::ImageLayout::GENERAL, - image_view: self.float_texture2.image_view, - sampler: self.float_texture2.sampler, - }, - ]; - let desc_types = &[vk::DescriptorType::SAMPLED_IMAGE]; - - AshRender::update_image_bindings( - &self.device, - &[&image_infos], - desc_types, - &self.descriptor_sets_render, - ); - - let desc_types = &[vk::DescriptorType::STORAGE_IMAGE]; - - AshRender::update_image_bindings( - &self.device, - &[&image_infos], - desc_types, - &self.descriptor_sets_compute, - ); - - let extent = Extent3D { - width, - height, - depth: 1, - }; - self.screenshot_ctx - .realloc(&self.device, &self.device_properties, extent)?; - - Ok(()) - } - - pub fn create_compute_pipeline(&self, shader: ShaderCreateInfo) -> VkResult { - let shader_info = vk::ShaderModuleCreateInfo::builder().code(shader.data); - - let comp_module = unsafe { self.device.create_shader_module(&shader_info, None) }?; - - let shader_stage = vk::PipelineShaderStageCreateInfo { - module: comp_module, - p_name: shader.entry_point.as_ptr(), - stage: vk::ShaderStageFlags::COMPUTE, - ..Default::default() - }; - let (pipeline_layout, descriptor_set_layout) = self.create_compute_pipeline_layout()?; - - let new_pipeline = VkComputePipeline::new( - &self.device, - &self.queues, - pipeline_layout, - descriptor_set_layout, - shader_stage, - )?; - - unsafe { - self.device.destroy_shader_module(comp_module, None); - } - - Ok(Pipeline::Compute(new_pipeline)) - } - - pub fn create_render_pipeline( - &self, - vert_code: ShaderCreateInfo, - frag_code: ShaderCreateInfo, - ) -> VkResult { - let vert_module = { - let shader_info = vk::ShaderModuleCreateInfo::builder().code(vert_code.data); - unsafe { self.device.create_shader_module(&shader_info, None) } - }?; - let frag_module = match { - let shader_info = vk::ShaderModuleCreateInfo::builder().code(frag_code.data); - unsafe { self.device.create_shader_module(&shader_info, None) } - } { - Ok(module) => module, - Err(e) => { - unsafe { self.device.destroy_shader_module(vert_module, None) }; - return Err(e); - } - }; - - let (pipeline_layout, descriptor_set_layout) = self.create_graphics_pipeline_layout()?; - - let desc = PipelineDescriptor::new( - vert_module, - vert_code.entry_point.to_owned(), - frag_module, - frag_code.entry_point.to_owned(), - ); - - let new_pipeline = VkGraphicsPipeline::new( - self.pipeline_cache, - pipeline_layout, - descriptor_set_layout, - desc, - &self.render_pass, - &self.device, - )?; - - unsafe { - self.device.destroy_shader_module(vert_module, None); - self.device.destroy_shader_module(frag_module, None); - } - - Ok(Pipeline::Graphics(new_pipeline)) - } - - pub fn push_compute_pipeline(&mut self, comp: ShaderCreateInfo) -> VkResult<()> { - self.pipelines.push(self.create_compute_pipeline(comp)?); - - Ok(()) - } - - pub fn push_render_pipeline( - &mut self, - vert: ShaderCreateInfo, - frag: ShaderCreateInfo, - ) -> VkResult<()> { - self.pipelines - .push(self.create_render_pipeline(vert, frag)?); - - Ok(()) - } - - pub fn rebuild_compute_pipeline( - &mut self, - index: usize, - comp: ShaderCreateInfo, - ) -> VkResult<()> { - self.pipelines[index] = self.create_compute_pipeline(comp)?; - - Ok(()) - } - - pub fn rebuild_render_pipeline( - &mut self, - index: usize, - vert: ShaderCreateInfo, - frag: ShaderCreateInfo, - ) -> VkResult<()> { - self.pipelines[index] = self.create_render_pipeline(vert, frag)?; - - Ok(()) - } - - pub fn create_graphics_pipeline_layout( - &self, - ) -> VkResult<(vk::PipelineLayout, Vec)> { - let push_constant_ranges = [vk::PushConstantRange::builder() - .offset(0) - .stage_flags(vk::ShaderStageFlags::ALL_GRAPHICS) - .size(self.push_constants_range) - .build()]; - - let descriptor_set_layouts = graphics_desc_set_leyout(&self.device)?; - - let layout_create_info = vk::PipelineLayoutCreateInfo::builder() - .push_constant_ranges(&push_constant_ranges) - .set_layouts(&descriptor_set_layouts) - .build(); - let pipeline_layout = unsafe { - self.device - .create_pipeline_layout(&layout_create_info, None) - }?; - - Ok((pipeline_layout, descriptor_set_layouts)) - } - - pub fn create_compute_pipeline_layout( - &self, - ) -> VkResult<(vk::PipelineLayout, Vec)> { - let push_constant_ranges = [vk::PushConstantRange::builder() - .offset(0) - .stage_flags(vk::ShaderStageFlags::COMPUTE) - .size(self.push_constants_range) - .build()]; - - let descriptor_set_layouts = compute_desc_set_leyout(&self.device)?; - - let layout_create_info = vk::PipelineLayoutCreateInfo::builder() - .push_constant_ranges(&push_constant_ranges) - .set_layouts(&descriptor_set_layouts) - .build(); - let pipeline_layout = unsafe { - self.device - .create_pipeline_layout(&layout_create_info, None) - }?; - - Ok((pipeline_layout, descriptor_set_layouts)) - } - - pub fn capture_frame(&mut self) -> VkResult { - puffin::profile_function!(); - let present_image = self.swapchain.images[self.command_pool.active_command]; - let queue = &self.queues.graphics_queue; - self.screenshot_ctx.capture_frame( - &self.device, - &self.device_properties, - present_image, - queue, - ) - } - - #[allow(dead_code)] - pub fn update_fft_texture(&mut self, data: &[f32]) -> VkResult<()> { - self.fft_texture - .update(data, &self.device, &self.queues.transfer_queue) - } - - pub fn screenshot_layout(&self) -> SubresourceLayout { - self.screenshot_ctx.image_dimentions(&self.device).0 - } - pub fn screenshot_dimentions(&self) -> ImageDimentions { - self.screenshot_ctx.image_dimentions(&self.device).1 - } -} - -impl<'a> Drop for AshRender<'a> { - fn drop(&mut self) { - unsafe { - for layout in &self.descriptor_set_layouts { - self.device.destroy_descriptor_set_layout(*layout, None); - } - for layout in &self.descriptor_set_layouts_compute { - self.device.destroy_descriptor_set_layout(*layout, None); - } - self.device - .destroy_descriptor_pool(self.descriptor_pool, None); - - self.fft_texture.destroy(&self.device); - - self.device.destroy_sampler(self.sampler, None); - - self.float_texture1.destroy(&self.device); - self.float_texture2.destroy(&self.device); - self.previous_frame.destroy(&self.device); - self.generic_texture.destroy(&self.device); - self.dummy_texture.destroy(&self.device); - - self.screenshot_ctx.destroy(&self.device); - self.device - .destroy_pipeline_cache(self.pipeline_cache, None); - - self.device - .destroy_semaphore(self.present_complete_semaphore, None); - self.device - .destroy_semaphore(self.rendering_complete_semaphore, None); - - for &framebuffer in &self.framebuffers { - self.device.destroy_framebuffer(framebuffer, None); - } - } - } -} diff --git a/pilka_ash/src/renderer/images.rs b/pilka_ash/src/renderer/images.rs deleted file mode 100644 index 0b28283..0000000 --- a/pilka_ash/src/renderer/images.rs +++ /dev/null @@ -1,362 +0,0 @@ -use crate::pvk::{VkCommandPool, VkDevice, VkDeviceProperties, VkQueue}; -use ash::{prelude::VkResult, vk}; - -const FFT_SIZE: u32 = 1024 * 2; - -#[derive(Debug)] -pub(crate) struct VkImage { - pub image: vk::Image, - pub memory: vk::DeviceMemory, - pub memory_requirements: vk::MemoryRequirements, -} - -impl VkImage { - pub fn new( - device: &VkDevice, - memory_properties: &vk::PhysicalDeviceMemoryProperties, - image_create_info: &vk::ImageCreateInfo, - image_memory_flags: vk::MemoryPropertyFlags, - ) -> VkResult { - let image = unsafe { device.create_image(image_create_info, None) }?; - let memory_reqs = unsafe { device.get_image_memory_requirements(image) }; - - let memory = device.alloc_memory(memory_properties, memory_reqs, image_memory_flags)?; - unsafe { device.bind_image_memory(image, memory, 0) }?; - Ok(Self { - image, - memory, - memory_requirements: memory_reqs, - }) - } -} - -#[derive(Debug)] -pub(crate) struct VkTexture { - pub image: VkImage, - pub image_view: vk::ImageView, - pub sampler: vk::Sampler, - pub usage_flags: vk::ImageUsageFlags, - pub format: vk::Format, -} - -impl VkTexture { - pub fn new( - device: &VkDevice, - memory_properties: &vk::PhysicalDeviceMemoryProperties, - image_create_info: &vk::ImageCreateInfo, - image_memory_flags: vk::MemoryPropertyFlags, - sampler_create_info: &vk::SamplerCreateInfo, - ) -> VkResult { - let image = VkImage::new( - device, - memory_properties, - image_create_info, - image_memory_flags, - )?; - let image_view_info = vk::ImageViewCreateInfo::builder() - .image(image.image) - .format(image_create_info.format) - .view_type(vk::ImageViewType::TYPE_2D) - .subresource_range(vk::ImageSubresourceRange { - aspect_mask: vk::ImageAspectFlags::COLOR, - base_mip_level: 0, - level_count: 1, - base_array_layer: 0, - layer_count: 1, - }); - let image_view = unsafe { device.create_image_view(&image_view_info, None) }?; - let sampler = unsafe { device.create_sampler(sampler_create_info, None) }?; - - Ok(Self { - image, - image_view, - sampler, - usage_flags: image_create_info.usage, - format: image_create_info.format, - }) - } - - pub fn resize( - &mut self, - device: &VkDevice, - memory_properties: &vk::PhysicalDeviceMemoryProperties, - width: u32, - height: u32, - ) -> VkResult<()> { - self.destroy(device); - let extent = vk::Extent3D { - width, - height, - depth: 1, - }; - let image_create_info = vk::ImageCreateInfo::builder() - .format(self.format) - .image_type(vk::ImageType::TYPE_2D) - .extent(extent) - .array_layers(1) - .mip_levels(1) - .samples(vk::SampleCountFlags::TYPE_1) - .tiling(vk::ImageTiling::OPTIMAL) - .usage(self.usage_flags) - .sharing_mode(vk::SharingMode::EXCLUSIVE) - .initial_layout(vk::ImageLayout::UNDEFINED); - let image_memory_flags = vk::MemoryPropertyFlags::DEVICE_LOCAL; - - let sampler_create_info = vk::SamplerCreateInfo::builder() - .mag_filter(vk::Filter::NEAREST) - .min_filter(vk::Filter::NEAREST) - .address_mode_u(vk::SamplerAddressMode::REPEAT) - .address_mode_v(vk::SamplerAddressMode::REPEAT) - .address_mode_w(vk::SamplerAddressMode::REPEAT) - .anisotropy_enable(false) - .max_anisotropy(0.); - - *self = Self::new( - device, - memory_properties, - &image_create_info, - image_memory_flags, - &sampler_create_info, - )?; - - Ok(()) - } - - pub fn destroy(&mut self, device: &VkDevice) { - unsafe { - device.destroy_sampler(self.sampler, None); - device.destroy_image_view(self.image_view, None); - device.destroy_image(self.image.image, None); - device.free_memory(self.image.memory, None); - } - } -} - -pub(crate) struct FftTexture<'a> { - pub texture: VkTexture, - staging_buffer: vk::Buffer, - staging_buffer_memory: vk::DeviceMemory, - mapped_memory: &'a mut [f32], - command_buffer: vk::CommandBuffer, - fence: vk::Fence, -} - -impl<'a> FftTexture<'a> { - pub fn new( - device: &VkDevice, - device_properties: &VkDeviceProperties, - command_pool: &VkCommandPool, - ) -> VkResult { - let extent = vk::Extent3D { - width: FFT_SIZE, - height: 1, - depth: 1, - }; - let image_create_info = vk::ImageCreateInfo::builder() - .format(vk::Format::R32_SFLOAT) - .image_type(vk::ImageType::TYPE_1D) - .extent(extent) - .array_layers(1) - .mip_levels(1) - .samples(vk::SampleCountFlags::TYPE_1) - .tiling(vk::ImageTiling::OPTIMAL) - .usage( - vk::ImageUsageFlags::SAMPLED - | vk::ImageUsageFlags::STORAGE - | vk::ImageUsageFlags::TRANSFER_DST, - ) - .sharing_mode(vk::SharingMode::EXCLUSIVE) - .initial_layout(vk::ImageLayout::UNDEFINED); - let image_memory_flags = vk::MemoryPropertyFlags::DEVICE_LOCAL; - let sampler_create_info = vk::SamplerCreateInfo::builder() - .mag_filter(vk::Filter::LINEAR) - .min_filter(vk::Filter::LINEAR) - .address_mode_u(vk::SamplerAddressMode::REPEAT) - .address_mode_v(vk::SamplerAddressMode::REPEAT) - .address_mode_w(vk::SamplerAddressMode::REPEAT) - .anisotropy_enable(false) - .max_anisotropy(0.); - let image = VkImage::new( - device, - &device_properties.memory, - &image_create_info, - image_memory_flags, - )?; - let image_view_info = vk::ImageViewCreateInfo::builder() - .image(image.image) - .format(image_create_info.format) - .view_type(vk::ImageViewType::TYPE_1D) - .subresource_range(vk::ImageSubresourceRange { - aspect_mask: vk::ImageAspectFlags::COLOR, - base_mip_level: 0, - level_count: 1, - base_array_layer: 0, - layer_count: 1, - }); - let image_view = unsafe { device.create_image_view(&image_view_info, None) }?; - let sampler = unsafe { device.create_sampler(&sampler_create_info, None) }?; - let texture = VkTexture { - image, - sampler, - image_view, - usage_flags: image_create_info.usage, - format: image_create_info.format, - }; - - let size = (FFT_SIZE as usize * std::mem::size_of::()) as u64; - let buffer_create_info = vk::BufferCreateInfo::builder() - .size(size) - .usage(vk::BufferUsageFlags::TRANSFER_SRC) - .sharing_mode(vk::SharingMode::EXCLUSIVE); - let staging_buffer = unsafe { device.create_buffer(&buffer_create_info, None) }?; - - let staging_buffer_mem_reqs = - unsafe { device.get_buffer_memory_requirements(staging_buffer) }; - - let staging_buffer_memory = device.alloc_memory( - &device_properties.memory, - staging_buffer_mem_reqs, - vk::MemoryPropertyFlags::HOST_VISIBLE - | vk::MemoryPropertyFlags::HOST_COHERENT - | vk::MemoryPropertyFlags::HOST_CACHED, - )?; - unsafe { device.bind_buffer_memory(staging_buffer, staging_buffer_memory, 0) }?; - - let mapped_memory = unsafe { - std::slice::from_raw_parts_mut::( - device.map_memory( - staging_buffer_memory, - 0, - staging_buffer_mem_reqs.size, - vk::MemoryMapFlags::empty(), - )? as _, - FFT_SIZE as _, - ) - }; - - let command_buffer_allocate_info = vk::CommandBufferAllocateInfo::builder() - .command_buffer_count(1) - .command_pool(command_pool.pool) - .level(vk::CommandBufferLevel::PRIMARY); - - let command_buffer = - unsafe { device.allocate_command_buffers(&command_buffer_allocate_info) }?[0]; - - let fence = device.create_fence(true)?; - - Ok(Self { - texture, - staging_buffer, - staging_buffer_memory, - mapped_memory, - command_buffer, - fence, - }) - } - - pub fn update( - &mut self, - data: &[f32], - device: &VkDevice, - submit_queue: &VkQueue, - ) -> VkResult<()> { - let regions = [vk::BufferImageCopy { - image_offset: vk::Offset3D { x: 0, y: 0, z: 0 }, - image_extent: vk::Extent3D { - width: FFT_SIZE, - height: 1, - depth: 1, - }, - buffer_offset: 0, - buffer_row_length: FFT_SIZE, - buffer_image_height: 1, - image_subresource: vk::ImageSubresourceLayers { - aspect_mask: vk::ImageAspectFlags::COLOR, - layer_count: 1, - base_array_layer: 0, - mip_level: 0, - }, - }]; - let subresource_range = vk::ImageSubresourceRange { - aspect_mask: vk::ImageAspectFlags::COLOR, - base_mip_level: 0, - level_count: 1, - base_array_layer: 0, - layer_count: 1, - }; - let submit_fence = self.fence; - let command_buffer = self.command_buffer; - - unsafe { device.wait_for_fences(&[submit_fence], true, std::u64::MAX) }?; - unsafe { device.reset_fences(&[submit_fence]) }?; - - unsafe { - device.reset_command_buffer( - command_buffer, - vk::CommandBufferResetFlags::RELEASE_RESOURCES, - ) - }?; - - let command_buffer_begin_info = vk::CommandBufferBeginInfo::builder() - .flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT); - - unsafe { device.begin_command_buffer(command_buffer, &command_buffer_begin_info) }?; - - let image = self.texture.image.image; - let barrier = |old_layout, new_layout, sq, dq| { - device.set_image_layout_with_subresource( - command_buffer, - image, - old_layout, - new_layout, - subresource_range, - vk::PipelineStageFlags::TRANSFER, - vk::PipelineStageFlags::TRANSFER, - Some(sq), - Some(dq), - ) - }; - - barrier( - vk::ImageLayout::GENERAL, - vk::ImageLayout::TRANSFER_DST_OPTIMAL, - submit_queue.index, - submit_queue.index, - ); - self.mapped_memory.copy_from_slice(data); - unsafe { - device.cmd_copy_buffer_to_image( - command_buffer, - self.staging_buffer, - image, - vk::ImageLayout::TRANSFER_DST_OPTIMAL, - ®ions, - ); - } - barrier( - vk::ImageLayout::TRANSFER_DST_OPTIMAL, - vk::ImageLayout::GENERAL, - submit_queue.index, - submit_queue.index, - ); - - unsafe { device.end_command_buffer(command_buffer) }?; - - let command_buffers = [command_buffer]; - - let submit_info = vk::SubmitInfo::builder().command_buffers(&command_buffers); - - unsafe { device.queue_submit(submit_queue.queue, &[submit_info.build()], submit_fence) }?; - - Ok(()) - } - - pub fn destroy(&mut self, device: &VkDevice) { - unsafe { - device.destroy_fence(self.fence, None); - self.texture.destroy(device); - device.free_memory(self.staging_buffer_memory, None); - device.destroy_buffer(self.staging_buffer, None); - } - } -} diff --git a/pilka_ash/src/renderer/screenshot.rs b/pilka_ash/src/renderer/screenshot.rs deleted file mode 100644 index 595e0cc..0000000 --- a/pilka_ash/src/renderer/screenshot.rs +++ /dev/null @@ -1,381 +0,0 @@ -use super::images::VkImage; -use crate::{ - pvk::{VkCommandPool, VkDevice, VkDeviceProperties}, - VkQueue, -}; -use ash::{ - prelude::VkResult, - vk::{self, SubresourceLayout}, -}; -use pilka_types::{Frame, ImageDimentions}; - -pub struct ScreenshotCtx<'a> { - fence: vk::Fence, - commbuf: vk::CommandBuffer, - image: VkImage, - blit_image: Option, - extent: vk::Extent3D, - format: vk::Format, - pub data: &'a [u8], -} - -impl<'a> ScreenshotCtx<'a> { - pub fn new( - device: &VkDevice, - memory_properties: &vk::PhysicalDeviceMemoryProperties, - command_pool: &VkCommandPool, - extent: vk::Extent2D, - src_format: vk::Format, - need2steps: bool, - ) -> VkResult { - let commandbuf_allocate_info = vk::CommandBufferAllocateInfo::builder() - .command_pool(command_pool.pool) - .level(vk::CommandBufferLevel::PRIMARY) - .command_buffer_count(1); - let commbuf = unsafe { device.allocate_command_buffers(&commandbuf_allocate_info) }?[0]; - let fence = device.create_fence(false)?; - let extent = vk::Extent3D { - width: extent.width, - height: extent.height + extent.height % 2, - depth: 1, - }; - - let dst_format = match src_format { - vk::Format::B8G8R8A8_SRGB => vk::Format::R8G8B8A8_SRGB, - vk::Format::B8G8R8A8_UNORM => vk::Format::R8G8B8_UNORM, - vk::Format::B8G8R8A8_UINT => vk::Format::R8G8B8A8_UINT, - vk::Format::B8G8R8A8_SINT => vk::Format::R8G8B8A8_SINT, - vk::Format::B8G8R8A8_SNORM => vk::Format::R8G8B8A8_SNORM, - vk::Format::B8G8R8A8_USCALED => vk::Format::R8G8B8A8_USCALED, - vk::Format::B8G8R8A8_SSCALED => vk::Format::R8G8B8A8_SSCALED, - _ => vk::Format::R8G8B8_UNORM, - }; - let mut image_create_info = vk::ImageCreateInfo::builder() - .format(dst_format) - .image_type(vk::ImageType::TYPE_2D) - .extent(extent) - .array_layers(1) - .mip_levels(1) - .samples(vk::SampleCountFlags::TYPE_1) - .tiling(vk::ImageTiling::LINEAR) - .usage(vk::ImageUsageFlags::TRANSFER_DST) - .sharing_mode(vk::SharingMode::EXCLUSIVE) - .initial_layout(vk::ImageLayout::UNDEFINED); - let mut image_memory_flags = vk::MemoryPropertyFlags::HOST_VISIBLE - | vk::MemoryPropertyFlags::HOST_CACHED - | vk::MemoryPropertyFlags::HOST_COHERENT; - - let blit_image = if need2steps { - let image = VkImage::new( - device, - memory_properties, - &image_create_info, - image_memory_flags, - )?; - image_create_info.tiling = vk::ImageTiling::OPTIMAL; - image_create_info.usage = - vk::ImageUsageFlags::TRANSFER_DST | vk::ImageUsageFlags::TRANSFER_SRC; - image_memory_flags = vk::MemoryPropertyFlags::DEVICE_LOCAL; - Some(image) - } else { - None - }; - - let image = VkImage::new( - device, - memory_properties, - &image_create_info, - image_memory_flags, - )?; - let data = unsafe { - let image = if let Some(ref blit_image) = blit_image { - blit_image - } else { - &image - }; - std::slice::from_raw_parts_mut( - device.map_memory( - image.memory, - 0, - image.memory_requirements.size, - vk::MemoryMapFlags::empty(), - )? as *mut u8, - image.memory_requirements.size as usize, - ) - }; - - Ok(Self { - fence, - commbuf, - image, - blit_image, - data, - extent, - format: dst_format, - }) - } - - pub fn destroy(&mut self, device: &VkDevice) { - unsafe { - if let Some(ref blit_image) = self.blit_image { - device.unmap_memory(blit_image.memory); - - device.free_memory(blit_image.memory, None); - device.destroy_image(blit_image.image, None); - } else { - device.unmap_memory(self.image.memory); - } - device.destroy_fence(self.fence, None); - device.destroy_image(self.image.image, None); - device.free_memory(self.image.memory, None); - } - } - - pub fn realloc( - &mut self, - device: &VkDevice, - device_properties: &VkDeviceProperties, - mut extent: vk::Extent3D, - ) -> VkResult<()> { - puffin::profile_function!(); - - if self.extent != extent { - extent.height = extent.height + extent.height % 2; - self.extent = extent; - - unsafe { device.destroy_image(self.image.image, None) }; - - let mut image_create_info = vk::ImageCreateInfo::builder() - .format(self.format) - .image_type(vk::ImageType::TYPE_2D) - .extent(extent) - .array_layers(1) - .mip_levels(1) - .samples(vk::SampleCountFlags::TYPE_1) - .tiling(vk::ImageTiling::LINEAR) - .usage(vk::ImageUsageFlags::TRANSFER_DST) - .sharing_mode(vk::SharingMode::EXCLUSIVE) - .initial_layout(vk::ImageLayout::UNDEFINED); - let mut image_memory_flags = vk::MemoryPropertyFlags::HOST_VISIBLE - | vk::MemoryPropertyFlags::HOST_CACHED - | vk::MemoryPropertyFlags::HOST_COHERENT; - - if let Some(ref mut blit_image) = self.blit_image { - unsafe { device.destroy_image(blit_image.image, None) }; - - blit_image.image = unsafe { device.create_image(&image_create_info, None) }?; - blit_image.memory_requirements = - unsafe { device.get_image_memory_requirements(blit_image.image) }; - image_create_info.tiling = vk::ImageTiling::OPTIMAL; - image_create_info.usage = - vk::ImageUsageFlags::TRANSFER_DST | vk::ImageUsageFlags::TRANSFER_SRC; - } - - self.image.image = unsafe { device.create_image(&image_create_info, None)? }; - self.image.memory_requirements = - unsafe { device.get_image_memory_requirements(self.image.image) }; - - if (extent.width * extent.height * 4) as usize > self.data.len() { - if let Some(ref mut blit_image) = self.blit_image { - unsafe { device.unmap_memory(blit_image.memory) }; - unsafe { device.free_memory(blit_image.memory, None) } - blit_image.memory = device.alloc_memory( - &device_properties.memory, - blit_image.memory_requirements, - image_memory_flags, - )?; - image_memory_flags = vk::MemoryPropertyFlags::DEVICE_LOCAL; - } else { - unsafe { device.unmap_memory(self.image.memory) }; - } - unsafe { device.free_memory(self.image.memory, None) } - - self.image.memory = device.alloc_memory( - &device_properties.memory, - self.image.memory_requirements, - image_memory_flags, - )?; - - self.data = unsafe { - let image = if let Some(ref blit_image) = self.blit_image { - blit_image - } else { - &self.image - }; - std::slice::from_raw_parts_mut( - device.map_memory( - image.memory, - 0, - image.memory_requirements.size, - vk::MemoryMapFlags::empty(), - )? as *mut u8, - image.memory_requirements.size as usize, - ) - } - } - - if let Some(ref mut blit_image) = self.blit_image { - unsafe { device.bind_image_memory(blit_image.image, blit_image.memory, 0) }?; - } - unsafe { device.bind_image_memory(self.image.image, self.image.memory, 0) }?; - } - - Ok(()) - } - - pub fn capture_frame( - &mut self, - device: &VkDevice, - device_properties: &VkDeviceProperties, - present_image: ash::vk::Image, - queue: &VkQueue, - ) -> VkResult { - puffin::profile_function!(); - - let copybuffer = self.commbuf; - unsafe { - device.reset_command_buffer(copybuffer, vk::CommandBufferResetFlags::RELEASE_RESOURCES) - }?; - let cmd_begininfo = vk::CommandBufferBeginInfo::builder() - .flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT); - unsafe { device.begin_command_buffer(copybuffer, &cmd_begininfo) }?; - - let extent = self.extent; - - self.realloc(device, device_properties, extent)?; - - // let present_image = self.swapchain.images[self.command_pool.active_command]; - let copy_image = self.image.image; - let dst_stage = vk::PipelineStageFlags::TRANSFER; - let src_stage = vk::PipelineStageFlags::TRANSFER; - - let transport_barrier = |image, old_layout, new_layout| { - device.set_image_layout( - copybuffer, image, old_layout, new_layout, src_stage, dst_stage, - ) - }; - - use vk::ImageLayout; - transport_barrier( - present_image, - ImageLayout::PRESENT_SRC_KHR, - ImageLayout::TRANSFER_SRC_OPTIMAL, - ); - transport_barrier( - copy_image, - ImageLayout::UNDEFINED, - ImageLayout::TRANSFER_DST_OPTIMAL, - ); - - let offset = [ - vk::Offset3D { x: 0, y: 0, z: 0 }, - vk::Offset3D { - x: extent.width as i32, - y: extent.height as i32, - z: extent.depth as i32, - }, - ]; - let blit_region = [vk::ImageBlit::builder() - .src_subresource(vk::ImageSubresourceLayers { - aspect_mask: vk::ImageAspectFlags::COLOR, - base_array_layer: 0, - layer_count: 1, - mip_level: 0, - }) - .dst_subresource(vk::ImageSubresourceLayers { - aspect_mask: vk::ImageAspectFlags::COLOR, - base_array_layer: 0, - layer_count: 1, - mip_level: 0, - }) - .src_offsets(offset) - .dst_offsets(offset) - .build()]; - - unsafe { - puffin::profile_scope!("Cmd Blit"); - device.cmd_blit_image( - copybuffer, - present_image, - vk::ImageLayout::TRANSFER_SRC_OPTIMAL, - copy_image, - vk::ImageLayout::TRANSFER_DST_OPTIMAL, - blit_region.as_ref(), - vk::Filter::NEAREST, - ) - }; - - if let Some(ref blit_image) = self.blit_image { - puffin::profile_scope!("Extra Copy"); - transport_barrier( - blit_image.image, - ImageLayout::UNDEFINED, - ImageLayout::TRANSFER_DST_OPTIMAL, - ); - - transport_barrier( - copy_image, - ImageLayout::TRANSFER_DST_OPTIMAL, - ImageLayout::TRANSFER_SRC_OPTIMAL, - ); - - device.copy_image(copybuffer, copy_image, blit_image.image, self.extent); - } - - transport_barrier( - if let Some(ref blit_image) = self.blit_image { - blit_image.image - } else { - copy_image - }, - ImageLayout::TRANSFER_DST_OPTIMAL, - ImageLayout::GENERAL, - ); - - transport_barrier( - present_image, - ImageLayout::TRANSFER_SRC_OPTIMAL, - ImageLayout::PRESENT_SRC_KHR, - ); - - unsafe { device.end_command_buffer(copybuffer) }?; - let submit_commbuffers = [copybuffer]; - let submit_infos = [vk::SubmitInfo::builder() - .command_buffers(&submit_commbuffers) - .build()]; - unsafe { device.queue_submit(queue.queue, &submit_infos, self.fence) }?; - unsafe { device.wait_for_fences(&[self.fence], true, u64::MAX) }?; - unsafe { device.reset_fences(&[self.fence]) }?; - - let (subresource_layout, image_dimentions) = self.image_dimentions(device); - - Ok(( - self.data[..subresource_layout.size as _].to_vec(), - image_dimentions, - )) - } - - pub fn image_dimentions(&self, device: &VkDevice) -> (SubresourceLayout, ImageDimentions) { - let image = if let Some(ref blit_image) = self.blit_image { - blit_image - } else { - &self.image - }; - let image_dimentions = ImageDimentions::new( - self.extent.width, - self.extent.height, - image.memory_requirements.alignment as _, - ); - let subresource_layout = unsafe { - device.get_image_subresource_layout( - image.image, - vk::ImageSubresource { - aspect_mask: vk::ImageAspectFlags::COLOR, - mip_level: 0, - array_layer: 0, - }, - ) - }; - (subresource_layout, image_dimentions) - } -} diff --git a/pilka_types/Cargo.toml b/pilka_types/Cargo.toml deleted file mode 100644 index d7adf31..0000000 --- a/pilka_types/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "pilka_types" -version = "0.7.10" -edition = "2021" -authors = ["Alex Komissarov "] -description = "Pilka types" -license = "MIT" -keywords = ["graphics"] - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -bytemuck = { version = "1.7.3", features = ["derive"] } diff --git a/pilka_types/src/lib.rs b/pilka_types/src/lib.rs deleted file mode 100644 index e1d42b1..0000000 --- a/pilka_types/src/lib.rs +++ /dev/null @@ -1,252 +0,0 @@ -#![allow(clippy::new_without_default)] - -use bytemuck::{Pod, Zeroable}; - -use std::{ - collections::{HashMap, HashSet}, - ffi::{CStr, CString}, - hash::Hash, - ops::{Deref, DerefMut}, - path::PathBuf, - time::Duration, -}; - -pub fn dispatch_optimal_size(len: u32, subgroup_size: u32) -> u32 { - let padded_size = (subgroup_size - len % subgroup_size) % subgroup_size; - (len + padded_size) / subgroup_size -} - -pub type Frame = (Vec, ImageDimentions); - -pub enum ShaderData { - Render { vert: Vec, frag: Vec }, - Compute(Vec), -} - -#[derive(Debug, Clone)] -pub struct ShaderCreateInfo<'a> { - pub data: &'a [u32], - pub entry_point: &'a CStr, -} - -impl<'a> ShaderCreateInfo<'a> { - pub fn new(data: &'a [u32], entry_point: &'a CStr) -> Self { - Self { data, entry_point } - } -} - -#[derive(Debug, Clone)] -pub enum PipelineInfo { - Rendering { vert: ShaderInfo, frag: ShaderInfo }, - Compute { comp: ShaderInfo }, -} - -#[derive(Hash, Debug, Clone, Copy)] -pub enum ShaderFlavor { - Glsl, - Wgsl, -} - -#[derive(Hash, Debug, Clone)] -pub struct ShaderInfo { - pub path: PathBuf, - pub entry_point: CString, - pub flavour: ShaderFlavor, -} - -impl ShaderInfo { - pub fn new(path: PathBuf, entry_point: String, flavour: ShaderFlavor) -> ShaderInfo { - ShaderInfo { - path, - entry_point: CString::new(entry_point).unwrap(), - flavour, - } - } -} - -#[derive(Hash, Debug, Clone)] -pub enum ShaderType { - Glsl, - Wgsl, - Spir, -} - -#[derive(Hash, Debug, Clone)] -pub enum ShaderStage { - Vertex = 0, - Fragment, - Compute, -} - -#[derive(Debug, Clone, Copy)] -pub struct ImageDimentions { - pub width: u32, - pub height: u32, - pub unpadded_bytes_per_row: u32, - pub padded_bytes_per_row: u32, -} - -impl ImageDimentions { - pub fn new(width: u32, height: u32, align: u32) -> Self { - let bytes_per_pixel = std::mem::size_of::<[u8; 4]>() as u32; - let unpadded_bytes_per_row = width * bytes_per_pixel; - let row_padding = (align - unpadded_bytes_per_row % align) % align; - let padded_bytes_per_row = unpadded_bytes_per_row + row_padding; - Self { - width, - height, - unpadded_bytes_per_row, - padded_bytes_per_row, - } - } - - pub fn linear_size(&self) -> u64 { - self.padded_bytes_per_row as u64 * self.height as u64 - } -} - -/// A hash map with a [HashSet](std::collections::HashSet) to hold unique values -#[derive(Debug)] -pub struct ContiniousHashMap(HashMap>); - -impl Deref for ContiniousHashMap { - type Target = HashMap>; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for ContiniousHashMap { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -impl ContiniousHashMap { - /// Creates an empty [ContiniousHashMap] - /// - /// The hash map is initially created with a capacity of 0, - /// so it will not allocate until it is first inserted into. - pub fn new() -> Self { - Self(HashMap::new()) - } -} - -impl ContiniousHashMap { - /// Inserts a key-value pair into the map. - /// - /// If the mep already contain this key this method will add - /// a value instead of rewriting an old value. - pub fn push_value(&mut self, key: K, value: V) { - self.0.entry(key).or_insert_with(HashSet::new).insert(value); - } -} - -#[repr(C)] -#[derive(Debug, Clone, Copy, Pod, Zeroable)] -pub struct PushConstant { - pub pos: [f32; 3], - pub time: f32, - pub wh: [f32; 2], - pub mouse: [f32; 2], - pub mouse_pressed: u32, - pub frame: u32, - pub time_delta: f32, - pub record_period: f32, -} - -impl PushConstant { - pub fn as_slice(&self) -> &[u8] { - unsafe { any_as_u8_slice(self) } - } - - pub fn size() -> u32 { - std::mem::size_of::() as _ - } -} - -/// # Safety -/// Until you're using it on not ZST or DST it's fine -pub unsafe fn any_as_u8_slice(p: &T) -> &[u8] { - std::slice::from_raw_parts((p as *const T) as *const _, std::mem::size_of::()) -} - -impl Default for PushConstant { - fn default() -> Self { - Self { - pos: [0.; 3], - time: 0., - wh: [1920.0, 780.], - mouse: [0.; 2], - mouse_pressed: false as _, - frame: 0, - time_delta: 1. / 60., - record_period: 10., - } - } -} - -impl std::fmt::Display for PushConstant { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let time = Duration::from_secs_f32(self.time); - let time_delta = Duration::from_secs_f32(self.time_delta); - write!( - f, - "position:\t{:?}\n\ - time:\t\t{:#.2?}\n\ - time delta:\t{:#.3?}, fps: {:#.2?}\n\ - width, height:\t{:?}\nmouse:\t\t{:.2?}\n\ - frame:\t\t{}\nrecord_period:\t{}\n", - self.pos, - time, - time_delta, - 1. / self.time_delta, - self.wh, - self.mouse, - self.frame, - self.record_period - ) - } -} - -#[repr(C)] -#[derive(Default, Debug, Clone, Copy, Pod, Zeroable)] -pub struct Uniform { - pub pos: [f32; 3], - _padding: f32, - pub wh: [f32; 2], - pub mouse: [f32; 2], - pub mouse_pressed: u32, - pub time: f32, - pub time_delta: f32, - pub frame: u32, - pub record_period: f32, - _padding2: [f32; 3], -} - -impl From for Uniform { - fn from( - PushConstant { - pos, - wh, - mouse, - mouse_pressed, - time, - time_delta, - frame, - record_period, - }: PushConstant, - ) -> Self { - Self { - pos, - wh, - mouse, - mouse_pressed, - time, - time_delta, - frame, - record_period, - ..Default::default() - } - } -} diff --git a/pilka_wgpu/Cargo.toml b/pilka_wgpu/Cargo.toml deleted file mode 100644 index 5ca7dbf..0000000 --- a/pilka_wgpu/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -name = "pilka_wgpu" -version = "0.7.11" -edition = "2021" -authors = ["Alex Komissarov "] -license = "MIT" -description = "Homebrew and probably-not-so-great wgpu renderer" -repository = "https://github.com/pudnax/pilka/" -readme = "README.md" -keywords = ["graphics", "glsl", "shaders", "creative", "wgpu"] -categories = ["graphics", "rendering"] - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -wgpu = { version = "0.14.0", features = ["spirv"] } -raw-window-handle = "0.5.0" -bytemuck = { version = "1.12.1", features = ["derive"] } -color-eyre = "0.6.2" -env_logger = "0.9.1" -pilka_types = { version = "0.7.1", path = "../pilka_types" } -puffin = "0.13.3" -pollster = "0.2.5" -smaa = "0.8.0" -# smaa = { git = "https://github.com/pudnax/smaa-rs", branch = "webgpu12" } -# naga = { git = "https://github.com/gfx-rs/naga", branch = "master", features = ["glsl-in", -# "wgsl-in", "spv-in", "span", "spv-out", "wgsl-out", "glsl-validate"] } - -[dev-dependencies] -winit = "0.27.4" -notify = "5.0.0" diff --git a/pilka_wgpu/README.md b/pilka_wgpu/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/pilka_wgpu/examples/run.rs b/pilka_wgpu/examples/run.rs deleted file mode 100644 index 22481f3..0000000 --- a/pilka_wgpu/examples/run.rs +++ /dev/null @@ -1,132 +0,0 @@ -use color_eyre::*; -use notify::Config; -use notify::{event::EventKind, RecursiveMode, Watcher}; -use pilka_types::{PushConstant, ShaderCreateInfo}; -use std::ffi::CString; -use std::path::Path; -use std::time::Instant; -use winit::dpi::PhysicalSize; -use winit::{ - event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent}, - event_loop::ControlFlow, - window::WindowBuilder, -}; - -fn main() -> Result<()> { - env_logger::init(); - color_eyre::install()?; - - let event_loop = winit::event_loop::EventLoop::new(); - let window = WindowBuilder::new() - .with_title("Pilka") - .build(&event_loop)?; - - let PhysicalSize { width, height } = window.inner_size(); - let mut state = pilka_wgpu::WgpuRender::new(&window, PushConstant::size(), width, height)?; - - let shader_v = wgpu::util::make_spirv_raw(include_bytes!("shader.vert.spv")); - let shader_f = wgpu::util::make_spirv_raw(include_bytes!("shader.frag.spv")); - - let entry_point = CString::new("main").unwrap(); - state.push_render_pipeline( - ShaderCreateInfo::new(&shader_v, entry_point.as_c_str()), - ShaderCreateInfo::new(&shader_f, entry_point.as_c_str()), - )?; - - let (tx, rx) = std::sync::mpsc::channel(); - - let mut watcher = notify::recommended_watcher(move |res| match res { - Ok(event) => tx.send(event).unwrap(), - Err(e) => { - eprintln!("Watch error: {:?}", e) - } - })?; - watcher.watch(Path::new("./"), RecursiveMode::Recursive)?; - watcher.configure(Config::PreciseEvents(true))?; - watcher.configure(Config::NoticeEvents(false))?; - - let mut push_constant = PushConstant::default(); - let time = Instant::now(); - - event_loop.run(move |event, _, control_flow| { - *control_flow = ControlFlow::Poll; - - match event { - Event::NewEvents(_) => { - for rx_event in rx.try_iter() { - if let notify::Event { - kind: - EventKind::Access(notify::event::AccessKind::Close( - notify::event::AccessMode::Write, - )), - .. - } = rx_event - { - // match state.rebuild_pipelines(&rx_event.paths) { - // Ok(_) => {} - // Err(e) => eprintln!("{}", e), - // }; - } - } - - push_constant.time = time.elapsed().as_secs_f32(); - } - // Event::DeviceEvent { device_id, event } => {} - Event::WindowEvent { window_id, event } if window_id == window.id() => match event { - WindowEvent::CloseRequested - | WindowEvent::KeyboardInput { - input: - KeyboardInput { - state: ElementState::Pressed, - virtual_keycode: Some(VirtualKeyCode::Escape), - .. - }, - .. - } => *control_flow = ControlFlow::Exit, - WindowEvent::Resized(PhysicalSize { width, height }) => { - state.resize(width, height); - push_constant.wh = [width as _, height as _]; - } - WindowEvent::ScaleFactorChanged { - new_inner_size: PhysicalSize { width, height }, - .. - } => state.resize(*width, *height), - _ => {} - }, - Event::MainEventsCleared => { - if state.render(push_constant).is_ok() {}; - } - Event::LoopDestroyed => {} - _ => {} - } - }); -} - -pub fn make_spirv(data: &[u8]) -> std::borrow::Cow<[u32]> { - const MAGIC_NUMBER: u32 = 0x723_0203; - - assert_eq!( - data.len() % std::mem::size_of::(), - 0, - "data size is not a multiple of 4" - ); - - let words = if data.as_ptr().align_offset(std::mem::align_of::()) == 0 { - let (pre, words, post) = unsafe { data.align_to::() }; - debug_assert!(pre.is_empty()); - debug_assert!(post.is_empty()); - std::borrow::Cow::from(words) - } else { - let mut words = vec![0u32; data.len() / std::mem::size_of::()]; - unsafe { - std::ptr::copy_nonoverlapping(data.as_ptr(), words.as_mut_ptr() as *mut u8, data.len()); - } - std::borrow::Cow::from(words) - }; - assert_eq!( - words[0], MAGIC_NUMBER, - "wrong magic word {:x}. Make sure you are using a binary SPIRV file.", - words[0] - ); - words -} diff --git a/pilka_wgpu/examples/shader.frag b/pilka_wgpu/examples/shader.frag deleted file mode 100644 index 95443c4..0000000 --- a/pilka_wgpu/examples/shader.frag +++ /dev/null @@ -1,112 +0,0 @@ -#version 460 - -// In the beginning, colours never existed. There's nothing that can be done before you... - -layout(location = 0) in vec2 in_uv; -layout(location = 0) out vec4 out_color; - -layout(std430, push_constant) uniform PushConstant { - vec3 pos; - float time; - vec2 resolution; - vec2 mouse; - float spectrum; - bool mouse_pressed; - float time_delta; -} pc; - -#define MAX_DIST 0.1 -const vec3 EPS = vec3(0., 0.01, 0.001); -const float HIT_DIST = EPS.y; -const int MAX_STEPS = 100; -const float MISS_DIST = 10.0; - -mat2 Rot(float a) { - float c = cos(a), s = sin(a); - return mat2(c, -s, s, c); -} - -float sc(vec3 p, float s) { - p = abs(p); - p = max(p, p.yzx); - return min(p.x, min(p.y, p.z)) - s; -} - -float sdTorus(vec3 p, vec2 t) { - vec2 q = vec2(length(p.xz) - t.x, p.y); - return length(q) - t.y; -} - -float worldSDF(in vec3 p) { - float t = pc.time / 5; - p.xz*=Rot(t*5.); - p.xy*=Rot(t*7.); - float scale = 0.6 + .2*sin(t * 10.); - p /= scale; - return sdTorus(p, vec2(1.2, .5)) * scale; -} - -vec3 getRayDir(vec2 uv, vec3 p, vec3 l, float z) { - vec3 f = normalize(l-p), - r = normalize(cross(vec3(0,1,0), f)), - u = cross(f,r), - c = f*z, - i = c + uv.x*r + uv.y*u, - d = normalize(i); - return d; -} - -float scene(vec3 p, float t) { - p.xz *= Rot(t * 5.); - p.xy *= Rot(t * 7.); - float scale = 0.6 + .2 * sin(t * 10.); - p /= scale; - return max(-sc(p, 0.8), length(max(abs(p) - vec3(1.), 0.))) * scale; -} - -vec2 ray_march(vec3 rayPos, vec3 rayDir, float t) { - float dist = 0.0; - - for(int i = 0; i < MAX_STEPS; i++) { - vec3 pos = rayPos + (dist * rayDir); - float posToScene = scene(pos, t); - dist += posToScene; - if(abs(posToScene) < HIT_DIST) return vec2(dist, i); - if(posToScene > MISS_DIST) break; - } - - return vec2(0, MAX_STEPS); -} - -vec3 normal_vec(vec3 p, float t) { - mat3 k = mat3(p, p, p) - mat3(EPS.z); - return normalize(vec3(p - vec3(scene(k[0], t), scene(k[1], t), scene(k[2], t)))); -} - -void main() { - vec2 uv = (in_uv + -0.5) * 2.0 * vec2(pc.resolution.x / pc.resolution.y, 1); - - float t = pc.time / 5; - vec3 ro = vec3(0.0, 0.0, 4.0); - vec3 rd = normalize(vec3(uv, -2.)); - vec3 color = vec3(0); - - for (int i = 0; i < 3; i++) { - vec2 rm = ray_march(ro, rd, t); - float d = rm[0]; - vec3 light = vec3(10, 0.0, 0.0); - vec3 p = ro + rd * d; - if (d > MAX_DIST) { - vec3 n = normal_vec(p, t); - vec3 dir_to_light = normalize(light - p); - vec2 ray_march_light = ray_march(p - dir_to_light * .06, dir_to_light, t); - float dist_to_obstacle = ray_march_light.x; - float dist_to_light = length(light - p); - color[i] = .5 * dot(n, dir_to_light) + 0.5; - } - t += .011; - } - - /* color = vec3(uv, 1.); */ - out_color = vec4(color, 1.0); -} diff --git a/pilka_wgpu/examples/shader.frag.spv b/pilka_wgpu/examples/shader.frag.spv deleted file mode 100644 index 446e02a..0000000 Binary files a/pilka_wgpu/examples/shader.frag.spv and /dev/null differ diff --git a/pilka_wgpu/examples/shader.vert b/pilka_wgpu/examples/shader.vert deleted file mode 100644 index 7fdad8c..0000000 --- a/pilka_wgpu/examples/shader.vert +++ /dev/null @@ -1,8 +0,0 @@ -#version 460 - -layout(location = 0) out vec2 out_uv; - -void main() { - out_uv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); - gl_Position = vec4(out_uv * 2.0f + -1.0f, 0.0, 1.0); -} diff --git a/pilka_wgpu/examples/shader.vert.spv b/pilka_wgpu/examples/shader.vert.spv deleted file mode 100644 index f267163..0000000 Binary files a/pilka_wgpu/examples/shader.vert.spv and /dev/null differ diff --git a/pilka_wgpu/shaders/shader_f.wgsl b/pilka_wgpu/shaders/shader_f.wgsl deleted file mode 100644 index bdad20d..0000000 --- a/pilka_wgpu/shaders/shader_f.wgsl +++ /dev/null @@ -1,8 +0,0 @@ -struct VertexOutput { - [[builtin(position)]] clip_position: vec4; -}; - -[[stage(fragment)]] -fn main(in: VertexOutput) -> [[location(0)]] vec4 { - return vec4(1.0, 0.2, 1.0, 1.0); -} diff --git a/pilka_wgpu/shaders/shader_v.wgsl b/pilka_wgpu/shaders/shader_v.wgsl deleted file mode 100644 index 2f700b9..0000000 --- a/pilka_wgpu/shaders/shader_v.wgsl +++ /dev/null @@ -1,14 +0,0 @@ -struct VertexOutput { - [[builtin(position)]] clip_position: vec4; -}; - -[[stage(vertex)]] -fn main( - [[builtin(vertex_index)]] in_vertex_index: u32, -) -> VertexOutput { - var out: VertexOutput; - let x = f32(1 - i32(in_vertex_index)) * 0.5; - let y = f32(i32(in_vertex_index & 1u) * 2 - 1) * 0.5; - out.clip_position = vec4(x, y, 0.0, 1.0); - return out; -} diff --git a/pilka_wgpu/src/lib.rs b/pilka_wgpu/src/lib.rs deleted file mode 100644 index 55e8847..0000000 --- a/pilka_wgpu/src/lib.rs +++ /dev/null @@ -1,21 +0,0 @@ -#![warn(unsafe_op_in_unsafe_fn)] -#![warn(trivial_casts, trivial_numeric_casts, unused_extern_crates)] -#![allow( - // We use loops for getting early-out of scope without closures. - clippy::never_loop, - // We don't use syntax sugar where it's not necessary. - clippy::match_like_matches_macro, - // Redundant matching is more explicit. - clippy::redundant_pattern_matching, - // Explicit lifetimes are often easier to reason about. - clippy::needless_lifetimes, - // No need for defaults in the internal types. - clippy::new_without_default, - // For some reason `rustc` can warn about these in const generics even - // though they are required. - unused_braces, -)] - -mod renderer; - -pub use renderer::WgpuRender; diff --git a/pilka_wgpu/src/renderer.rs b/pilka_wgpu/src/renderer.rs deleted file mode 100644 index a048cce..0000000 --- a/pilka_wgpu/src/renderer.rs +++ /dev/null @@ -1,898 +0,0 @@ -mod blitter; -mod screenshot; - -use blitter::Blitter; -use screenshot::ScreenshotCtx; - -use std::{fmt::Display, ops::Index, path::PathBuf}; - -use color_eyre::Result; -use pilka_types::{ - dispatch_optimal_size, ContiniousHashMap, Frame, ImageDimentions, PushConstant, - ShaderCreateInfo, Uniform, -}; -use pollster::block_on; -use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle}; -use wgpu::{ - Adapter, BindGroup, BindGroupLayout, BindGroupLayoutDescriptor, ComputePipeline, Device, - PrimitiveState, PrimitiveTopology, Queue, RenderPipeline, Surface, Texture, TextureFormat, - TextureView, -}; - -pub(crate) const SUBGROUP_SIZE: u32 = 16; -const NUM_SAMPLES: u32 = 4; - -pub enum Pipeline { - Render(RenderPipeline), - Compute(ComputePipeline), -} - -enum Binding { - Uniform, - Texture, - Sampler, -} - -#[derive(Debug)] -struct RenderPipelineLayoutInfo([BindGroupLayout; N]); -impl<'a> RenderPipelineLayoutInfo<3> { - const DESC: [BindGroupLayoutDescriptor<'a>; 3] = [ - wgpu::BindGroupLayoutDescriptor { - label: Some("Texture Render Bind Group Layout"), - entries: &[ - wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Texture { - multisampled: false, - view_dimension: wgpu::TextureViewDimension::D2, - sample_type: wgpu::TextureSampleType::Float { filterable: true }, - }, - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 1, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Texture { - multisampled: false, - view_dimension: wgpu::TextureViewDimension::D2, - sample_type: wgpu::TextureSampleType::Float { filterable: true }, - }, - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 2, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Texture { - multisampled: false, - view_dimension: wgpu::TextureViewDimension::D2, - sample_type: wgpu::TextureSampleType::Float { filterable: true }, - }, - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 3, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Texture { - multisampled: false, - view_dimension: wgpu::TextureViewDimension::D2, - sample_type: wgpu::TextureSampleType::Float { filterable: true }, - }, - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 4, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Texture { - multisampled: false, - view_dimension: wgpu::TextureViewDimension::D2, - sample_type: wgpu::TextureSampleType::Float { filterable: true }, - }, - count: None, - }, - ], - }, - wgpu::BindGroupLayoutDescriptor { - label: Some("Sampler Render Bind Group Layout"), - entries: &[wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), - count: None, - }], - }, - wgpu::BindGroupLayoutDescriptor { - label: Some("Uniform Render Bind Group Layout"), - entries: &[wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStages::VERTEX_FRAGMENT, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: None, - }, - count: None, - }], - }, - // wgpu::BindGroupLayoutDescriptor { - // label: Some("Fft Texture Bind Group Layout"), - // entries: &[wgpu::BindGroupLayoutEntry { - // binding: 0, - // visibility: wgpu::ShaderStages::FRAGMENT, - // ty: wgpu::BindingType::Texture { - // multisampled: false, - // sample_type: wgpu::TextureSampleType::Float { filterable: true }, - // view_dimension: wgpu::TextureViewDimension::D2, - // }, - // count: None, - // }], - // }, - ]; - - pub fn new(device: &Device) -> Self { - Self(Self::DESC.map(|x| device.create_bind_group_layout(&x))) - } -} - -impl Index for RenderPipelineLayoutInfo { - type Output = BindGroupLayout; - - fn index(&self, index: Binding) -> &Self::Output { - match index { - Binding::Texture => &self.0[0], - Binding::Sampler => &self.0[1], - Binding::Uniform => &self.0[2], - } - } -} - -#[derive(Debug)] -struct ComputePipelineLayoutInfo([BindGroupLayout; N]); -impl<'a> ComputePipelineLayoutInfo<2> { - const DESC: [BindGroupLayoutDescriptor<'a>; 2] = [ - wgpu::BindGroupLayoutDescriptor { - label: Some("Texture Compute Bind Group Layout"), - entries: &[ - wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStages::COMPUTE, - ty: wgpu::BindingType::StorageTexture { - access: wgpu::StorageTextureAccess::ReadWrite, - format: wgpu::TextureFormat::Rgba8Unorm, - view_dimension: wgpu::TextureViewDimension::D2, - }, - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 1, - visibility: wgpu::ShaderStages::COMPUTE, - ty: wgpu::BindingType::StorageTexture { - access: wgpu::StorageTextureAccess::ReadWrite, - format: wgpu::TextureFormat::Rgba8Unorm, - view_dimension: wgpu::TextureViewDimension::D2, - }, - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 2, - visibility: wgpu::ShaderStages::COMPUTE, - ty: wgpu::BindingType::StorageTexture { - access: wgpu::StorageTextureAccess::ReadWrite, - format: wgpu::TextureFormat::Rgba8Unorm, - view_dimension: wgpu::TextureViewDimension::D2, - }, - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 3, - visibility: wgpu::ShaderStages::COMPUTE, - ty: wgpu::BindingType::StorageTexture { - access: wgpu::StorageTextureAccess::ReadWrite, - format: wgpu::TextureFormat::Rgba32Float, - view_dimension: wgpu::TextureViewDimension::D2, - }, - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 4, - visibility: wgpu::ShaderStages::COMPUTE, - ty: wgpu::BindingType::StorageTexture { - access: wgpu::StorageTextureAccess::ReadWrite, - format: wgpu::TextureFormat::Rgba32Float, - view_dimension: wgpu::TextureViewDimension::D2, - }, - count: None, - }, - ], - }, - wgpu::BindGroupLayoutDescriptor { - label: Some("Uniform Compute Bind Group Layout"), - entries: &[wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStages::COMPUTE, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: None, - }, - count: None, - }], - }, - // wgpu::BindGroupLayoutDescriptor { - // label: Some("fft Texture Bind Group Layout"), - // entries: &[wgpu::BindGroupLayoutEntry { - // binding: 0, - // visibility: wgpu::ShaderStages::COMPUTE, - // ty: wgpu::BindingType::StorageTexture { - // access: wgpu::StorageTextureAccess::ReadWrite, - // format: wgpu::TextureFormat::Rgba32Float, - // view_dimension: wgpu::TextureViewDimension::D2, - // }, - // count: None, - // }], - // }, - ]; - - pub fn new(device: &Device) -> Self { - Self(Self::DESC.map(|x| device.create_bind_group_layout(&x))) - } -} - -impl Index for ComputePipelineLayoutInfo { - type Output = BindGroupLayout; - - fn index(&self, index: Binding) -> &Self::Output { - match index { - Binding::Texture => &self.0[0], - Binding::Uniform => &self.0[1], - _ => panic!(), - } - } -} - -// impl Index for [BindGroupLayout; N] { -// type Output = BindGroupLayout; - -// fn index(&self, index: Binding) -> &Self::Output { -// match index { -// Binding::Uniform => &self[0], -// Binding::Texture => &self[1], -// Binding::Sampler => &self[2], -// } -// } -// } - -fn create_textures( - device: &Device, - extent: wgpu::Extent3d, -) -> (Vec, Vec, BindGroup, BindGroup) { - puffin::profile_function!(); - let make_texture = |label, format| { - device.create_texture(&wgpu::TextureDescriptor { - label: Some(label), - size: extent, - usage: wgpu::TextureUsages::COPY_SRC - | wgpu::TextureUsages::COPY_DST - | wgpu::TextureUsages::RENDER_ATTACHMENT - | wgpu::TextureUsages::TEXTURE_BINDING - | wgpu::TextureUsages::STORAGE_BINDING, - mip_level_count: 1, - sample_count: 1, - dimension: wgpu::TextureDimension::D2, - format, - }) - }; - let textures: Vec<_> = [ - ("Previous Frame Texture", wgpu::TextureFormat::Rgba8Unorm), - ("Generic Frame Texture", wgpu::TextureFormat::Rgba8Unorm), - ("Dummy Frame Texture", wgpu::TextureFormat::Rgba8Unorm), - ("Float Texture 1", wgpu::TextureFormat::Rgba32Float), - ("Float Texture 2", wgpu::TextureFormat::Rgba32Float), - ] - .iter() - .map(|(label, format)| make_texture(label, *format)) - .collect(); - - let texture_views: Vec<_> = textures - .iter() - .map(|texture| texture.create_view(&wgpu::TextureViewDescriptor::default())) - .collect(); - - let entries: Vec<_> = texture_views - .iter() - .enumerate() - .map(|(i, view)| wgpu::BindGroupEntry { - binding: i as _, - resource: wgpu::BindingResource::TextureView(view), - }) - .collect(); - - let sampled_texture_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - label: Some("Render Bind Group"), - layout: &RenderPipelineLayoutInfo::new(device)[Binding::Texture], - entries: &entries, - }); - - let storage_texture_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - label: Some("Compute Bind Group"), - layout: &ComputePipelineLayoutInfo::new(device)[Binding::Texture], - entries: &entries, - }); - - ( - textures, - texture_views, - sampled_texture_bind_group, - storage_texture_bind_group, - ) -} - -pub struct WgpuRender { - adapter: Adapter, - pub device: Device, - pub surface: Surface, - surface_config: wgpu::SurfaceConfiguration, - queue: Queue, - pipelines: Vec, - pub shader_set: ContiniousHashMap, - format: TextureFormat, - push_constant_ranges: u32, - - extent: wgpu::Extent3d, - - textures: Vec, - texture_views: Vec, - - sampled_texture_bind_group: BindGroup, - storage_texture_bind_group: BindGroup, - sampler_bind_group: BindGroup, - - blitter: Blitter, - screenshot_ctx: ScreenshotCtx, - - multisampled_framebuffer: wgpu::TextureView, - smaa_target: smaa::SmaaTarget, - - pub paused: bool, - - uniform: Uniform, - uniform_buffer: wgpu::Buffer, - compute_uniform_bind_group: wgpu::BindGroup, - render_uniform_bind_group: wgpu::BindGroup, -} - -#[derive(Debug)] -pub struct RendererInfo { - pub device_name: String, - pub device_type: String, - pub vendor_name: String, - pub backend: String, -} - -impl Display for RendererInfo { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - writeln!(f, "Vendor name: {}", self.vendor_name)?; - writeln!(f, "Device name: {}", self.device_name)?; - writeln!(f, "Device type: {}", self.device_type)?; - writeln!(f, "Backend: {}", self.backend)?; - Ok(()) - } -} - -impl WgpuRender { - pub fn get_info(&self) -> RendererInfo { - let info = self.adapter.get_info(); - RendererInfo { - device_name: info.name, - device_type: self.get_device_type().to_string(), - vendor_name: self.get_vendor_name().to_string(), - backend: self.get_backend().to_string(), - } - } - fn get_vendor_name(&self) -> &str { - match self.adapter.get_info().vendor { - 0x1002 => "AMD", - 0x1010 => "ImgTec", - 0x10DE => "NVIDIA Corporation", - 0x13B5 => "ARM", - 0x5143 => "Qualcomm", - 0x8086 => "INTEL Corporation", - _ => "Unknown vendor", - } - } - fn get_backend(&self) -> &str { - match self.adapter.get_info().backend { - wgpu::Backend::Empty => "Empty", - wgpu::Backend::Vulkan => "Vulkan", - wgpu::Backend::Metal => "Metal", - wgpu::Backend::Dx12 => "Dx12", - wgpu::Backend::Dx11 => "Dx11", - wgpu::Backend::Gl => "GL", - wgpu::Backend::BrowserWebGpu => "Browser WGPU", - } - } - fn get_device_type(&self) -> &str { - match self.adapter.get_info().device_type { - wgpu::DeviceType::Other => "Other", - wgpu::DeviceType::IntegratedGpu => "Integrated GPU", - wgpu::DeviceType::DiscreteGpu => "Discrete GPU", - wgpu::DeviceType::VirtualGpu => "Virtual GPU", - wgpu::DeviceType::Cpu => "CPU", - } - } - - pub fn new( - window: &W, - push_constant_ranges: u32, - width: u32, - height: u32, - ) -> Result { - let instance = wgpu::Instance::new(wgpu::Backends::PRIMARY); - - let surface = unsafe { instance.create_surface(window) }; - - let adapter = block_on(instance.request_adapter(&wgpu::RequestAdapterOptions { - power_preference: wgpu::PowerPreference::HighPerformance, - force_fallback_adapter: false, - compatible_surface: Some(&surface), - })) - .unwrap(); - - let format = *surface - .get_supported_formats(&adapter) - .first() - .unwrap_or(&wgpu::TextureFormat::Bgra8UnormSrgb); - let limits = adapter.limits(); - let features = adapter.features(); - let trace_dir = std::env::var("WGPU_TRACE"); - let (device, queue) = block_on(adapter.request_device( - &wgpu::DeviceDescriptor { - label: Some("Device"), - limits, - features, - }, - trace_dir.ok().as_ref().map(std::path::Path::new), - ))?; - let extent = wgpu::Extent3d { - width, - height, - depth_or_array_layers: 1, - }; - - let surface_config = wgpu::SurfaceConfiguration { - usage: wgpu::TextureUsages::RENDER_ATTACHMENT - | wgpu::TextureUsages::COPY_SRC - | wgpu::TextureUsages::TEXTURE_BINDING, - format, - width: extent.width, - height: extent.height, - present_mode: wgpu::PresentMode::Immediate, - alpha_mode: wgpu::CompositeAlphaMode::Auto, - }; - surface.configure(&device, &surface_config); - - let (textures, texture_views, sampled_texture_bind_group, storage_texture_bind_group) = - create_textures(&device, extent); - - let sampler = device.create_sampler(&wgpu::SamplerDescriptor { - label: Some("Sampler"), - address_mode_u: wgpu::AddressMode::Repeat, - address_mode_v: wgpu::AddressMode::Repeat, - address_mode_w: wgpu::AddressMode::Repeat, - mag_filter: wgpu::FilterMode::Linear, - min_filter: wgpu::FilterMode::Linear, - mipmap_filter: wgpu::FilterMode::Linear, - compare: None, - ..Default::default() - }); - let sampler_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - label: Some("Render Bind Group"), - layout: &RenderPipelineLayoutInfo::new(&device)[Binding::Sampler], - entries: &[wgpu::BindGroupEntry { - binding: 0, - resource: wgpu::BindingResource::Sampler(&sampler), - }], - }); - - let blitter = Blitter::new(&device); - let screenshot_ctx = ScreenshotCtx::new(&device, width, height); - - let multisampled_framebuffer = - Self::create_multisample_texture(&device, format, NUM_SAMPLES, extent); - - let smaa_target = smaa::SmaaTarget::new( - &device, - &queue, - width, - height, - format, - smaa::SmaaMode::Smaa1X, - ); - - let uniform = Uniform::default(); - let uniform_buffer = device.create_buffer(&wgpu::BufferDescriptor { - label: Some("Uniform Buffer"), - size: std::mem::size_of::() as _, - usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, - mapped_at_creation: false, - }); - - let compute_uniform_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - label: Some("Uniform Bind Group"), - layout: &ComputePipelineLayoutInfo::new(&device)[Binding::Uniform], - entries: &[wgpu::BindGroupEntry { - binding: 0, - resource: uniform_buffer.as_entire_binding(), - }], - }); - let render_uniform_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - label: Some("Uniform Bind Group"), - layout: &RenderPipelineLayoutInfo::new(&device)[Binding::Uniform], - entries: &[wgpu::BindGroupEntry { - binding: 0, - resource: uniform_buffer.as_entire_binding(), - }], - }); - - Ok(Self { - adapter, - device, - surface, - surface_config, - pipelines: Vec::new(), - shader_set: ContiniousHashMap::new(), - queue, - format, - push_constant_ranges, - - textures, - texture_views, - - extent, - - sampled_texture_bind_group, - storage_texture_bind_group, - sampler_bind_group, - - blitter, - screenshot_ctx, - - multisampled_framebuffer, - smaa_target, - - paused: false, - - uniform, - uniform_buffer, - compute_uniform_bind_group, - render_uniform_bind_group, - }) - } - - pub fn resize(&mut self, width: u32, height: u32) { - puffin::profile_function!(); - if self.extent.width == width && self.extent.height == height { - return; - } - - self.extent = wgpu::Extent3d { - width, - height, - depth_or_array_layers: 1, - }; - self.surface_config.width = width; - self.surface_config.height = height; - self.surface.configure(&self.device, &self.surface_config); - let (textures, texture_views, sampled_texture_bind_group, storage_texture_bind_group) = - create_textures(&self.device, self.extent); - - self.textures = textures; - self.texture_views = texture_views; - self.sampled_texture_bind_group = sampled_texture_bind_group; - self.storage_texture_bind_group = storage_texture_bind_group; - - self.screenshot_ctx.resize(&self.device, width, height); - - self.multisampled_framebuffer = - Self::create_multisample_texture(&self.device, self.format, NUM_SAMPLES, self.extent); - self.smaa_target.resize(&self.device, width, height); - } - - fn create_multisample_texture( - device: &Device, - format: wgpu::TextureFormat, - sample_count: u32, - extent: wgpu::Extent3d, - ) -> wgpu::TextureView { - device - .create_texture(&wgpu::TextureDescriptor { - label: Some("Multisampled Frame"), - size: extent, - mip_level_count: 1, - sample_count, - dimension: wgpu::TextureDimension::D2, - format, - usage: wgpu::TextureUsages::RENDER_ATTACHMENT, - }) - .create_view(&wgpu::TextureViewDescriptor::default()) - } - - pub fn push_compute_pipeline(&mut self, comp: ShaderCreateInfo) -> Result<()> { - self.pipelines.push(self.create_compute_pipeline(comp)?); - - Ok(()) - } - - pub fn push_render_pipeline( - &mut self, - vert: ShaderCreateInfo, - frag: ShaderCreateInfo, - ) -> Result<()> { - self.pipelines - .push(self.create_render_pipeline(vert, frag)?); - - Ok(()) - } - - pub fn rebuild_compute_pipeline(&mut self, index: usize, comp: ShaderCreateInfo) -> Result<()> { - self.pipelines[index] = self.create_compute_pipeline(comp)?; - - Ok(()) - } - - pub fn rebuild_render_pipeline( - &mut self, - index: usize, - vert: ShaderCreateInfo, - frag: ShaderCreateInfo, - ) -> Result<()> { - self.pipelines[index] = self.create_render_pipeline(vert, frag)?; - - Ok(()) - } - - pub fn create_compute_pipeline(&self, cs: ShaderCreateInfo) -> Result { - let cs_module = unsafe { - self.device - .create_shader_module_spirv(&wgpu::ShaderModuleDescriptorSpirV { - label: Some("CS"), - source: cs.data.into(), - }) - }; - - let binding_layouts = ComputePipelineLayoutInfo::new(&self.device); - let layouts = array_cringing(&binding_layouts.0); - - let pipeline_layout = self - .device - .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - label: Some("Compute Pipeline Layout"), - bind_group_layouts: &layouts, - push_constant_ranges: &[wgpu::PushConstantRange { - stages: wgpu::ShaderStages::COMPUTE, - range: 0..self.push_constant_ranges, - }], - }); - - let pipeline = self - .device - .create_compute_pipeline(&wgpu::ComputePipelineDescriptor { - label: Some("Compute Pipeline"), - layout: Some(&pipeline_layout), - module: &cs_module, - entry_point: cs.entry_point.to_str().unwrap(), - }); - - Ok(Pipeline::Compute(pipeline)) - } - - pub fn create_render_pipeline( - &self, - vs: ShaderCreateInfo, - fs: ShaderCreateInfo, - ) -> Result { - let fs_module = unsafe { - self.device - .create_shader_module_spirv(&wgpu::ShaderModuleDescriptorSpirV { - label: Some("FS"), - source: fs.data.into(), - }) - }; - let vs_module = unsafe { - self.device - .create_shader_module_spirv(&wgpu::ShaderModuleDescriptorSpirV { - label: Some("VS"), - source: vs.data.into(), - }) - }; - - let binding_layouts = RenderPipelineLayoutInfo::new(&self.device); - let layouts = array_cringing(&binding_layouts.0); - - let pipeline_layout = self - .device - .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - label: Some("Render Pipeline Layout"), - bind_group_layouts: &layouts, - push_constant_ranges: &[wgpu::PushConstantRange { - stages: wgpu::ShaderStages::VERTEX_FRAGMENT, - range: 0..self.push_constant_ranges, - }], - }); - - let pipeline = self - .device - .create_render_pipeline(&wgpu::RenderPipelineDescriptor { - label: Some("Render Pipeline"), - layout: Some(&pipeline_layout), - vertex: wgpu::VertexState { - module: &vs_module, - entry_point: vs.entry_point.to_str().unwrap(), - buffers: &[], - }, - primitive: PrimitiveState { - topology: PrimitiveTopology::TriangleList, - strip_index_format: None, - front_face: wgpu::FrontFace::Ccw, - cull_mode: Some(wgpu::Face::Back), - ..Default::default() - }, - depth_stencil: None, - multisample: wgpu::MultisampleState { - count: NUM_SAMPLES, - mask: !0, - alpha_to_coverage_enabled: false, - }, - fragment: Some(wgpu::FragmentState { - module: &fs_module, - entry_point: fs.entry_point.to_str().unwrap(), - targets: &[Some(wgpu::ColorTargetState { - format: self.format, - blend: Some(wgpu::BlendState::REPLACE), - write_mask: wgpu::ColorWrites::ALL, - })], - }), - multiview: None, - }); - - Ok(Pipeline::Render(pipeline)) - } - - pub fn render(&mut self, push_constant: PushConstant) -> Result<(), wgpu::SurfaceError> { - puffin::profile_function!(); - - self.uniform = push_constant.into(); - self.queue - .write_buffer(&self.uniform_buffer, 0, bytemuck::bytes_of(&self.uniform)); - - let mut _pre_scope = - puffin::ProfilerScope::new("Aquiring frame", puffin::short_file_name(file!()), ""); - - let frame = match self.surface.get_current_texture() { - Ok(frame) => frame, - Err(_) => { - self.surface.configure(&self.device, &self.surface_config); - self.surface - .get_current_texture() - .expect("Failed to acquire next surface texture") - } - }; - let frame_view = frame - .texture - .create_view(&wgpu::TextureViewDescriptor::default()); - let smaa_frame = self - .smaa_target - .start_frame(&self.device, &self.queue, &frame_view); - - let mut encoder = self - .device - .create_command_encoder(&wgpu::CommandEncoderDescriptor { - label: Some("Main Encoder"), - }); - - drop(_pre_scope); - - for (i, pipeline) in self.pipelines.iter().enumerate() { - match pipeline { - Pipeline::Render(ref pipeline) => { - puffin::profile_scope!("Render Pass", format!("iteration {}", i).as_str()); - - let label = format!("Render Pass {}", i); - let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - label: Some(&label), - color_attachments: &[Some(wgpu::RenderPassColorAttachment { - view: &self.multisampled_framebuffer, - resolve_target: Some(&*smaa_frame), - ops: wgpu::Operations { - load: wgpu::LoadOp::Load, - store: true, - }, - })], - depth_stencil_attachment: None, - }); - render_pass.set_pipeline(pipeline); - render_pass.set_push_constants( - wgpu::ShaderStages::VERTEX_FRAGMENT, - 0, - bytemuck::bytes_of(&push_constant), - ); - render_pass.set_bind_group(0, &self.sampled_texture_bind_group, &[]); - render_pass.set_bind_group(1, &self.sampler_bind_group, &[]); - render_pass.set_bind_group(2, &self.render_uniform_bind_group, &[]); - render_pass.draw(0..3, 0..1); - } - Pipeline::Compute(ref pipeline) if !self.paused => { - puffin::profile_scope!("Compute Pass", format!("iteration {}", i).as_str()); - - let mut compute_pass = - encoder.begin_compute_pass(&wgpu::ComputePassDescriptor { - label: Some(&format!("Compute Pass {}", i)), - }); - compute_pass.set_pipeline(pipeline); - compute_pass.set_push_constants(0, bytemuck::bytes_of(&push_constant)); - compute_pass.set_bind_group(0, &self.storage_texture_bind_group, &[]); - compute_pass.set_bind_group(1, &self.compute_uniform_bind_group, &[]); - compute_pass.dispatch_workgroups( - dispatch_optimal_size(self.extent.width, SUBGROUP_SIZE), - dispatch_optimal_size(self.extent.height, SUBGROUP_SIZE), - 1, - ); - } - Pipeline::Compute { .. } => {} - } - } - - { - puffin::profile_scope!("Post-Process Antialiasing"); - drop(smaa_frame); - } - - { - puffin::profile_scope!("Blitting"); - self.blitter.blit_to_texture( - &self.device, - &mut encoder, - &frame_view, - &self.texture_views[0], - ); - } - - { - puffin::profile_scope!("Submit"); - self.queue.submit(std::iter::once(encoder.finish())); - } - { - puffin::profile_scope!("Present"); - frame.present(); - } - - Ok(()) - } - - pub fn screenshot_dimentions(&self) -> ImageDimentions { - self.screenshot_ctx.image_dimentions - } - - pub fn capture_frame(&mut self) -> Result { - puffin::profile_function!(); - let frame = pollster::block_on(self.screenshot_ctx.capture_frame( - &self.device, - &self.queue, - &self.textures[0], - )); - Ok(frame) - } - - pub fn wait_idle(&self) { - puffin::profile_function!(); - self.device.poll(wgpu::Maintain::Wait); - } -} - -fn array_cringing(arr: &[T; N]) -> [&T; N] { - let mut res = [&arr[0]; N]; - for i in 1..N { - res[i] = &arr[i]; - } - res -} diff --git a/pilka_wgpu/src/renderer/blit.wgsl b/pilka_wgpu/src/renderer/blit.wgsl deleted file mode 100644 index 0462cfb..0000000 --- a/pilka_wgpu/src/renderer/blit.wgsl +++ /dev/null @@ -1,35 +0,0 @@ -fn linear_to_srgb(vlinear: vec4) -> vec4 { - let color_linear = vlinear.rgb; - let selector = ceil(color_linear - 0.0031308); - let under = 12.92 * color_linear; - let over = 1.055 * pow(color_linear, vec3(0.41666)) - 0.055; - let result = mix(under, over, selector); - return vec4(result, vlinear.a); -} - -struct VertexOutput { - @builtin(position) position: vec4, - @location(0) uv: vec2, -}; - -@vertex -fn vs_main(@builtin(vertex_index) in_vertex_index: u32) -> VertexOutput { - let vertex_idx = i32(in_vertex_index); - var out : VertexOutput; - out.uv = vec2(f32((vertex_idx << 1u) & 2), f32(vertex_idx & 2)); - out.position = - vec4(out.uv.x * 2.0 + -1.0, 1.0 - out.uv.y * 2.0, 0.0, 1.0); - return out; -} - -@group(0) @binding(0) -var src_sampler: sampler; -@group(1) @binding(0) -var src_texture: texture_2d; - -@fragment -fn fs_main(in: VertexOutput) -> @location(0) vec4 { - let col = textureSample(src_texture, src_sampler, in.uv); - let col = linear_to_srgb(col); - return col; -} diff --git a/pilka_wgpu/src/renderer/blitter.rs b/pilka_wgpu/src/renderer/blitter.rs deleted file mode 100644 index 19386b3..0000000 --- a/pilka_wgpu/src/renderer/blitter.rs +++ /dev/null @@ -1,97 +0,0 @@ -use wgpu::{BindGroup, Device, RenderPipeline}; - -pub struct Blitter { - pipeline: RenderPipeline, - sampler_bind_group: BindGroup, -} - -impl Blitter { - pub const DST_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Rgba8Unorm; - - pub fn new(device: &Device) -> Self { - let shader = device.create_shader_module(wgpu::include_wgsl!("blit.wgsl")); - let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { - label: Some("blit"), - layout: None, - vertex: wgpu::VertexState { - module: &shader, - entry_point: "vs_main", - buffers: &[], - }, - primitive: wgpu::PrimitiveState { - topology: wgpu::PrimitiveTopology::TriangleList, - ..Default::default() - }, - depth_stencil: None, - multisample: wgpu::MultisampleState::default(), - fragment: Some(wgpu::FragmentState { - module: &shader, - entry_point: "fs_main", - targets: &[Some(Self::DST_FORMAT.into())], - }), - multiview: None, - }); - - let bind_group_layout = pipeline.get_bind_group_layout(0); - - let sampler = device.create_sampler(&wgpu::SamplerDescriptor { - label: Some("mip"), - address_mode_u: wgpu::AddressMode::ClampToEdge, - address_mode_v: wgpu::AddressMode::ClampToEdge, - address_mode_w: wgpu::AddressMode::ClampToEdge, - mag_filter: wgpu::FilterMode::Linear, - min_filter: wgpu::FilterMode::Nearest, - mipmap_filter: wgpu::FilterMode::Nearest, - ..Default::default() - }); - - let sampler_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - label: None, - layout: &bind_group_layout, - entries: &[wgpu::BindGroupEntry { - binding: 0, - resource: wgpu::BindingResource::Sampler(&sampler), - }], - }); - - Self { - pipeline, - sampler_bind_group, - } - } - - pub fn blit_to_texture( - &self, - device: &Device, - encoder: &mut wgpu::CommandEncoder, - src_texture: &wgpu::TextureView, - dst_texture: &wgpu::TextureView, - ) { - puffin::profile_function!(); - let texture_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - label: None, - layout: &self.pipeline.get_bind_group_layout(1), - entries: &[wgpu::BindGroupEntry { - binding: 0, - resource: wgpu::BindingResource::TextureView(src_texture), - }], - }); - let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - label: Some("Blit Pass"), - color_attachments: &[Some(wgpu::RenderPassColorAttachment { - view: dst_texture, - resolve_target: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Clear(wgpu::Color::WHITE), - store: true, - }, - })], - depth_stencil_attachment: None, - }); - - render_pass.set_pipeline(&self.pipeline); - render_pass.set_bind_group(0, &self.sampler_bind_group, &[]); - render_pass.set_bind_group(1, &texture_bind_group, &[]); - render_pass.draw(0..3, 0..1); - } -} diff --git a/pilka_wgpu/src/renderer/screenshot.rs b/pilka_wgpu/src/renderer/screenshot.rs deleted file mode 100644 index 7ed2080..0000000 --- a/pilka_wgpu/src/renderer/screenshot.rs +++ /dev/null @@ -1,97 +0,0 @@ -use std::num::NonZeroU32; - -use pilka_types::ImageDimentions; -use wgpu::{Device, MapMode}; - -pub struct ScreenshotCtx { - pub image_dimentions: ImageDimentions, - data: wgpu::Buffer, -} - -impl ScreenshotCtx { - pub fn resize(&mut self, device: &Device, width: u32, height: u32) { - puffin::profile_function!(); - let new_dims = ImageDimentions::new(width, height, wgpu::COPY_BYTES_PER_ROW_ALIGNMENT); - if new_dims.linear_size() > self.image_dimentions.linear_size() { - puffin::profile_scope!("Reallocating Buffer"); - let image_dimentions = - ImageDimentions::new(width, height, wgpu::COPY_BYTES_PER_ROW_ALIGNMENT); - - self.data = device.create_buffer(&wgpu::BufferDescriptor { - label: Some("Screen mapped Buffer"), - size: image_dimentions.linear_size(), - usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ, - mapped_at_creation: false, - }); - } - self.image_dimentions = new_dims; - } - - pub fn new(device: &Device, width: u32, height: u32) -> Self { - let image_dimentions = - ImageDimentions::new(width, height, wgpu::COPY_BYTES_PER_ROW_ALIGNMENT); - - let data = device.create_buffer(&wgpu::BufferDescriptor { - label: Some("Screen mapped Buffer"), - size: image_dimentions.linear_size(), - usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ, - mapped_at_creation: false, - }); - - Self { - image_dimentions, - - data, - } - } - - pub async fn capture_frame( - &mut self, - device: &wgpu::Device, - queue: &wgpu::Queue, - src_texture: &wgpu::Texture, - ) -> (Vec, ImageDimentions) { - puffin::profile_function!(); - let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { - label: Some("Capture Encoder"), - }); - let copy_size = wgpu::Extent3d { - width: self.image_dimentions.width, - height: self.image_dimentions.height, - depth_or_array_layers: 1, - }; - encoder.copy_texture_to_buffer( - src_texture.as_image_copy(), - wgpu::ImageCopyBuffer { - buffer: &self.data, - layout: wgpu::ImageDataLayout { - offset: 0, - bytes_per_row: Some( - NonZeroU32::new(self.image_dimentions.padded_bytes_per_row).unwrap(), - ), - rows_per_image: Some(NonZeroU32::new(self.image_dimentions.height).unwrap()), - }, - }, - copy_size, - ); - - queue.submit(Some(encoder.finish())); - - let image_slice = self.data.slice(0..self.image_dimentions.linear_size()); - image_slice.map_async(MapMode::Read, |err| { - if let Err(e) = err { - println!("Oh no, error on mapping buffer: {e}"); - } - }); - - device.poll(wgpu::Maintain::Wait); - - let mapped_slice = image_slice.get_mapped_range(); - let frame = mapped_slice.to_vec(); - - drop(mapped_slice); - self.data.unmap(); - - (frame, self.image_dimentions) - } -} diff --git a/src/app.rs b/src/app.rs deleted file mode 100644 index 0c53476..0000000 --- a/src/app.rs +++ /dev/null @@ -1,134 +0,0 @@ -use std::{error::Error, io::Write, path::PathBuf}; - -use crate::recorder; -use crate::render_bundle::{RenderBundleStatic, Renderer}; -use crate::utils::{self, print_help}; -use pilka_types::{PipelineInfo, PushConstant, ShaderInfo}; - -use notify::event::{EventKind, ModifyKind}; -use winit::dpi::PhysicalSize; - -pub const SHADER_PATH: &str = "shaders"; -const SHADER_ENTRY_POINT: &str = "main"; - -use crate::shader_compiler::ShaderCompiler; - -pub struct App<'a> { - pub render: RenderBundleStatic<'a>, - pub compiler: ShaderCompiler, - pub push_constant: PushConstant, - pub has_ffmpeg: bool, - - pub folder_events: crossbeam_channel::Receiver, -} - -impl<'a> App<'a> { - pub fn new( - window: &winit::window::Window, - folder_events: crossbeam_channel::Receiver, - ) -> Result> { - let PhysicalSize { width, height } = window.inner_size(); - let mut render = RenderBundleStatic::new(&window, PushConstant::size(), (width, height))?; - - let shader_dir = PathBuf::new().join(SHADER_PATH); - - let spec = utils::parse_folder(SHADER_PATH)?; - - let mut compiler = ShaderCompiler::new(); - - // Compute pipeline have to go first - render.push_pipeline( - PipelineInfo::Compute { - comp: ShaderInfo::new(spec.comp.path, SHADER_ENTRY_POINT.into(), spec.comp.ty), - }, - &[spec.glsl_prelude.clone().unwrap()], - &mut compiler, - )?; - - render.push_pipeline( - PipelineInfo::Rendering { - vert: ShaderInfo::new(spec.vert.path, SHADER_ENTRY_POINT.into(), spec.vert.ty), - frag: ShaderInfo::new(spec.frag.path, SHADER_ENTRY_POINT.into(), spec.frag.ty), - }, - &[spec.glsl_prelude.unwrap()], - &mut compiler, - )?; - - let (ffmpeg_version, has_ffmpeg) = recorder::ffmpeg_version()?; - - println!("{}", render.get_info()); - // println!("Audio host: {:?}", audio_context.host_id); - // println!( - // "Sample rate: {}, channels: {}", - // audio_context.sample_rate, audio_context.num_channels - // ); - println!("{}", ffmpeg_version); - println!( - "Default shader path:\n\t{}", - shader_dir.canonicalize()?.display() - ); - - print_help(); - - println!("// Set up our new world⏎ "); - println!("// And let's begin the⏎ "); - println!("\tSIMULATION⏎ \n"); - - let push_constant = PushConstant::default(); - - Ok(Self { - render, - compiler, - push_constant, - has_ffmpeg, - - folder_events, - }) - } - - pub fn setup_frame(&mut self) { - if let Ok(rx_event) = self.folder_events.try_recv() { - if let notify::Event { - kind: EventKind::Modify(ModifyKind::Data(_)), - .. - } = rx_event - { - puffin::profile_scope!("Shader Change Event"); - match self - .render - .register_shader_change(rx_event.paths.as_ref(), &mut self.compiler) - { - Ok(_) => { - const ESC: &str = "\x1B["; - const RESET: &str = "\x1B[0m"; - eprint!("\r{}42m{}K{}\r", ESC, ESC, RESET); - std::io::stdout().flush().unwrap(); - std::thread::spawn(|| { - std::thread::sleep(std::time::Duration::from_millis(50)); - eprint!("\r{}40m{}K{}\r", ESC, ESC, RESET); - std::io::stdout().flush().unwrap(); - }); - } - Err(e) => { - eprintln!("{}", e) - } - }; - } - } - - self.render.pause(); - } - - pub fn render(&mut self) { - self.render.render(self.push_constant).unwrap(); - self.push_constant.frame += 1; - } - - pub fn resize(&mut self, width: u32, height: u32) -> eyre::Result<()> { - self.render.resize(width, height) - } - - pub fn shut_down(&self) { - self.render.shut_down(); - } -} diff --git a/src/audio.rs b/src/audio.rs deleted file mode 100644 index e93436e..0000000 --- a/src/audio.rs +++ /dev/null @@ -1,102 +0,0 @@ -use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; -use cpal::HostId; -use eyre::*; -use std::sync::{Arc, Mutex}; -use std::thread; - -use rustfft::{num_complex::Complex32, Fft, FftPlanner}; - -pub const FFT_SIZE: u32 = 1024 * 2; -const AMPLIFICATION: f32 = 1.; - -pub struct AudioContext { - pub sample_rate: u32, - pub num_channels: u16, - pub host_id: HostId, - sample_buffer: Arc>>, - fft: Arc>, - inner: Vec, - scratch_area: Vec, -} - -fn start_audio_thread() -> Result { - let host = cpal::default_host(); - - let device = host - .default_input_device() - .context("failed to find input device")?; - - let config = device.default_input_config()?; - let sample_rate = config.sample_rate().0; - let num_channels = config.channels(); - - let err_fn = move |err| { - eprintln!("an error occured on stream: {}", err); - }; - - let inner = vec![Complex32::default(); FFT_SIZE as usize]; - let buff = Arc::new(Mutex::new(vec![Complex32::default(); FFT_SIZE as usize])); - let mut planner = FftPlanner::::new(); - let fft = planner.plan_fft_forward(FFT_SIZE as usize); - let scratch_area = vec![Complex32::default(); fft.get_inplace_scratch_len()]; - - let stream = device.build_input_stream( - &config.into(), - { - let buff2 = Arc::clone(&buff); - move |data, _: &_| { - let mut buff3 = buff2.lock().unwrap(); - write_input_data::(data, &mut buff3); - } - }, - err_fn, - )?; - match stream.play() { - Err(e) => Err(Report::from(e)), - Ok(()) => Ok(AudioContext { - sample_rate, - num_channels, - host_id: host.id(), - sample_buffer: buff, - fft, - inner, - scratch_area, - }), - } -} - -impl AudioContext { - pub fn new() -> Result { - // Start the audio stream on another thread, to work around winit + cpal COM incompatibilities - // on Windows. - let context = thread::spawn(start_audio_thread) - .join() - .expect("Audio thread crashed")?; - Ok(context) - } - - pub fn get_fft(&mut self, out: &mut [f32]) { - let mut buf = self.sample_buffer.lock().unwrap(); - self.fft - .process_outofplace_with_scratch(&mut buf, &mut self.inner, &mut self.scratch_area); - - let scaling = 2. / (buf.len() as f32 * buf.len() as f32); - out.iter_mut() - .zip(self.inner.iter().map(|s| s.norm() * scaling)) - .for_each(|(l, r)| *l = r); - } -} - -fn write_input_data(input: &[T], buff: &mut [Complex32]) -where - T: cpal::Sample, -{ - let buff_size = buff.len(); - let diff = buff_size - input.len().min(buff_size); - - buff.rotate_right(diff); - buff.iter_mut() - .skip(diff) - .zip(input.iter().map(|s| s.to_f32())) - .for_each(|(l, r)| *l = (r * AMPLIFICATION).into()); -} diff --git a/src/default_shaders/glsl.rs b/src/default_shaders/glsl.rs index 52cab98..ab53fc2 100644 --- a/src/default_shaders/glsl.rs +++ b/src/default_shaders/glsl.rs @@ -1,21 +1,12 @@ pub const FRAG_SHADER: &str = "#version 460 +#extension GL_EXT_buffer_reference : require // In the beginning, colours never existed. There's nothing that was done before you... #include -layout(location = 0) in vec2 in_uv; -layout(location = 0) out vec4 out_color; - -layout(set = 0, binding = 0) uniform texture2D prev_frame; -layout(set = 0, binding = 1) uniform texture2D generic_texture; -layout(set = 0, binding = 2) uniform texture2D dummy_texture; -layout(set = 0, binding = 3) uniform texture2D float_texture1; -layout(set = 0, binding = 4) uniform texture2D float_texture2; -layout(set = 1, binding = 0) uniform sampler tex_sampler; -#define T(tex, uv_coord) (texture(sampler2D(tex, tex_sampler), uv_coord)) -#define Tuv(tex) (T(tex, in_uv)) -#define T_off(tex, off) (T(tex, vec2(in_uv.x + off.x, -(in_uv.y + off.y)))) +layout(set = 0, binding = 0) uniform sampler gsamplers[]; +layout(set = 0, binding = 1) uniform texture2D gtextures[]; layout(std430, push_constant) uniform PushConstant { vec3 pos; @@ -25,8 +16,12 @@ layout(std430, push_constant) uniform PushConstant { bool mouse_pressed; uint frame; float time_delta; - float record_period; -} pc; + float record_time; +} +pc; + +layout(location = 0) in vec2 in_uv; +layout(location = 0) out vec4 out_color; void main() { vec2 uv = (in_uv + -0.5) * vec2(pc.resolution.x / pc.resolution.y, 1); @@ -36,8 +31,10 @@ void main() { }"; pub const VERT_SHADER: &str = "#version 460 +#extension GL_EXT_buffer_reference : require -layout(location = 0) out vec2 out_uv; +layout(set = 0, binding = 0) uniform sampler gsamplers[]; +layout(set = 0, binding = 1) uniform texture2D gtextures[]; layout(std430, push_constant) uniform PushConstant { vec3 pos; @@ -47,8 +44,11 @@ layout(std430, push_constant) uniform PushConstant { bool mouse_pressed; uint frame; float time_delta; - float record_period; -} pc; + float record_time; +} +pc; + +layout(location = 0) out vec2 out_uv; void main() { out_uv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); @@ -56,6 +56,10 @@ void main() { }"; pub const COMP_SHADER: &str = "#version 460 +#extension GL_EXT_buffer_reference : require + +layout(set = 0, binding = 0) uniform sampler gsamplers[]; +layout(set = 0, binding = 1) uniform texture2D gtextures[]; layout(std430, push_constant) uniform PushConstant { vec3 pos; @@ -65,18 +69,12 @@ layout(std430, push_constant) uniform PushConstant { bool mouse_pressed; uint frame; float time_delta; - float record_period; -} pc; + float record_time; +} +pc; layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in; -layout (binding = 0, rgba8) uniform image2D previous_frame; -layout (binding = 1, rgba8) uniform image2D generic_texture; -layout (binding = 2, rgba8) uniform image2D dummy_texture; - -layout (binding = 3, rgba32f) uniform image2D float_texture1; -layout (binding = 4, rgba32f) uniform image2D float_texture2; - void main() { if (gl_GlobalInvocationID.x >= pc.resolution.x || gl_GlobalInvocationID.y >= pc.resolution.y) { @@ -84,11 +82,18 @@ void main() { } }"; -pub const PRELUDE: &str = " -const float PI = acos(-1.); +pub const PRELUDE: &str = "const float PI = acos(-1.); const float TAU = 2. * PI; -const float HALF_WIDTH = 1.0; +const uint PREV_TEX = 0; +const uint GENERIC_TEX1 = 1; +const uint GENERIC_TEX2 = 2; +const uint DITHER_TEX = 3; +const uint NOISE_TEX = 4; +const uint BLUE_TEX = 5; + +const uint LINER_SAMPL = 0; +const uint NEAREST_SAMPL = 1; vec4 ASSERT_COL = vec4(0.); void assert(bool cond, int v) { @@ -106,9 +111,14 @@ void assert(bool cond) { assert(cond, 0); } if (ASSERT_COL.z < 0.0) out = vec4(0.0, 0.0, 1.0, 1.0); \ if (ASSERT_COL.w < 0.0) out = vec4(1.0, 1.0, 0.0, 1.0); -#define AAstep(x0, x) clamp(((x) - (x0)) / (4. / pc.resolution.y), 0., 1.) +float AAstep(float threshold, float val) { + return smoothstep(-.5, .5, (val - threshold) / min(0.005, fwidth(val - threshold))); +} +float AAstep(float val) { + return AAstep(val, 0.); +} -float worldSDF(vec3 rayPos); +float worldsdf(vec3 rayPos); vec2 ray_march(vec3 rayPos, vec3 rayDir) { const vec3 EPS = vec3(0., 0.001, 0.0001); @@ -119,7 +129,7 @@ vec2 ray_march(vec3 rayPos, vec3 rayDir) { for(int i = 0; i < MAX_STEPS; i++) { vec3 pos = rayPos + (dist * rayDir); - float posToScene = worldSDF(pos); + float posToScene = worldsdf(pos); dist += posToScene; if(abs(posToScene) < HIT_DIST) return vec2(dist, i); if(posToScene > MISS_DIST) break; @@ -128,57 +138,6 @@ vec2 ray_march(vec3 rayPos, vec3 rayDir) { return vec2(-dist, MAX_STEPS); } -float crossSDF(vec3 rayPos) { - const vec3 corner = vec3(HALF_WIDTH); - vec3 ray = abs(rayPos); - vec3 cornerToRay = ray - corner; - float minComp = min(min(cornerToRay.x, cornerToRay.y), cornerToRay.z); - float maxComp = max(max(cornerToRay.x, cornerToRay.y), cornerToRay.z); - float midComp = cornerToRay.x + cornerToRay.y + cornerToRay.z - - minComp - maxComp; - vec2 closestOutsidePoint = max(vec2(minComp, midComp), 0.0); - vec2 closestInsidePoint = min(vec2(midComp, maxComp), 0.0); - return (midComp > 0.0) ? length(closestOutsidePoint) : -length(closestInsidePoint); -} - -float cubeSDF(vec3 rayPos) { - const vec3 corner = vec3(HALF_WIDTH); - vec3 ray = abs(rayPos); - vec3 cornerToRay = ray - corner; - float cornerToRayMaxComponent = max(max(cornerToRay.x, cornerToRay.y), cornerToRay.z); - float distToInsideRay = min(cornerToRayMaxComponent, 0.0); - vec3 closestToOusideRay = max(cornerToRay, 0.0); - return length(closestToOusideRay) + distToInsideRay; -} - -float squareSDF(vec2 rayPos) { - const vec2 corner = vec2(HALF_WIDTH); - vec2 ray = abs(rayPos.xy); - vec2 cornerToRay = ray - corner; - float cornerToRayMaxComponent = max(cornerToRay.x, cornerToRay.y); - float distToInsideRay = min(cornerToRayMaxComponent, 0.0); - vec2 closestToOusideRay = max(cornerToRay, 0.0); - return length(closestToOusideRay) + distToInsideRay; -} - -float sphereSDF(vec3 rayPosition, vec3 sphereCenterPosition, float radius) { - vec3 centerToRay = rayPosition - sphereCenterPosition; - float distToCenter = length(centerToRay); - return distToCenter - radius; -} - -float sphereSDF(vec3 rayPos, float radius) { - return length(rayPos) - radius; -} - -float sphereSDF(vec3 rayPos) { - return length(rayPos) - HALF_WIDTH; -} - -float yplaneSDF(vec3 rayPos) { - return abs(rayPos.y); -} - mat2 rotate(float angle) { float sine = sin(angle); float cosine = cos(angle); @@ -193,7 +152,7 @@ vec3 enlight(in vec3 at, vec3 normal, vec3 diffuse, vec3 l_color, vec3 l_pos) { vec3 wnormal(in vec3 p) { const vec3 EPS = vec3(0., 0.01, 0.0001); - return normalize(vec3(worldSDF(p + EPS.yxx) - worldSDF(p - EPS.yxx), - worldSDF(p + EPS.xyx) - worldSDF(p - EPS.xyx), - worldSDF(p + EPS.xxy) - worldSDF(p - EPS.xxy))); + return normalize(vec3(worldsdf(p + EPS.yxx) - worldsdf(p - EPS.yxx), + worldsdf(p + EPS.xyx) - worldsdf(p - EPS.xyx), + worldsdf(p + EPS.xxy) - worldsdf(p - EPS.xxy))); }"; diff --git a/src/default_shaders/mod.rs b/src/default_shaders/mod.rs index e49a784..de8f9e6 100644 --- a/src/default_shaders/mod.rs +++ b/src/default_shaders/mod.rs @@ -2,15 +2,11 @@ use std::fs::File; use std::io::Write; use std::path::Path; -use super::utils::create_folder; +use crate::create_folder; mod glsl; -mod wgsl; -pub fn create_default_shaders>( - name: P, - wgsl_mode: Option<()>, -) -> std::io::Result<()> { +pub fn create_default_shaders>(name: P) -> std::io::Result<()> { create_folder(&name)?; let create_file = |filename: &str, content: &str| -> std::io::Result<()> { @@ -19,17 +15,10 @@ pub fn create_default_shaders>( file.write_all(content.as_bytes()) }; - if wgsl_mode.is_some() { - create_file("prelude.glsl", glsl::PRELUDE)?; - create_file("shader.frag.wgsl", wgsl::FRAG_SHADER)?; - create_file("shader.vert.wgsl", wgsl::VERT_SHADER)?; - create_file("shader.comp.wgsl", wgsl::COMP_SHADER)?; - } else { - create_file("prelude.glsl", glsl::PRELUDE)?; - create_file("shader.frag", glsl::FRAG_SHADER)?; - create_file("shader.vert", glsl::VERT_SHADER)?; - create_file("shader.comp", glsl::COMP_SHADER)?; - } + create_file("prelude.glsl", glsl::PRELUDE)?; + create_file("shader.frag", glsl::FRAG_SHADER)?; + create_file("shader.vert", glsl::VERT_SHADER)?; + create_file("shader.comp", glsl::COMP_SHADER)?; Ok(()) } diff --git a/src/default_shaders/wgsl.rs b/src/default_shaders/wgsl.rs deleted file mode 100644 index 1ab3d82..0000000 --- a/src/default_shaders/wgsl.rs +++ /dev/null @@ -1,83 +0,0 @@ -pub const FRAG_SHADER: &str = " -struct Uniform { - pos: vec3, - resolution: vec2, - mouse: vec2, - mouse_pressed: u32, - time: f32, - time_delta: f32, - frame: u32, - record_period: f32, -}; - -@group(0) @binding(0) -var prev_frame: texture_2d; -@group(0) @binding(1) var generic_texture: texture_2d; -@group(0) @binding(2) var dummy_texture: texture_2d; -@group(0) @binding(3) var float_texture1: texture_2d; -@group(0) @binding(4) var float_texture2: texture_2d; -@group(1) @binding(4) var tex_sampler: sampler; -@group(2) @binding(0) var un: Uniform; - -struct VertexOutput { - @builtin(position) pos: vec4, - @location(0) uv: vec2, -}; - -@fragment -fn main(in: VertexOutput) -> @location(0) vec4 { - let uv = - (in.uv * 2.0 - 1.0) * vec2(un.resolution.x / un.resolution.y, 1.); - - var col = vec3(uv, 1.); - col.x = col.x + un.mouse.x; - col.y = col.y + un.mouse.y; - - return vec4(col, 1.0); -} -"; - -pub const VERT_SHADER: &str = " -struct VertexOutput { - @builtin(position) - pos: vec4, - @location(0) - uv: vec2, -}; - -@vertex -fn main(@builtin(vertex_index) vertex_idx: u32) -> VertexOutput { - let uv = vec2((vertex_idx << 1u) & 2u, vertex_idx & 2u); - let out = VertexOutput(vec4(2.0 * vec2(uv) - 1.0, 0.0, 1.0), vec2(uv)); - return out; -} -"; - -pub const COMP_SHADER: &str = " -struct Uniform { - pos: vec3, - resolution: vec2, - mouse: vec2, - mouse_pressed: u32, - time: f32, - time_delta: f32, - frame: u32, - record_period: f32, -}; - -@group(0) @binding(0) var prev_frame: texture_storage_2d; -@group(0) @binding(1) var generic_texture: texture_storage_2d; -@group(0) @binding(2) var dummy_texture: texture_storage_2d; -@group(0) @binding(3) var float_texture1: texture_storage_2d; -@group(0) @binding(4) var float_texture2: texture_storage_2d; -@group(1) @binding(0) var un: Uniform; - -@compute -@workgroup_size(256, 1) -fn main(@builtin(global_invocation_id) global_id: vec3) { - if (f32(global_id.x) >= un.resolution.x || - f32(global_id.y) >= un.resolution.y) { - return; - } -} -"; diff --git a/src/device.rs b/src/device.rs new file mode 100644 index 0000000..66ba2da --- /dev/null +++ b/src/device.rs @@ -0,0 +1,508 @@ +use anyhow::Result; +use gpu_alloc::{GpuAllocator, MemoryBlock, Request, UsageFlags}; +use gpu_alloc_ash::AshMemoryDevice; +use parking_lot::Mutex; +use std::{ffi::CStr, mem::ManuallyDrop, sync::Arc}; + +use ash::{ + khr, + prelude::VkResult, + vk::{self, DeviceMemory}, +}; + +use crate::{align_to, ManagedImage, COLOR_SUBRESOURCE_MASK}; + +pub struct Device { + pub physical_device: vk::PhysicalDevice, + pub memory_properties: vk::PhysicalDeviceMemoryProperties, + pub device_properties: vk::PhysicalDeviceProperties, + pub descriptor_indexing_props: vk::PhysicalDeviceDescriptorIndexingProperties<'static>, + pub command_pool: vk::CommandPool, + pub main_queue_family_idx: u32, + pub transfer_queue_family_idx: u32, + pub allocator: Arc>>, + pub device: Arc, + pub ext: Arc, +} + +pub struct DeviceExt { + pub dynamic_rendering: khr::dynamic_rendering::Device, +} + +impl std::ops::Deref for Device { + type Target = RawDevice; + + fn deref(&self) -> &Self::Target { + &self.device + } +} + +#[derive(Clone)] +pub struct RawDevice { + inner: ash::Device, +} + +impl RawDevice { + pub fn new(inner: ash::Device) -> Self { + Self { inner } + } + + pub fn get_buffer_address(&self, buffer: vk::Buffer) -> u64 { + unsafe { + self.get_buffer_device_address(&vk::BufferDeviceAddressInfo::default().buffer(buffer)) + } + } + + pub fn create_2d_view(&self, image: &vk::Image, format: vk::Format) -> VkResult { + let view = unsafe { + self.create_image_view( + &vk::ImageViewCreateInfo::default() + .view_type(vk::ImageViewType::TYPE_2D) + .image(*image) + .format(format) + .subresource_range( + vk::ImageSubresourceRange::default() + .aspect_mask(vk::ImageAspectFlags::COLOR) + .base_mip_level(0) + .level_count(1) + .base_array_layer(0) + .layer_count(1), + ), + None, + )? + }; + Ok(view) + } + + pub fn alloc_memory( + &self, + allocator: &mut GpuAllocator, + memory_reqs: vk::MemoryRequirements, + usage: UsageFlags, + ) -> Result, gpu_alloc::AllocationError> { + let memory_block = unsafe { + allocator.alloc( + AshMemoryDevice::wrap(self), + Request { + size: memory_reqs.size, + align_mask: memory_reqs.alignment - 1, + usage: usage | UsageFlags::DEVICE_ADDRESS, + memory_types: memory_reqs.memory_type_bits, + }, + ) + }; + memory_block + } + + pub fn one_time_submit( + &self, + command_pool: &vk::CommandPool, + queue: &vk::Queue, + callbk: impl FnOnce(&Self, vk::CommandBuffer), + ) -> VkResult<()> { + let fence = unsafe { self.create_fence(&vk::FenceCreateInfo::default(), None)? }; + let command_buffer = unsafe { + self.allocate_command_buffers( + &vk::CommandBufferAllocateInfo::default() + .command_pool(*command_pool) + .command_buffer_count(1) + .level(vk::CommandBufferLevel::PRIMARY), + )?[0] + }; + + unsafe { + self.begin_command_buffer( + command_buffer, + &vk::CommandBufferBeginInfo::default() + .flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT), + )?; + + callbk(self, command_buffer); + + self.end_command_buffer(command_buffer)?; + + let submit_info = + vk::SubmitInfo::default().command_buffers(std::slice::from_ref(&command_buffer)); + + self.queue_submit(*queue, &[submit_info], fence)?; + self.wait_for_fences(&[fence], true, u64::MAX)?; + + self.destroy_fence(fence, None); + self.free_command_buffers(*command_pool, &[command_buffer]); + } + + Ok(()) + } + + pub fn blit_image( + &self, + command_buffer: &vk::CommandBuffer, + src_image: &vk::Image, + src_extent: vk::Extent2D, + src_orig_layout: vk::ImageLayout, + dst_image: &vk::Image, + dst_extent: vk::Extent2D, + dst_orig_layout: vk::ImageLayout, + ) { + let src_barrier = vk::ImageMemoryBarrier2::default() + .subresource_range(COLOR_SUBRESOURCE_MASK) + .image(*src_image) + .src_stage_mask(vk::PipelineStageFlags2::ALL_COMMANDS) + .dst_stage_mask(vk::PipelineStageFlags2::ALL_COMMANDS) + .dst_access_mask(vk::AccessFlags2::MEMORY_READ) + .old_layout(src_orig_layout) + .new_layout(vk::ImageLayout::TRANSFER_SRC_OPTIMAL); + let dst_barrier = vk::ImageMemoryBarrier2::default() + .subresource_range(COLOR_SUBRESOURCE_MASK) + .image(*dst_image) + .src_stage_mask(vk::PipelineStageFlags2::ALL_COMMANDS) + .dst_stage_mask(vk::PipelineStageFlags2::ALL_COMMANDS) + .dst_access_mask(vk::AccessFlags2::MEMORY_WRITE) + .old_layout(dst_orig_layout) + .new_layout(vk::ImageLayout::TRANSFER_DST_OPTIMAL); + let image_memory_barriers = &[src_barrier, dst_barrier]; + let dependency_info = + vk::DependencyInfo::default().image_memory_barriers(image_memory_barriers); + unsafe { self.cmd_pipeline_barrier2(*command_buffer, &dependency_info) }; + + let src_offsets = [ + vk::Offset3D { x: 0, y: 0, z: 0 }, + vk::Offset3D { + x: src_extent.width as _, + y: src_extent.height as _, + z: 1, + }, + ]; + let dst_offsets = [ + vk::Offset3D { x: 0, y: 0, z: 0 }, + vk::Offset3D { + x: dst_extent.width as _, + y: dst_extent.height as _, + z: 1, + }, + ]; + let subresource_layer = vk::ImageSubresourceLayers { + aspect_mask: vk::ImageAspectFlags::COLOR, + base_array_layer: 0, + layer_count: 1, + mip_level: 0, + }; + let regions = [vk::ImageBlit2::default() + .src_offsets(src_offsets) + .dst_offsets(dst_offsets) + .src_subresource(subresource_layer) + .dst_subresource(subresource_layer)]; + let blit_info = vk::BlitImageInfo2::default() + .src_image(*src_image) + .src_image_layout(vk::ImageLayout::TRANSFER_SRC_OPTIMAL) + .dst_image(*dst_image) + .dst_image_layout(vk::ImageLayout::TRANSFER_DST_OPTIMAL) + .regions(®ions) + .filter(vk::Filter::NEAREST); + unsafe { self.cmd_blit_image2(*command_buffer, &blit_info) }; + + let src_barrier = src_barrier + .src_access_mask(vk::AccessFlags2::MEMORY_READ) + .old_layout(vk::ImageLayout::TRANSFER_SRC_OPTIMAL) + .new_layout(src_orig_layout); + let dst_barrier = dst_barrier + .src_access_mask(vk::AccessFlags2::MEMORY_WRITE) + .old_layout(vk::ImageLayout::TRANSFER_DST_OPTIMAL) + .new_layout(match dst_orig_layout { + vk::ImageLayout::UNDEFINED => vk::ImageLayout::GENERAL, + _ => dst_orig_layout, + }); + let image_memory_barriers = &[src_barrier, dst_barrier]; + let dependency_info = + vk::DependencyInfo::default().image_memory_barriers(image_memory_barriers); + unsafe { self.cmd_pipeline_barrier2(*command_buffer, &dependency_info) }; + } +} + +impl std::ops::Deref for RawDevice { + type Target = ash::Device; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl Device { + pub fn one_time_submit( + &self, + queue: &vk::Queue, + callbk: impl FnOnce(&RawDevice, vk::CommandBuffer), + ) -> VkResult<()> { + self.device + .one_time_submit(&self.command_pool, queue, callbk) + } + + pub fn alloc_memory( + &self, + memory_reqs: vk::MemoryRequirements, + usage: UsageFlags, + ) -> Result, gpu_alloc::AllocationError> { + let mut allocator = self.allocator.lock(); + self.device.alloc_memory(&mut allocator, memory_reqs, usage) + } + + pub fn capture_image_data( + &self, + queue: &vk::Queue, + src_image: &vk::Image, + extent: vk::Extent2D, + callback: impl FnOnce(ManagedImage), + ) -> Result<()> { + let dst_image = ManagedImage::new( + self, + &vk::ImageCreateInfo::default() + .extent(vk::Extent3D { + width: dbg!(align_to(extent.width, 2)), + height: dbg!(align_to(extent.height, 2)), + depth: 1, + }) + .image_type(vk::ImageType::TYPE_2D) + .format(vk::Format::R8G8B8A8_SRGB) + .usage(vk::ImageUsageFlags::TRANSFER_DST) + .samples(vk::SampleCountFlags::TYPE_1) + .mip_levels(1) + .array_layers(1) + .tiling(vk::ImageTiling::LINEAR), + UsageFlags::DOWNLOAD, + )?; + + self.one_time_submit(queue, |device, command_buffer| { + device.blit_image( + &command_buffer, + src_image, + extent, + vk::ImageLayout::PRESENT_SRC_KHR, + &dst_image.image, + extent, + vk::ImageLayout::UNDEFINED, + ); + })?; + + callback(dst_image); + + Ok(()) + } + + pub fn create_host_buffer( + &self, + size: u64, + usage: vk::BufferUsageFlags, + memory_usage: gpu_alloc::UsageFlags, + ) -> Result { + let buffer = unsafe { + self.create_buffer( + &vk::BufferCreateInfo::default() + .size(size) + .usage(usage | vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS), + None, + )? + }; + let mem_requirements = unsafe { self.get_buffer_memory_requirements(buffer) }; + + let mut memory = + self.alloc_memory(mem_requirements, memory_usage | UsageFlags::HOST_ACCESS)?; + unsafe { self.bind_buffer_memory(buffer, *memory.memory(), memory.offset()) }?; + + let address = unsafe { + self.get_buffer_device_address(&vk::BufferDeviceAddressInfo::default().buffer(buffer)) + }; + + let ptr = unsafe { + memory.map( + AshMemoryDevice::wrap(self), + memory.offset(), + memory.size() as usize, + )? + }; + let data = unsafe { std::slice::from_raw_parts_mut(ptr.as_ptr(), size as _) }; + + Ok(HostBuffer { + address, + size, + buffer, + memory: ManuallyDrop::new(memory), + data, + device: self.device.clone(), + allocator: self.allocator.clone(), + }) + } + + pub fn create_host_buffer_typed( + &self, + usage: vk::BufferUsageFlags, + memory_usage: gpu_alloc::UsageFlags, + ) -> Result> { + let byte_size = (size_of::()) as vk::DeviceSize; + let buffer = unsafe { + self.device.create_buffer( + &vk::BufferCreateInfo::default() + .size(byte_size) + .usage(usage | vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS), + None, + )? + }; + let mem_requirements = unsafe { self.get_buffer_memory_requirements(buffer) }; + + let mut memory = + self.alloc_memory(mem_requirements, memory_usage | UsageFlags::HOST_ACCESS)?; + unsafe { self.bind_buffer_memory(buffer, *memory.memory(), memory.offset()) }?; + + let address = unsafe { + self.get_buffer_device_address(&vk::BufferDeviceAddressInfo::default().buffer(buffer)) + }; + + let ptr = unsafe { + memory.map( + AshMemoryDevice::wrap(&self.device), + memory.offset(), + memory.size() as usize, + )? + }; + let ptr = unsafe { &mut *ptr.as_ptr().cast::() }; + + Ok(HostBufferTyped { + address, + buffer, + memory: ManuallyDrop::new(memory), + data: ptr, + device: self.device.clone(), + allocator: self.allocator.clone(), + }) + } + + pub fn get_info(&self) -> RendererInfo { + RendererInfo { + device_name: self.get_device_name().unwrap().to_string(), + device_type: self.get_device_type().to_string(), + vendor_name: self.get_vendor_name().to_string(), + } + } + pub fn get_device_name(&self) -> Result<&str, std::str::Utf8Error> { + unsafe { CStr::from_ptr(self.device_properties.device_name.as_ptr()) }.to_str() + } + pub fn get_device_type(&self) -> &str { + match self.device_properties.device_type { + vk::PhysicalDeviceType::CPU => "CPU", + vk::PhysicalDeviceType::INTEGRATED_GPU => "INTEGRATED_GPU", + vk::PhysicalDeviceType::DISCRETE_GPU => "DISCRETE_GPU", + vk::PhysicalDeviceType::VIRTUAL_GPU => "VIRTUAL_GPU", + _ => "OTHER", + } + } + pub fn get_vendor_name(&self) -> &str { + match self.device_properties.vendor_id { + 0x1002 => "AMD", + 0x1010 => "ImgTec", + 0x10DE => "NVIDIA Corporation", + 0x13B5 => "ARM", + 0x5143 => "Qualcomm", + 0x8086 => "INTEL Corporation", + _ => "Unknown vendor", + } + } +} + +impl Drop for Device { + fn drop(&mut self) { + unsafe { + self.device.destroy_command_pool(self.command_pool, None); + { + let mut allocator = self.allocator.lock(); + allocator.cleanup(AshMemoryDevice::wrap(&self.device)); + } + self.device.destroy_device(None); + } + } +} + +pub struct HostBuffer { + pub address: u64, + pub size: u64, + pub buffer: vk::Buffer, + pub memory: ManuallyDrop>, + pub data: &'static mut [u8], + device: Arc, + allocator: Arc>>, +} + +impl std::ops::Deref for HostBuffer { + type Target = [u8]; + fn deref(&self) -> &Self::Target { + self.data + } +} + +impl std::ops::DerefMut for HostBuffer { + fn deref_mut(&mut self) -> &mut Self::Target { + self.data + } +} + +impl Drop for HostBuffer { + fn drop(&mut self) { + unsafe { + self.device.destroy_buffer(self.buffer, None); + { + let mut allocator = self.allocator.lock(); + let memory = ManuallyDrop::take(&mut self.memory); + allocator.dealloc(AshMemoryDevice::wrap(&self.device), memory); + } + } + } +} + +pub struct HostBufferTyped { + pub address: u64, + pub buffer: vk::Buffer, + pub memory: ManuallyDrop>, + pub data: &'static mut T, + device: Arc, + allocator: Arc>>, +} + +impl std::ops::Deref for HostBufferTyped { + type Target = T; + fn deref(&self) -> &Self::Target { + self.data + } +} + +impl std::ops::DerefMut for HostBufferTyped { + fn deref_mut(&mut self) -> &mut Self::Target { + self.data + } +} + +impl Drop for HostBufferTyped { + fn drop(&mut self) { + unsafe { + self.device.destroy_buffer(self.buffer, None); + { + let mut allocator = self.allocator.lock(); + let memory = ManuallyDrop::take(&mut self.memory); + allocator.dealloc(AshMemoryDevice::wrap(&self.device), memory); + } + } + } +} + +#[derive(Debug)] +pub struct RendererInfo { + pub device_name: String, + pub device_type: String, + pub vendor_name: String, +} + +impl std::fmt::Display for RendererInfo { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!(f, "Vendor name: {}", self.vendor_name)?; + writeln!(f, "Device name: {}", self.device_name)?; + writeln!(f, "Device type: {}", self.device_type)?; + Ok(()) + } +} diff --git a/src/input.rs b/src/input.rs index d6890ec..2045dd3 100644 --- a/src/input.rs +++ b/src/input.rs @@ -1,16 +1,17 @@ use super::PushConstant; -use winit::event::{ElementState, VirtualKeyCode}; +use winit::{ + event::{ElementState, KeyEvent, RawKeyEvent}, + keyboard::{KeyCode, PhysicalKey}, +}; #[derive(Debug, Default)] pub struct Input { - pub up_pressed: bool, - pub down_pressed: bool, - pub right_pressed: bool, - pub left_pressed: bool, - pub slash_pressed: bool, - pub right_shift_pressed: bool, - pub enter_pressed: bool, - pub space_pressed: bool, + pub move_forward: bool, + pub move_backward: bool, + pub move_right: bool, + pub move_left: bool, + pub move_up: bool, + pub move_down: bool, } impl Input { @@ -18,63 +19,52 @@ impl Input { Default::default() } - pub fn update(&mut self, key: &VirtualKeyCode, state: &ElementState) -> bool { - let pressed = state == &ElementState::Pressed; - match key { - VirtualKeyCode::Up => { - self.up_pressed = pressed; - true + pub fn update_window_input(&mut self, key_event: &KeyEvent) { + let pressed = key_event.state == ElementState::Pressed; + if let PhysicalKey::Code(key) = key_event.physical_key { + match key { + KeyCode::KeyA => self.move_left = pressed, + KeyCode::KeyD => self.move_right = pressed, + KeyCode::KeyS => self.move_backward = pressed, + KeyCode::KeyW => self.move_forward = pressed, + KeyCode::Period | KeyCode::KeyQ => self.move_down = pressed, + KeyCode::Slash | KeyCode::KeyE => self.move_up = pressed, + _ => {} } - VirtualKeyCode::Down => { - self.down_pressed = pressed; - true - } - VirtualKeyCode::Left => { - self.left_pressed = pressed; - true - } - VirtualKeyCode::Right => { - self.right_pressed = pressed; - true - } - VirtualKeyCode::Slash => { - self.slash_pressed = pressed; - true - } - VirtualKeyCode::RShift => { - self.right_shift_pressed = pressed; - true - } - VirtualKeyCode::Return => { - self.enter_pressed = pressed; - true - } - VirtualKeyCode::Space => { - self.space_pressed = pressed; - true + } + } + + pub fn update_device_input(&mut self, key_event: RawKeyEvent) { + let pressed = key_event.state == ElementState::Pressed; + if let PhysicalKey::Code(key) = key_event.physical_key { + match key { + KeyCode::ArrowLeft => self.move_left = pressed, + KeyCode::ArrowRight => self.move_right = pressed, + KeyCode::ArrowDown => self.move_backward = pressed, + KeyCode::ArrowUp => self.move_forward = pressed, + _ => {} } - _ => false, } } pub fn process_position(&self, push_constant: &mut PushConstant) { let dx = 0.01; - if self.left_pressed { + if self.move_left { push_constant.pos[0] -= dx; } - if self.right_pressed { + if self.move_right { push_constant.pos[0] += dx; } - if self.down_pressed { + if self.move_backward { push_constant.pos[1] -= dx; } - if self.up_pressed { + if self.move_forward { push_constant.pos[1] += dx; } - if self.slash_pressed { + if self.move_down { push_constant.pos[2] -= dx; } - if self.right_shift_pressed { + if self.move_up { push_constant.pos[2] += dx; } } diff --git a/src/instance.rs b/src/instance.rs new file mode 100644 index 0000000..aaa8824 --- /dev/null +++ b/src/instance.rs @@ -0,0 +1,230 @@ +use std::{collections::HashSet, sync::Arc}; + +use crate::{ + device::{Device, DeviceExt}, + surface::Surface, + RawDevice, +}; + +use anyhow::{Context, Result}; +use ash::{ext, khr, vk, Entry}; +use parking_lot::Mutex; +use raw_window_handle::{HasDisplayHandle, HasWindowHandle}; + +pub struct Instance { + pub entry: ash::Entry, + pub instance: ash::Instance, +} + +impl std::ops::Deref for Instance { + type Target = ash::Instance; + + fn deref(&self) -> &Self::Target { + &self.instance + } +} + +impl Instance { + pub fn new(display_handle: Option<&impl HasDisplayHandle>) -> Result { + let entry = unsafe { Entry::load() }?; + let layers = [ + #[cfg(debug_assertions)] + c"VK_LAYER_KHRONOS_validation".as_ptr(), + ]; + let mut extensions = vec![ + khr::surface::NAME.as_ptr(), + khr::display::NAME.as_ptr(), + khr::get_physical_device_properties2::NAME.as_ptr(), + ]; + if let Some(handle) = display_handle { + extensions.extend(ash_window::enumerate_required_extensions( + handle.display_handle()?.as_raw(), + )?); + } + + let appinfo = vk::ApplicationInfo::default() + .application_name(c"Modern Vulkan") + .api_version(vk::API_VERSION_1_3); + let instance_info = vk::InstanceCreateInfo::default() + .application_info(&appinfo) + .flags(vk::InstanceCreateFlags::default()) + .enabled_layer_names(&layers) + .enabled_extension_names(&extensions); + let instance = unsafe { entry.create_instance(&instance_info, None) }?; + Ok(Self { entry, instance }) + } + + pub fn create_device_and_queues( + &self, + surface: &Surface, + ) -> Result<(Device, vk::Queue, vk::Queue)> { + let required_device_extensions = [ + khr::swapchain::NAME, + ext::graphics_pipeline_library::NAME, + khr::pipeline_library::NAME, + khr::dynamic_rendering::NAME, + ext::extended_dynamic_state2::NAME, + ext::extended_dynamic_state::NAME, + khr::synchronization2::NAME, + khr::buffer_device_address::NAME, + khr::create_renderpass2::NAME, + ext::descriptor_indexing::NAME, + ]; + let required_device_extensions_set = HashSet::from(required_device_extensions); + + let devices = unsafe { self.enumerate_physical_devices() }?; + let (pdevice, main_queue_family_idx, transfer_queue_family_idx) = + devices + .into_iter() + .find_map(|device| { + let extensions = + unsafe { self.enumerate_device_extension_properties(device) }.ok()?; + let extensions: HashSet<_> = extensions + .iter() + .map(|x| x.extension_name_as_c_str().unwrap()) + .collect(); + let missing = required_device_extensions_set.difference(&extensions); + if missing.count() > 0 { + return None; + } + + use vk::QueueFlags as QF; + let queue_properties = + unsafe { self.get_physical_device_queue_family_properties(device) }; + let main_queue_idx = + queue_properties + .iter() + .enumerate() + .find_map(|(family_idx, properties)| { + let family_idx = family_idx as u32; + + let queue_support = + properties.queue_flags.contains(QF::GRAPHICS | QF::TRANSFER); + let surface_support = + surface.get_device_surface_support(device, family_idx); + (queue_support && surface_support).then_some(family_idx) + }); + + let transfer_queue_idx = queue_properties.iter().enumerate().find_map( + |(family_idx, properties)| { + let family_idx = family_idx as u32; + let queue_support = properties.queue_flags.contains(QF::TRANSFER) + && !properties.queue_flags.contains(QF::GRAPHICS); + (Some(family_idx) != main_queue_idx && queue_support) + .then_some(family_idx) + }, + )?; + + Some((device, main_queue_idx?, transfer_queue_idx)) + }) + .context("Failed to find suitable device.")?; + + let queue_infos = [ + vk::DeviceQueueCreateInfo::default() + .queue_family_index(main_queue_family_idx) + .queue_priorities(&[1.0]), + vk::DeviceQueueCreateInfo::default() + .queue_family_index(transfer_queue_family_idx) + .queue_priorities(&[0.5]), + ]; + + let required_device_extensions = required_device_extensions.map(|x| x.as_ptr()); + + let mut feature_dynamic_state = + vk::PhysicalDeviceExtendedDynamicState2FeaturesEXT::default(); + let mut feature_descriptor_indexing = + vk::PhysicalDeviceDescriptorIndexingFeatures::default() + .runtime_descriptor_array(true) + .shader_sampled_image_array_non_uniform_indexing(true) + .shader_storage_image_array_non_uniform_indexing(true) + .shader_storage_buffer_array_non_uniform_indexing(true) + .shader_uniform_buffer_array_non_uniform_indexing(true) + .descriptor_binding_sampled_image_update_after_bind(true) + .descriptor_binding_partially_bound(true) + .descriptor_binding_variable_descriptor_count(true) + .descriptor_binding_update_unused_while_pending(true); + let mut feature_buffer_device_address = + vk::PhysicalDeviceBufferDeviceAddressFeatures::default().buffer_device_address(true); + let mut feature_synchronization2 = + vk::PhysicalDeviceSynchronization2Features::default().synchronization2(true); + let mut feature_pipeline_library = + vk::PhysicalDeviceGraphicsPipelineLibraryFeaturesEXT::default() + .graphics_pipeline_library(true); + let mut feature_dynamic_rendering = + vk::PhysicalDeviceDynamicRenderingFeatures::default().dynamic_rendering(true); + + let mut features = vk::PhysicalDeviceFeatures::default().shader_int64(true); + if cfg!(debug_assertions) { + features.robust_buffer_access = 1; + } + + let mut default_features = vk::PhysicalDeviceFeatures2::default() + .features(features) + .push_next(&mut feature_descriptor_indexing) + .push_next(&mut feature_buffer_device_address) + .push_next(&mut feature_synchronization2) + .push_next(&mut feature_dynamic_state) + .push_next(&mut feature_pipeline_library) + .push_next(&mut feature_dynamic_rendering); + + let device_info = vk::DeviceCreateInfo::default() + .queue_create_infos(&queue_infos) + .enabled_extension_names(&required_device_extensions) + .push_next(&mut default_features); + let device = unsafe { self.instance.create_device(pdevice, &device_info, None) }?; + + let memory_properties = unsafe { self.get_physical_device_memory_properties(pdevice) }; + + let dynamic_rendering = khr::dynamic_rendering::Device::new(self, &device); + + let device_alloc_properties = + unsafe { gpu_alloc_ash::device_properties(self, vk::API_VERSION_1_3, pdevice)? }; + let allocator = + gpu_alloc::GpuAllocator::new(gpu_alloc::Config::i_am_potato(), device_alloc_properties); + + let mut descriptor_indexing_props = + vk::PhysicalDeviceDescriptorIndexingProperties::default(); + let mut device_properties = + vk::PhysicalDeviceProperties2::default().push_next(&mut descriptor_indexing_props); + unsafe { self.get_physical_device_properties2(pdevice, &mut device_properties) }; + + let command_pool = unsafe { + device.create_command_pool( + &vk::CommandPoolCreateInfo::default() + .flags(vk::CommandPoolCreateFlags::TRANSIENT) + .queue_family_index(main_queue_family_idx), + None, + )? + }; + + let device = Device { + physical_device: pdevice, + device_properties: device_properties.properties, + descriptor_indexing_props, + main_queue_family_idx, + transfer_queue_family_idx, + command_pool, + memory_properties, + allocator: Arc::new(Mutex::new(allocator)), + device: Arc::new(RawDevice::new(device)), + ext: Arc::new(DeviceExt { dynamic_rendering }), + }; + let main_queue = unsafe { device.get_device_queue(main_queue_family_idx, 0) }; + let transfer_queue = unsafe { device.get_device_queue(transfer_queue_family_idx, 0) }; + + Ok((device, main_queue, transfer_queue)) + } + + pub fn create_surface( + &self, + handle: &(impl HasDisplayHandle + HasWindowHandle), + ) -> Result { + Surface::new(&self.entry, &self.instance, handle) + } +} + +impl Drop for Instance { + fn drop(&mut self) { + unsafe { self.instance.destroy_instance(None) }; + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..40554e6 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,352 @@ +#![allow(clippy::new_without_default)] +#![allow(clippy::too_many_arguments)] + +pub mod default_shaders; +mod device; +mod input; +mod instance; +mod pipeline_arena; +mod recorder; +mod shader_compiler; +mod surface; +mod swapchain; +mod texture_arena; +mod watcher; + +use std::{ + fs::File, + io, + mem::ManuallyDrop, + ops::{Add, Rem, Sub}, + path::Path, + sync::Arc, + time::Duration, +}; + +pub use self::{ + device::{Device, HostBufferTyped, RawDevice}, + input::Input, + instance::Instance, + pipeline_arena::*, + recorder::{RecordEvent, Recorder}, + shader_compiler::ShaderCompiler, + surface::Surface, + swapchain::Swapchain, + texture_arena::*, + watcher::Watcher, +}; + +use anyhow::{bail, Context}; +use ash::vk::{self, DeviceMemory}; +use gpu_alloc::{GpuAllocator, MapError, MemoryBlock}; +use gpu_alloc_ash::AshMemoryDevice; +use parking_lot::Mutex; + +pub const SHADER_DUMP_FOLDER: &str = "shader_dump"; +pub const SHADER_FOLDER: &str = "shaders"; +pub const VIDEO_FOLDER: &str = "recordings"; +pub const SCREENSHOT_FOLDER: &str = "screenshots"; + +pub const COLOR_SUBRESOURCE_MASK: vk::ImageSubresourceRange = vk::ImageSubresourceRange { + aspect_mask: vk::ImageAspectFlags::COLOR, + base_mip_level: 0, + level_count: vk::REMAINING_MIP_LEVELS, + base_array_layer: 0, + layer_count: vk::REMAINING_ARRAY_LAYERS, +}; + +// pub fn align_to(value: u64, alignment: u64) -> u64 { +// (value + alignment - 1) & !(alignment - 1) +// } + +pub fn align_to(value: T, alignment: T) -> T +where + T: Add + Copy + Default + PartialEq + Rem + Sub, +{ + let remainder = value % alignment; + if remainder == T::default() { + value + } else { + value + alignment - remainder + } +} + +pub fn dispatch_optimal(len: u32, subgroup_size: u32) -> u32 { + let padded_size = (subgroup_size - len % subgroup_size) % subgroup_size; + (len + padded_size) / subgroup_size +} + +pub fn create_folder>(name: P) -> io::Result<()> { + match std::fs::create_dir(name) { + Ok(_) => {} + Err(e) if e.kind() == io::ErrorKind::AlreadyExists => {} + Err(e) => return Err(e), + } + + Ok(()) +} + +pub fn print_help() { + println!(); + println!("- `F1`: Print help"); + println!("- `F2`: Toggle play/pause"); + println!("- `F3`: Pause and step back one frame"); + println!("- `F4`: Pause and step forward one frame"); + println!("- `F5`: Restart playback at frame 0 (`Time` and `Pos` = 0)"); + println!("- `F6`: Print parameters"); + println!("- `F10`: Save shaders"); + println!("- `F11`: Take Screenshot"); + println!("- `F12`: Start/Stop record video"); + println!("- `ESC`: Exit the application"); + println!("- `Arrows`: Change `Pos`\n"); +} + +#[derive(Debug)] +pub struct Args { + pub inner_size: Option<(u32, u32)>, + pub record_time: Option, +} + +pub fn parse_args() -> anyhow::Result { + let mut inner_size = None; + let mut record_time = None; + let args = std::env::args().skip(1).step_by(2); + for (flag, value) in args.zip(std::env::args().skip(2).step_by(2)) { + match flag.trim() { + "--record" => { + let time = match value.split_once('.') { + Some((sec, ms)) => { + let seconds = sec.parse()?; + let millis: u32 = ms.parse()?; + Duration::new(seconds, millis * 1_000_000) + } + None => Duration::from_secs(value.parse()?), + }; + record_time = Some(time) + } + "--size" => { + let (w, h) = value + .split_once('x') + .context("Failed to parse window size: Missing 'x' delimiter")?; + inner_size = Some((w.parse()?, h.parse()?)); + } + _ => {} + } + } + + Ok(Args { + record_time, + inner_size, + }) +} + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct PushConstant { + pub pos: [f32; 3], + pub time: f32, + pub wh: [f32; 2], + pub mouse: [f32; 2], + pub mouse_pressed: u32, + pub frame: u32, + pub time_delta: f32, + pub record_time: f32, +} + +impl Default for PushConstant { + fn default() -> Self { + Self { + pos: [0.; 3], + time: 0., + wh: [1920.0, 1020.], + mouse: [0.; 2], + mouse_pressed: false as _, + frame: 0, + time_delta: 1. / 60., + record_time: 10., + } + } +} + +impl std::fmt::Display for PushConstant { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let time = Duration::from_secs_f32(self.time); + let time_delta = Duration::from_secs_f32(self.time_delta); + write!( + f, + "position:\t{:?}\n\ + time:\t\t{:#.2?}\n\ + time delta:\t{:#.3?}, fps: {:#.2?}\n\ + width, height:\t{:?}\nmouse:\t\t{:.2?}\n\ + frame:\t\t{}\nrecord_period:\t{}\n", + self.pos, + time, + time_delta, + 1. / self.time_delta, + self.wh, + self.mouse, + self.frame, + self.record_time + ) + } +} + +pub fn save_shaders>(path: P) -> anyhow::Result<()> { + let dump_folder = Path::new(SHADER_DUMP_FOLDER); + create_folder(dump_folder)?; + let dump_folder = + dump_folder.join(chrono::Local::now().format("%Y-%m-%d_%H-%M-%S").to_string()); + create_folder(&dump_folder)?; + let dump_folder = dump_folder.join(SHADER_FOLDER); + create_folder(&dump_folder)?; + + if !path.as_ref().is_dir() { + bail!("Folder wasn't supplied"); + } + let shaders = path.as_ref().read_dir()?; + + // for path in paths { + for shader in shaders { + let shader = shader?.path(); + let to = dump_folder.join(shader.strip_prefix(Path::new(SHADER_FOLDER).canonicalize()?)?); + if !to.exists() { + std::fs::create_dir_all(&to.parent().unwrap().canonicalize()?)?; + File::create(&to)?; + } + std::fs::copy(shader, &to)?; + eprintln!("Saved: {}", &to.display()); + } + + Ok(()) +} + +#[derive(Debug)] +pub enum UserEvent { + Glsl { path: std::path::PathBuf }, +} + +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct ShaderSource { + pub path: std::path::PathBuf, + pub kind: ShaderKind, +} + +#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)] +pub enum ShaderKind { + Fragment, + Vertex, + Compute, +} + +impl From for shaderc::ShaderKind { + fn from(value: ShaderKind) -> Self { + match value { + ShaderKind::Compute => shaderc::ShaderKind::Compute, + ShaderKind::Vertex => shaderc::ShaderKind::Vertex, + ShaderKind::Fragment => shaderc::ShaderKind::Fragment, + } + } +} + +#[derive(Debug, Clone, Copy)] +pub struct ImageDimensions { + pub width: usize, + pub height: usize, + pub padded_bytes_per_row: usize, + pub unpadded_bytes_per_row: usize, +} + +impl ImageDimensions { + pub fn new(width: usize, height: usize, alignment: u64) -> Self { + let channel_width = std::mem::size_of::<[u8; 4]>(); + let unpadded_bytes_per_row = width * channel_width; + let padded_bytes_per_row = align_to(unpadded_bytes_per_row, alignment as usize); + Self { + width, + height, + unpadded_bytes_per_row, + padded_bytes_per_row, + } + } +} + +pub struct ManagedImage { + pub image: vk::Image, + pub memory: ManuallyDrop>, + pub image_dimensions: ImageDimensions, + pub data: Option<&'static mut [u8]>, + pub format: vk::Format, + device: Arc, + allocator: Arc>>, +} + +impl ManagedImage { + pub fn new( + device: &Device, + info: &vk::ImageCreateInfo, + usage: gpu_alloc::UsageFlags, + ) -> anyhow::Result { + let image = unsafe { device.create_image(info, None)? }; + let memory_reqs = unsafe { device.get_image_memory_requirements(image) }; + let memory = device.alloc_memory(memory_reqs, usage)?; + unsafe { device.bind_image_memory(image, *memory.memory(), memory.offset()) }?; + let image_dimensions = ImageDimensions::new( + info.extent.width as _, + info.extent.height as _, + memory_reqs.alignment, + ); + Ok(Self { + image, + memory: ManuallyDrop::new(memory), + image_dimensions, + format: info.format, + data: None, + device: device.device.clone(), + allocator: device.allocator.clone(), + }) + } + + pub fn map_memory(&mut self) -> Result<&mut [u8], MapError> { + if self.data.is_some() { + return Err(MapError::AlreadyMapped); + } + let size = self.memory.size() as usize; + let offset = self.memory.offset(); + let ptr = unsafe { + self.memory + .map(AshMemoryDevice::wrap(&self.device), offset, size)? + }; + + let data = unsafe { std::slice::from_raw_parts_mut(ptr.as_ptr().cast(), size) }; + self.data = Some(data); + + Ok(self.data.as_mut().unwrap()) + } +} + +impl Drop for ManagedImage { + fn drop(&mut self) { + unsafe { + self.device.destroy_image(self.image, None); + { + let mut allocator = self.allocator.lock(); + let memory = ManuallyDrop::take(&mut self.memory); + allocator.dealloc(AshMemoryDevice::wrap(&self.device), memory); + } + } + } +} + +pub fn find_memory_type_index( + memory_prop: &vk::PhysicalDeviceMemoryProperties, + memory_type_bits: u32, + flags: vk::MemoryPropertyFlags, +) -> Option { + memory_prop.memory_types[..memory_prop.memory_type_count as _] + .iter() + .enumerate() + .find(|(index, memory_type)| { + (1 << index) & memory_type_bits != 0 && (memory_type.property_flags & flags) == flags + }) + .map(|(index, _memory_type)| index as _) +} diff --git a/src/main.rs b/src/main.rs index c1d8362..99f84a5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,349 +1,696 @@ -mod app; -mod default_shaders; -mod input; -// mod profiler_window; -mod recorder; -mod render_bundle; -mod shader_compiler; -mod utils; - -#[allow(dead_code)] -mod audio; - -// use profiler_window::ProfilerWindow; - +use core::panic; use std::{ - error::Error, + io::Write, path::{Path, PathBuf}, time::{Duration, Instant}, }; -use pilka_types::{PushConstant, ShaderInfo}; -use recorder::{RecordEvent, RecordTimer}; -use render_bundle::Renderer; -use utils::{parse_args, print_help, save_screenshot, save_shaders, Args}; - -use eyre::*; -use notify::{RecursiveMode, Watcher}; +use anyhow::{bail, Result}; +use ash::{khr, vk}; +use either::Either; +use pilka::{ + align_to, default_shaders, dispatch_optimal, parse_args, print_help, save_shaders, Args, + ComputeHandle, Device, FragmentOutputDesc, FragmentShaderDesc, Input, Instance, PipelineArena, + PushConstant, Recorder, RenderHandle, ShaderKind, ShaderSource, Surface, Swapchain, + TextureArena, UserEvent, VertexInputDesc, VertexShaderDesc, Watcher, COLOR_SUBRESOURCE_MASK, + PREV_FRAME_IMAGE_IDX, SCREENSIZED_IMAGE_INDICES, SHADER_FOLDER, +}; use winit::{ + application::ApplicationHandler, dpi::{LogicalSize, PhysicalPosition, PhysicalSize}, - event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent}, - event_loop::{ControlFlow, EventLoop}, - window::WindowBuilder, + event::{ElementState, KeyEvent, MouseButton, StartCause, WindowEvent}, + event_loop::EventLoopProxy, + keyboard::{Key, NamedKey}, + window::{Window, WindowAttributes}, }; -use app::App; - -pub const SCREENSHOTS_FOLDER: &str = "screenshots"; -pub const SHADER_DUMP_FOLDER: &str = "shader_dump"; -pub const VIDEO_FOLDER: &str = "recordings"; -pub const SHADER_PATH: &str = "shaders"; - -fn main() -> Result<(), Box> { - // Initialize error hook. - color_eyre::install()?; - env_logger::init(); - puffin::set_scopes_on(true); - - let Args { - record_time, - inner_size, - wgsl_mode, - } = parse_args(); - - // let mut audio_context = audio::AudioContext::new()?; +pub const UPDATES_PER_SECOND: u32 = 60; +pub const FIXED_TIME_STEP: f64 = 1. / UPDATES_PER_SECOND as f64; +pub const MAX_FRAME_TIME: f64 = 15. * FIXED_TIME_STEP; // 0.25; - let event_loop = EventLoop::new(); +#[allow(dead_code)] +struct AppInit { + window: Window, + input: Input, + + pause: bool, + timeline: Instant, + backup_time: Duration, + frame_instant: Instant, + frame_accumulated_time: f64, + + texture_arena: TextureArena, + + file_watcher: Watcher, + recorder: Recorder, + video_recording: bool, + record_time: Option, + + push_constant: PushConstant, + render_pipeline: RenderHandle, + compute_pipeline: ComputeHandle, + pipeline_arena: PipelineArena, + + queue: vk::Queue, + transfer_queue: vk::Queue, + + swapchain: Swapchain, + surface: Surface, + device: Device, + instance: Instance, +} - let main_window = { - let mut window_builder = WindowBuilder::new().with_title("Pilka"); - #[cfg(unix)] - { - use winit::platform::unix::WindowBuilderExtUnix; - window_builder = - window_builder.with_resize_increments(LogicalSize::::from((8, 2))); +impl AppInit { + fn new( + event_loop: &winit::event_loop::ActiveEventLoop, + proxy: EventLoopProxy, + window_attributes: WindowAttributes, + record_time: Option, + ) -> Result { + let window = event_loop.create_window(window_attributes)?; + let watcher = Watcher::new(proxy)?; + let mut recorder = Recorder::new(); + + let instance = Instance::new(Some(&window))?; + let surface = instance.create_surface(&window)?; + let (device, queue, transfer_queue) = instance.create_device_and_queues(&surface)?; + + let swapchain_loader = khr::swapchain::Device::new(&instance, &device); + let swapchain = Swapchain::new(&device, &surface, swapchain_loader)?; + + let mut pipeline_arena = PipelineArena::new(&device, watcher.clone())?; + + let extent = swapchain.extent(); + let video_recording = record_time.is_some(); + let push_constant = PushConstant { + wh: [extent.width as f32, extent.height as f32], + record_time: record_time.map(|t| t.as_secs_f32()).unwrap_or(10.), + ..Default::default() + }; + + let mut texture_arena = TextureArena::new(&device, swapchain.extent())?; + + let bytes = include_bytes!("../assets/dither.dds"); + let dds = ddsfile::Dds::read(&bytes[..])?; + let mut extent = vk::Extent3D { + width: dds.get_width(), + height: dds.get_height(), + depth: 1, + }; + let mut info = vk::ImageCreateInfo::default() + .extent(extent) + .image_type(vk::ImageType::TYPE_2D) + .format(vk::Format::R8G8B8A8_UNORM) + .usage(vk::ImageUsageFlags::SAMPLED | vk::ImageUsageFlags::TRANSFER_DST) + .samples(vk::SampleCountFlags::TYPE_1) + .mip_levels(1) + .array_layers(1) + .tiling(vk::ImageTiling::OPTIMAL); + texture_arena.push_image(&device, &queue, info, dds.get_data(0)?)?; + + let bytes = include_bytes!("../assets/noise.dds"); + let dds = ddsfile::Dds::read(&bytes[..])?; + extent.width = dds.get_width(); + extent.height = dds.get_height(); + info.extent = extent; + texture_arena.push_image(&device, &queue, info, dds.get_data(0)?)?; + + let bytes = include_bytes!("../assets/BLUE_RGBA_0.dds"); + let dds = ddsfile::Dds::read(&bytes[..])?; + extent.width = dds.get_width(); + extent.height = dds.get_height(); + info.extent = extent; + texture_arena.push_image(&device, &queue, info, dds.get_data(0)?)?; + + let vertex_shader_desc = VertexShaderDesc { + shader_path: "shaders/shader.vert".into(), + ..Default::default() + }; + let fragment_shader_desc = FragmentShaderDesc { + shader_path: "shaders/shader.frag".into(), + }; + let fragment_output_desc = FragmentOutputDesc { + surface_format: swapchain.format(), + ..Default::default() + }; + let push_constant_range = vk::PushConstantRange::default() + .size(size_of::() as _) + .stage_flags( + vk::ShaderStageFlags::VERTEX + | vk::ShaderStageFlags::FRAGMENT + | vk::ShaderStageFlags::COMPUTE, + ); + let render_pipeline = pipeline_arena.create_render_pipeline( + &VertexInputDesc::default(), + &vertex_shader_desc, + &fragment_shader_desc, + &fragment_output_desc, + &[push_constant_range], + &[texture_arena.images_set_layout], + )?; + + let compute_pipeline = pipeline_arena.create_compute_pipeline( + "shaders/shader.comp", + &[push_constant_range], + &[texture_arena.images_set_layout], + )?; + + if record_time.is_some() { + let mut image_dimensions = swapchain.image_dimensions; + image_dimensions.width = align_to(image_dimensions.width, 2); + image_dimensions.height = align_to(image_dimensions.height, 2); + recorder.start(image_dimensions); } - if let Some(size) = inner_size { - window_builder = window_builder - .with_resizable(false) - .with_inner_size(LogicalSize::::from(size)); - } else { - window_builder = window_builder.with_inner_size(LogicalSize::new(1280, 720)); - } - window_builder.build(&event_loop)? - }; - let shader_dir = PathBuf::new().join(SHADER_PATH); - if !shader_dir.is_dir() { - default_shaders::create_default_shaders(&shader_dir, wgsl_mode)?; - } - - let (folder_tx, folder_rx) = crossbeam_channel::unbounded(); - let mut watcher = notify::recommended_watcher(move |res| match res { - Ok(event) => { - folder_tx.send(event).unwrap(); - } - Err(e) => eprintln!("watch error: {:?}", e), - })?; - watcher.watch(Path::new(SHADER_PATH), RecursiveMode::Recursive)?; + Ok(Self { + window, + input: Input::default(), - let mut app = App::new(&main_window, folder_rx)?; + pause: false, + timeline: Instant::now(), + backup_time: Duration::from_secs(0), + frame_instant: Instant::now(), + frame_accumulated_time: 0., - let mut video_recording = false; - let (video_tx, video_rx) = crossbeam_channel::unbounded(); - std::thread::spawn(move || recorder::record_thread(video_rx)); + texture_arena, - let mut input = input::Input::new(); - let mut pause = false; + file_watcher: watcher, + video_recording, + record_time, + recorder, - let mut timeline = Instant::now(); - let mut prev_time = timeline.elapsed(); - let mut backup_time = timeline.elapsed(); - let mut dt = Duration::from_secs_f32(1. / 60.); + push_constant, + render_pipeline, + compute_pipeline, + pipeline_arena, - let mut last_update_inst = Instant::now(); + queue, + transfer_queue, - let (mut timer, start_event) = RecordTimer::new(record_time, video_tx.clone()); - if let Some(period) = record_time { - app.push_constant.record_period = period.as_secs_f32(); + surface, + swapchain, + device, + instance, + }) } - // let mut profiler_window: Option = None; - - event_loop.run(move |event, _event_loop, control_flow| { - *control_flow = winit::event_loop::ControlFlow::Poll; + fn update(&mut self) { + self.input.process_position(&mut self.push_constant); + } - // if let Some(ref mut w) = profiler_window { - // w.handle_event(&event); - // } + fn reload_shaders(&mut self, path: PathBuf) -> Result<()> { + if let Some(frame) = self.swapchain.get_current_frame() { + let fences = std::slice::from_ref(&frame.present_finished); + unsafe { self.device.wait_for_fences(fences, true, u64::MAX)? }; + } - match event { - Event::RedrawEventsCleared => { - puffin::profile_scope!("Redraw Timeout"); - let target_frametime = Duration::from_secs_f64(1.0 / 60.0); - let time_since_last_frame = last_update_inst.elapsed(); - if time_since_last_frame >= target_frametime { - main_window.request_redraw(); - // if let Some(ref mut w) = profiler_window { - // w.request_redraw(); - // } - last_update_inst = Instant::now(); - } else { - *control_flow = ControlFlow::WaitUntil( - Instant::now() + target_frametime - time_since_last_frame, - ); + let resolved = { + let mapping = self.file_watcher.include_mapping.lock(); + mapping[&path].clone() + }; + + for ShaderSource { path, kind } in resolved { + let handles = &self.pipeline_arena.path_mapping[&path]; + for handle in handles { + let compiler = &self.pipeline_arena.shader_compiler; + match handle { + Either::Left(handle) => { + let pipeline = &mut self.pipeline_arena.render.pipelines[*handle]; + match kind { + ShaderKind::Vertex => pipeline.reload_vertex_lib(compiler, &path), + ShaderKind::Fragment => pipeline.reload_fragment_lib(compiler, &path), + ShaderKind::Compute => { + bail!("Supplied compute shader into the render pipeline!") + } + }?; + pipeline.link()?; + } + Either::Right(handle) => { + let pipeline = &mut self.pipeline_arena.compute.pipelines[*handle]; + pipeline.reload(compiler)?; + } } } - Event::NewEvents(_) => { - puffin::profile_scope!("Frame setup"); - - app.setup_frame(); + } + Ok(()) + } - app.push_constant.time = if pause { - backup_time.as_secs_f32() - } else if let Some(recording_time) = timer.counter { - recording_time.elapsed().as_secs_f32() - } else { - timeline.elapsed().as_secs_f32() - }; + fn recreate_swapchain(&mut self) -> Result<()> { + self.swapchain + .recreate(&self.device, &self.surface) + .expect("Failed to recreate swapchain"); + let extent = self.swapchain.extent(); + self.push_constant.wh = [extent.width as f32, extent.height as f32]; + + for i in SCREENSIZED_IMAGE_INDICES { + self.texture_arena.image_infos[i].extent = vk::Extent3D { + width: extent.width, + height: extent.height, + depth: 1, + }; + } + self.texture_arena + .update_images(&SCREENSIZED_IMAGE_INDICES)?; - app.push_constant.wh = main_window.inner_size().into(); + Ok(()) + } +} - input.process_position(&mut app.push_constant); +impl ApplicationHandler for AppInit { + fn new_events( + &mut self, + event_loop: &winit::event_loop::ActiveEventLoop, + cause: winit::event::StartCause, + ) { + self.push_constant.time = if !self.pause { + self.timeline.elapsed().as_secs_f32() + } else { + self.backup_time.as_secs_f32() + }; + if let StartCause::WaitCancelled { .. } = cause { + let new_instant = Instant::now(); + let frame_time = new_instant + .duration_since(self.frame_instant) + .as_secs_f64() + .min(MAX_FRAME_TIME); + self.frame_instant = new_instant; + self.push_constant.time_delta = frame_time as _; + + self.frame_accumulated_time += frame_time; + while self.frame_accumulated_time >= FIXED_TIME_STEP { + self.update(); + + self.frame_accumulated_time -= FIXED_TIME_STEP; + } + } - if !pause { - // let mut tmp_buf = [0f32; audio::FFT_SIZE]; - // audio_context.get_fft(&mut tmp_buf); - // pilka.update_fft_texture(&tmp_buf).unwrap(); + if let Some(limit) = self.record_time { + if self.timeline.elapsed() >= limit && self.recorder.is_active() { + self.recorder.finish(); + event_loop.exit(); + } + } + } - dt = timeline.elapsed().saturating_sub(prev_time); - app.push_constant.time_delta = dt.as_secs_f32(); + fn device_event( + &mut self, + _event_loop: &winit::event_loop::ActiveEventLoop, + _device_id: winit::event::DeviceId, + event: winit::event::DeviceEvent, + ) { + if let winit::event::DeviceEvent::Key(key_event) = event { + self.input.update_device_input(key_event); + } + } - prev_time = timeline.elapsed(); - } + fn window_event( + &mut self, + event_loop: &winit::event_loop::ActiveEventLoop, + _window_id: winit::window::WindowId, + event: WindowEvent, + ) { + match event { + WindowEvent::CloseRequested + | WindowEvent::KeyboardInput { + event: + KeyEvent { + logical_key: Key::Named(NamedKey::Escape), + state: ElementState::Pressed, + .. + }, + .. + } => event_loop.exit(), - timer - .update(&mut video_recording, app.render.captured_frame_dimentions()) - .unwrap(); - } - Event::WindowEvent { + WindowEvent::KeyboardInput { event: - WindowEvent::Resized(size) - | WindowEvent::ScaleFactorChanged { - new_inner_size: &mut size, + KeyEvent { + logical_key: Key::Named(key), + state: ElementState::Pressed, + repeat: false, .. }, - window_id, + .. } => { - puffin::profile_scope!("Resize"); - let PhysicalSize { width, height } = size; + let dt = Duration::from_secs_f32(1. / 60.); + match key { + NamedKey::F1 => print_help(), + NamedKey::F2 => { + if !self.pause { + self.backup_time = self.timeline.elapsed(); + } else { + self.timeline = Instant::now() - self.backup_time; + } + self.pause = !self.pause; + } + NamedKey::F3 => { + if !self.pause { + self.backup_time = self.timeline.elapsed(); + self.pause = true; + } + self.backup_time = self.backup_time.saturating_sub(dt); + } + NamedKey::F4 => { + if !self.pause { + self.backup_time = self.timeline.elapsed(); + self.pause = true; + } + self.backup_time += dt; + } + NamedKey::F5 => { + self.push_constant.pos = [0.; 3]; + self.push_constant.time = 0.; + self.push_constant.frame = 0; + self.timeline = Instant::now(); + self.backup_time = self.timeline.elapsed(); + } + NamedKey::F6 => { + eprintln!("{}", self.push_constant); + } + NamedKey::F10 => { + let _ = save_shaders(SHADER_FOLDER).map_err(|err| eprintln!("{err}")); + } + NamedKey::F11 => { + let _ = self + .device + .capture_image_data( + &self.queue, + self.swapchain.get_current_image(), + self.swapchain.extent(), + |tex| self.recorder.screenshot(tex), + ) + .map_err(|err| eprintln!("{err}")); + } + NamedKey::F12 => { + if !self.video_recording { + let mut image_dimensions = self.swapchain.image_dimensions; + image_dimensions.width = align_to(image_dimensions.width, 2); + image_dimensions.height = align_to(image_dimensions.height, 2); + self.recorder.start(image_dimensions); + } else { + self.recorder.finish(); + } + self.video_recording = !self.video_recording; + } + _ => {} + } + } + WindowEvent::KeyboardInput { event, .. } => { + self.input.update_window_input(&event); + } - // if let Some(ref mut w) = profiler_window { - // if w.id() == window_id { - // w.resize(); - // } - // } + WindowEvent::MouseInput { + state, + button: MouseButton::Left, + .. + } => { + self.push_constant.mouse_pressed = (ElementState::Pressed == state) as u32; + } + WindowEvent::CursorMoved { + position: PhysicalPosition { x, y }, + .. + } => { + if !self.pause { + let PhysicalSize { width, height } = self.window.inner_size(); + let x = (x as f32 / width as f32 - 0.5) * 2.; + let y = -(y as f32 / height as f32 - 0.5) * 2.; + self.push_constant.mouse = [x, y]; + } + } + WindowEvent::RedrawRequested => { + let mut frame = match self.swapchain.acquire_next_image() { + Ok(frame) => frame, + Err(vk::Result::ERROR_OUT_OF_DATE_KHR) => { + let _ = self.recreate_swapchain().map_err(|err| eprintln!("{err}")); + self.window.request_redraw(); + return; + } + Err(e) => panic!("error: {e}\n"), + }; - if main_window.id() == window_id { - app.resize(width.max(1), height.max(1)).unwrap(); + let stages = vk::ShaderStageFlags::VERTEX + | vk::ShaderStageFlags::FRAGMENT + | vk::ShaderStageFlags::COMPUTE; + let pipeline = self.pipeline_arena.get_pipeline(self.compute_pipeline); + frame.push_constant(pipeline.layout, stages, &[self.push_constant]); + frame.bind_descriptor_sets( + vk::PipelineBindPoint::COMPUTE, + pipeline.layout, + &[self.texture_arena.images_set], + ); + frame.bind_pipeline(vk::PipelineBindPoint::COMPUTE, &pipeline.pipeline); + const SUBGROUP_SIZE: u32 = 16; + let extent = self.swapchain.extent(); + frame.dispatch( + dispatch_optimal(extent.width, SUBGROUP_SIZE), + dispatch_optimal(extent.height, SUBGROUP_SIZE), + 1, + ); + + unsafe { + let image_barrier = vk::ImageMemoryBarrier2::default() + .subresource_range(COLOR_SUBRESOURCE_MASK) + .src_stage_mask(vk::PipelineStageFlags2::COMPUTE_SHADER) + .dst_stage_mask(vk::PipelineStageFlags2::ALL_GRAPHICS) + .image(self.texture_arena.images[PREV_FRAME_IMAGE_IDX].image); + self.device.cmd_pipeline_barrier2( + *frame.command_buffer(), + &vk::DependencyInfo::default() + .image_memory_barriers(std::slice::from_ref(&image_barrier)), + ) + }; + + frame.begin_rendering( + self.swapchain.get_current_image_view(), + [0., 0.025, 0.025, 1.0], + ); + let pipeline = self.pipeline_arena.get_pipeline(self.render_pipeline); + frame.push_constant(pipeline.layout, stages, &[self.push_constant]); + frame.bind_descriptor_sets( + vk::PipelineBindPoint::GRAPHICS, + pipeline.layout, + &[self.texture_arena.images_set], + ); + frame.bind_pipeline(vk::PipelineBindPoint::GRAPHICS, &pipeline.pipeline); + + frame.draw(3, 0, 1, 0); + frame.end_rendering(); + + self.device.blit_image( + frame.command_buffer(), + self.swapchain.get_current_image(), + self.swapchain.extent(), + vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL, + &self.texture_arena.images[PREV_FRAME_IMAGE_IDX].image, + self.swapchain.extent(), + vk::ImageLayout::UNDEFINED, + ); + + match self.swapchain.submit_image(&self.queue, frame) { + Ok(_) => {} + Err(vk::Result::ERROR_OUT_OF_DATE_KHR) => { + let _ = self.recreate_swapchain().map_err(|err| eprintln!("{err}")); + } + Err(e) => panic!("error: {e}\n"), } - if video_recording { - println!("Stop recording. Resolution has been changed.",); - video_recording = false; - video_tx.send(RecordEvent::Finish).unwrap(); + self.window.request_redraw(); + + if self.video_recording && self.recorder.ffmpeg_installed() { + let res = self.device.capture_image_data( + &self.queue, + self.swapchain.get_current_image(), + self.swapchain.extent(), + |tex| self.recorder.record(tex), + ); + if let Err(err) = res { + eprintln!("{err}"); + self.video_recording = false; + } } - } - Event::WindowEvent { - event: WindowEvent::CloseRequested, - window_id: _window_id, - } => { - // let sec_id = profiler_window.as_ref().unwrap().id(); - // if window_id == sec_id { - // profiler_window = None; - // } + self.push_constant.frame = self.push_constant.frame.saturating_add(1); } + _ => {} + } + } - Event::WindowEvent { event, window_id } if main_window.id() == window_id => match event - { - WindowEvent::KeyboardInput { - input: - KeyboardInput { - virtual_keycode: Some(keycode), - state, - .. - }, - .. - } => { - puffin::profile_scope!("Keyboard Events"); - - input.update(&keycode, &state); - - if VirtualKeyCode::Escape == keycode { - *control_flow = ControlFlow::Exit; + fn user_event(&mut self, _event_loop: &winit::event_loop::ActiveEventLoop, event: UserEvent) { + match event { + UserEvent::Glsl { path } => { + match self.reload_shaders(path) { + Err(err) => eprintln!("{err}"), + Ok(()) => { + const ESC: &str = "\x1B["; + const RESET: &str = "\x1B[0m"; + eprint!("\r{}42m{}K{}\r", ESC, ESC, RESET); + std::io::stdout().flush().unwrap(); + std::thread::spawn(|| { + std::thread::sleep(std::time::Duration::from_millis(50)); + eprint!("\r{}40m{}K{}\r", ESC, ESC, RESET); + std::io::stdout().flush().unwrap(); + }); } + }; + } + } + } - if ElementState::Pressed == state { - if VirtualKeyCode::F1 == keycode { - print_help(); - } + fn exiting(&mut self, _event_loop: &winit::event_loop::ActiveEventLoop) { + self.recorder.close_thread(); + if let Some(handle) = self.recorder.thread_handle.take() { + let _ = handle.join(); + } + let _ = unsafe { self.device.device_wait_idle() }; + println!("// End from the loop. Bye bye~⏎ "); + } - if VirtualKeyCode::F2 == keycode { - if !pause { - backup_time = timeline.elapsed(); - pause = true; - } else { - timeline = Instant::now() - backup_time; - pause = false; - } - } + fn resumed(&mut self, _event_loop: &winit::event_loop::ActiveEventLoop) { + panic!("On native platforms `resumed` can be called only once.") + } +} - if VirtualKeyCode::F3 == keycode { - if !pause { - backup_time = timeline.elapsed(); - pause = true; - } - backup_time = backup_time.saturating_sub(dt); - } +fn main() -> Result<()> { + let event_loop = winit::event_loop::EventLoop::with_user_event().build()?; - if VirtualKeyCode::F4 == keycode { - if !pause { - backup_time = timeline.elapsed(); - pause = true; - } - backup_time += dt; - } + let Args { + record_time, + inner_size, + } = parse_args()?; - if VirtualKeyCode::F5 == keycode { - app.push_constant.pos = [0.; 3]; - app.push_constant.time = 0.; - app.push_constant.frame = 0; - timeline = Instant::now(); - backup_time = timeline.elapsed(); - } + let shader_dir = PathBuf::new().join(SHADER_FOLDER); + if !shader_dir.is_dir() { + default_shaders::create_default_shaders(&shader_dir)?; + } - if VirtualKeyCode::F6 == keycode { - eprintln!("{}", app.push_constant); - } + let mut app = App::new(event_loop.create_proxy(), record_time, inner_size); + event_loop.run_app(&mut app)?; + Ok(()) +} - if VirtualKeyCode::F7 == keycode { - // if profiler_window.is_some() { - // profiler_window = None; - // } else { - // profiler_window = Some(ProfilerWindow::new(event_loop).unwrap()); - // } - } +struct App { + proxy: EventLoopProxy, + record_time: Option, + initial_window_size: Option<(u32, u32)>, + inner: AppEnum, +} - if VirtualKeyCode::F8 == keycode { - app.render.switch(&main_window, &mut app.compiler).unwrap(); - } +impl App { + fn new( + proxy: EventLoopProxy, + record_time: Option, + inner_size: Option<(u32, u32)>, + ) -> Self { + Self { + proxy, + record_time, + initial_window_size: inner_size, + inner: AppEnum::Uninitialized, + } + } +} - if VirtualKeyCode::F10 == keycode { - save_shaders(&app.render.shader_list()).unwrap(); - } +#[derive(Default)] +enum AppEnum { + #[default] + Uninitialized, + Init(AppInit), +} - if VirtualKeyCode::F11 == keycode { - let now = Instant::now(); - let (frame, image_dimentions) = app.render.capture_frame().unwrap(); - eprintln!("Capture image: {:#.2?}", now.elapsed()); - save_screenshot(frame, image_dimentions); - } +impl ApplicationHandler for App { + fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) { + let mut window_attributes = WindowAttributes::default().with_title("myndgera"); + if let Some(size) = self.initial_window_size { + window_attributes = window_attributes + .with_resizable(false) + .with_inner_size(LogicalSize::::from(size)); + } + match self.inner { + AppEnum::Uninitialized => { + let app = AppInit::new( + event_loop, + self.proxy.clone(), + window_attributes, + self.record_time, + ) + .expect("Failed to create application"); + + println!("{}", app.device.get_info()); + println!("{}", app.recorder.ffmpeg_version); + println!( + "Default shader path:\n\t{}", + Path::new(SHADER_FOLDER).canonicalize().unwrap().display() + ); + print_help(); + + println!("// Set up our new world⏎ "); + println!("// And let's begin the⏎ "); + println!("\tSIMULATION⏎ \n"); + + self.inner = AppEnum::Init(app); + } + AppEnum::Init(_) => {} + } + } - if app.has_ffmpeg && VirtualKeyCode::F12 == keycode { - if video_recording { - video_tx.send(RecordEvent::Finish).unwrap() - } else { - let (_, image_dimentions) = app.render.capture_frame().unwrap(); - video_tx.send(RecordEvent::Start(image_dimentions)).unwrap() - } - video_recording = !video_recording; - } - } - } + fn window_event( + &mut self, + event_loop: &winit::event_loop::ActiveEventLoop, + window_id: winit::window::WindowId, + event: WindowEvent, + ) { + if let AppEnum::Init(app) = &mut self.inner { + app.window_event(event_loop, window_id, event); + } + } - WindowEvent::CursorMoved { - position: PhysicalPosition { x, y }, - .. - } => { - if !pause { - let PhysicalSize { width, height } = main_window.inner_size(); - let x = (x as f32 / width as f32 - 0.5) * 2.; - let y = -(y as f32 / height as f32 - 0.5) * 2.; - app.push_constant.mouse = [x, y]; - } - } - WindowEvent::MouseInput { - button: winit::event::MouseButton::Left, - state, - .. - } => match state { - ElementState::Pressed => app.push_constant.mouse_pressed = true as _, - ElementState::Released => app.push_constant.mouse_pressed = false as _, - }, - _ => {} - }, - Event::RedrawRequested(_) => { - puffin::GlobalProfiler::lock().new_frame(); - puffin::profile_scope!("Rendering"); - - // if let Some(w) = &mut profiler_window { - // w.render(&timeline); - // } - - app.render(); - - start_event.try_send(()).ok(); - if video_recording { - let (frame, _image_dimentions) = app.render.capture_frame().unwrap(); - video_tx.send(RecordEvent::Record(frame)).unwrap() - } - } - Event::LoopDestroyed => { - app.shut_down(); - println!("// End from the loop. Bye bye~⏎ "); - } - _ => {} + fn new_events( + &mut self, + event_loop: &winit::event_loop::ActiveEventLoop, + cause: winit::event::StartCause, + ) { + if let AppEnum::Init(app) = &mut self.inner { + app.new_events(event_loop, cause); } - }); + } + + fn user_event(&mut self, event_loop: &winit::event_loop::ActiveEventLoop, event: UserEvent) { + if let AppEnum::Init(app) = &mut self.inner { + app.user_event(event_loop, event) + } + } + + fn device_event( + &mut self, + event_loop: &winit::event_loop::ActiveEventLoop, + device_id: winit::event::DeviceId, + event: winit::event::DeviceEvent, + ) { + if let AppEnum::Init(app) = &mut self.inner { + app.device_event(event_loop, device_id, event) + } + } + + fn about_to_wait(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) { + if let AppEnum::Init(app) = &mut self.inner { + app.about_to_wait(event_loop) + } + } + + fn suspended(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) { + if let AppEnum::Init(app) = &mut self.inner { + app.suspended(event_loop) + } + } + + fn exiting(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) { + if let AppEnum::Init(app) = &mut self.inner { + app.exiting(event_loop) + } + } + + fn memory_warning(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) { + if let AppEnum::Init(app) = &mut self.inner { + app.memory_warning(event_loop) + } + } } diff --git a/src/pipeline_arena.rs b/src/pipeline_arena.rs new file mode 100644 index 0000000..6551061 --- /dev/null +++ b/src/pipeline_arena.rs @@ -0,0 +1,597 @@ +use ahash::{AHashMap, AHashSet}; +use anyhow::Result; +use either::Either; +use slotmap::SlotMap; +use std::{ + path::{Path, PathBuf}, + sync::Arc, +}; + +use ash::{ + prelude::VkResult, + vk::{self}, +}; + +use crate::{Device, RawDevice, ShaderCompiler, ShaderKind, ShaderSource, Watcher}; + +pub struct ComputePipeline { + pub layout: vk::PipelineLayout, + pub pipeline: vk::Pipeline, + shader_path: PathBuf, + device: RawDevice, +} + +impl Drop for ComputePipeline { + fn drop(&mut self) { + unsafe { + self.device.destroy_pipeline(self.pipeline, None); + self.device.destroy_pipeline_layout(self.layout, None); + } + } +} + +impl ComputePipeline { + fn new( + device: &RawDevice, + shader_compiler: &ShaderCompiler, + shader_path: impl AsRef, + push_constant_ranges: &[vk::PushConstantRange], + descriptor_set_layouts: &[vk::DescriptorSetLayout], + ) -> Result { + let cs_bytes = shader_compiler.compile(&shader_path, shaderc::ShaderKind::Compute)?; + + let pipeline_layout = unsafe { + device.create_pipeline_layout( + &vk::PipelineLayoutCreateInfo::default() + .set_layouts(descriptor_set_layouts) + .push_constant_ranges(push_constant_ranges), + None, + )? + }; + + let mut shader_module = vk::ShaderModuleCreateInfo::default().code(cs_bytes.as_binary()); + let shader_stage = vk::PipelineShaderStageCreateInfo::default() + .stage(vk::ShaderStageFlags::COMPUTE) + .name(c"main") + .push_next(&mut shader_module); + + let create_info = vk::ComputePipelineCreateInfo::default() + .layout(pipeline_layout) + .stage(shader_stage); + let pipeline = unsafe { + device.create_compute_pipelines(vk::PipelineCache::null(), &[create_info], None) + }; + let pipeline = pipeline.map_err(|(_, err)| err)?[0]; + + Ok(Self { + pipeline, + shader_path: shader_path.as_ref().to_path_buf(), + layout: pipeline_layout, + device: device.clone(), + }) + } + + pub fn reload(&mut self, shader_compiler: &ShaderCompiler) -> Result<()> { + let cs_bytes = shader_compiler.compile(&self.shader_path, shaderc::ShaderKind::Compute)?; + + unsafe { self.device.destroy_pipeline(self.pipeline, None) } + + let mut shader_module = vk::ShaderModuleCreateInfo::default().code(cs_bytes.as_binary()); + let shader_stage = vk::PipelineShaderStageCreateInfo::default() + .stage(vk::ShaderStageFlags::COMPUTE) + .name(c"main") + .push_next(&mut shader_module); + + let create_info = vk::ComputePipelineCreateInfo::default() + .layout(self.layout) + .stage(shader_stage); + let pipeline = unsafe { + self.device + .create_compute_pipelines(vk::PipelineCache::null(), &[create_info], None) + }; + let pipeline = pipeline.map_err(|(_, err)| err)?[0]; + + self.pipeline = pipeline; + + Ok(()) + } +} + +pub struct VertexInputDesc { + pub primitive_topology: vk::PrimitiveTopology, + pub primitive_restart: bool, +} + +impl Default for VertexInputDesc { + fn default() -> Self { + Self { + primitive_topology: vk::PrimitiveTopology::TRIANGLE_LIST, + primitive_restart: false, + } + } +} + +pub struct VertexShaderDesc { + pub shader_path: PathBuf, + pub dynamic_state: Vec, + pub line_width: f32, + pub polygon_mode: vk::PolygonMode, + pub cull_mode: vk::CullModeFlags, + pub front_face: vk::FrontFace, + pub viewport_count: u32, + pub scissot_count: u32, +} + +impl Default for VertexShaderDesc { + fn default() -> Self { + Self { + shader_path: PathBuf::new(), + dynamic_state: vec![vk::DynamicState::VIEWPORT, vk::DynamicState::SCISSOR], + line_width: 1.0, + polygon_mode: vk::PolygonMode::FILL, + cull_mode: vk::CullModeFlags::BACK, + front_face: vk::FrontFace::COUNTER_CLOCKWISE, + viewport_count: 1, + scissot_count: 1, + } + } +} + +pub struct FragmentShaderDesc { + pub shader_path: PathBuf, +} + +pub struct FragmentOutputDesc { + pub surface_format: vk::Format, + pub multisample_state: vk::SampleCountFlags, +} + +impl Default for FragmentOutputDesc { + fn default() -> Self { + Self { + surface_format: vk::Format::B8G8R8A8_SRGB, + multisample_state: vk::SampleCountFlags::TYPE_1, + } + } +} + +pub struct RenderPipeline { + pub layout: vk::PipelineLayout, + pub pipeline: vk::Pipeline, + vertex_input_lib: vk::Pipeline, + vertex_shader_lib: vk::Pipeline, + fragment_shader_lib: vk::Pipeline, + fragment_output_lib: vk::Pipeline, + device: RawDevice, +} + +impl RenderPipeline { + pub fn new( + device: &RawDevice, + shader_compiler: &ShaderCompiler, + vertex_input_desc: &VertexInputDesc, + vertex_shader_desc: &VertexShaderDesc, + fragment_shader_desc: &FragmentShaderDesc, + fragment_output_desc: &FragmentOutputDesc, + push_constant_ranges: &[vk::PushConstantRange], + descriptor_set_layouts: &[vk::DescriptorSetLayout], + ) -> Result { + let vs_bytes = shader_compiler + .compile(&vertex_shader_desc.shader_path, shaderc::ShaderKind::Vertex)?; + let fs_bytes = shader_compiler.compile( + &fragment_shader_desc.shader_path, + shaderc::ShaderKind::Fragment, + )?; + + let pipeline_layout = unsafe { + device.create_pipeline_layout( + &vk::PipelineLayoutCreateInfo::default() + .set_layouts(descriptor_set_layouts) + .push_constant_ranges(push_constant_ranges), + None, + )? + }; + + use vk::GraphicsPipelineLibraryFlagsEXT as GPF; + let vertex_input_lib = { + let input_ass = vk::PipelineInputAssemblyStateCreateInfo::default() + .topology(vertex_input_desc.primitive_topology) + .primitive_restart_enable(vertex_input_desc.primitive_restart); + let vertex_input = vk::PipelineVertexInputStateCreateInfo::default(); + + create_library(device, GPF::VERTEX_INPUT_INTERFACE, |desc| { + desc.vertex_input_state(&vertex_input) + .input_assembly_state(&input_ass) + })? + }; + + let vertex_shader_lib = { + let mut shader_module = + vk::ShaderModuleCreateInfo::default().code(vs_bytes.as_binary()); + let shader_stage = vk::PipelineShaderStageCreateInfo::default() + .stage(vk::ShaderStageFlags::VERTEX) + .name(c"main") + .push_next(&mut shader_module); + let dynamic_state = vk::PipelineDynamicStateCreateInfo::default() + .dynamic_states(&vertex_shader_desc.dynamic_state); + let rasterization_state = vk::PipelineRasterizationStateCreateInfo::default() + .line_width(vertex_shader_desc.line_width) + .polygon_mode(vertex_shader_desc.polygon_mode) + .cull_mode(vertex_shader_desc.cull_mode) + .front_face(vertex_shader_desc.front_face); + let viewport_state = vk::PipelineViewportStateCreateInfo::default() + .viewport_count(vertex_shader_desc.viewport_count) + .scissor_count(vertex_shader_desc.scissot_count); + + create_library(device, GPF::PRE_RASTERIZATION_SHADERS, |desc| { + desc.layout(pipeline_layout) + .stages(std::slice::from_ref(&shader_stage)) + .dynamic_state(&dynamic_state) + .viewport_state(&viewport_state) + .rasterization_state(&rasterization_state) + })? + }; + + let fragment_shader_lib = { + let mut shader_module = + vk::ShaderModuleCreateInfo::default().code(fs_bytes.as_binary()); + let shader_stage = vk::PipelineShaderStageCreateInfo::default() + .stage(vk::ShaderStageFlags::FRAGMENT) + .name(c"main") + .push_next(&mut shader_module); + + let depth_stencil_state = vk::PipelineDepthStencilStateCreateInfo::default(); + + create_library(device, GPF::FRAGMENT_SHADER, |desc| { + desc.layout(pipeline_layout) + .stages(std::slice::from_ref(&shader_stage)) + .depth_stencil_state(&depth_stencil_state) + })? + }; + + let fragment_output_lib = { + let color_attachment_formats = [fragment_output_desc.surface_format]; + let mut dyn_render = vk::PipelineRenderingCreateInfo::default() + .color_attachment_formats(&color_attachment_formats); + + let multisample_state = vk::PipelineMultisampleStateCreateInfo::default() + .rasterization_samples(vk::SampleCountFlags::TYPE_1); + + create_library(device, GPF::FRAGMENT_OUTPUT_INTERFACE, |desc| { + desc.multisample_state(&multisample_state) + .push_next(&mut dyn_render) + })? + }; + + let pipeline = Self::link_libraries( + device, + &pipeline_layout, + &vertex_input_lib, + &vertex_shader_lib, + &fragment_shader_lib, + &fragment_output_lib, + )?; + + Ok(Self { + device: device.clone(), + layout: pipeline_layout, + pipeline, + vertex_input_lib, + vertex_shader_lib, + fragment_shader_lib, + fragment_output_lib, + }) + } + + pub fn reload_vertex_lib( + &mut self, + shader_compiler: &ShaderCompiler, + shader_path: impl AsRef, + ) -> Result<()> { + let vs_bytes = shader_compiler.compile(shader_path, shaderc::ShaderKind::Vertex)?; + + unsafe { self.device.destroy_pipeline(self.vertex_shader_lib, None) }; + + let mut shader_module = vk::ShaderModuleCreateInfo::default().code(vs_bytes.as_binary()); + let shader_stage = vk::PipelineShaderStageCreateInfo::default() + .stage(vk::ShaderStageFlags::VERTEX) + .name(c"main") + .push_next(&mut shader_module); + let dynamic_state = vk::PipelineDynamicStateCreateInfo::default() + .dynamic_states(&[vk::DynamicState::VIEWPORT, vk::DynamicState::SCISSOR]); + let rasterization_state = vk::PipelineRasterizationStateCreateInfo::default() + .line_width(1.0) + .polygon_mode(vk::PolygonMode::FILL) + .cull_mode(vk::CullModeFlags::BACK) + .front_face(vk::FrontFace::COUNTER_CLOCKWISE); + let viewport_state = vk::PipelineViewportStateCreateInfo::default() + .viewport_count(1) + .scissor_count(1); + let vertex_shader_lib = create_library( + &self.device, + vk::GraphicsPipelineLibraryFlagsEXT::PRE_RASTERIZATION_SHADERS, + |desc| { + desc.layout(self.layout) + .stages(std::slice::from_ref(&shader_stage)) + .dynamic_state(&dynamic_state) + .viewport_state(&viewport_state) + .rasterization_state(&rasterization_state) + }, + )?; + + self.vertex_shader_lib = vertex_shader_lib; + + Ok(()) + } + + pub fn reload_fragment_lib( + &mut self, + shader_compiler: &ShaderCompiler, + shader_path: impl AsRef, + ) -> Result<()> { + let fs_bytes = shader_compiler.compile(shader_path, shaderc::ShaderKind::Fragment)?; + + unsafe { self.device.destroy_pipeline(self.fragment_shader_lib, None) }; + + let mut shader_module = vk::ShaderModuleCreateInfo::default().code(fs_bytes.as_binary()); + let shader_stage = vk::PipelineShaderStageCreateInfo::default() + .stage(vk::ShaderStageFlags::FRAGMENT) + .name(c"main") + .push_next(&mut shader_module); + + let depth_stencil_state = vk::PipelineDepthStencilStateCreateInfo::default(); + + let fragment_shader_lib = create_library( + &self.device, + vk::GraphicsPipelineLibraryFlagsEXT::FRAGMENT_SHADER, + |desc| { + desc.layout(self.layout) + .stages(std::slice::from_ref(&shader_stage)) + .depth_stencil_state(&depth_stencil_state) + }, + )?; + + self.fragment_shader_lib = fragment_shader_lib; + + Ok(()) + } + + pub fn link(&mut self) -> Result<()> { + unsafe { self.device.destroy_pipeline(self.pipeline, None) }; + self.pipeline = Self::link_libraries( + &self.device, + &self.layout, + &self.vertex_input_lib, + &self.vertex_shader_lib, + &self.fragment_shader_lib, + &self.fragment_output_lib, + )?; + + Ok(()) + } + + fn link_libraries( + device: &ash::Device, + layout: &vk::PipelineLayout, + vertex_input_lib: &vk::Pipeline, + vertex_shader_lib: &vk::Pipeline, + fragment_shader_lib: &vk::Pipeline, + fragment_output_lib: &vk::Pipeline, + ) -> Result { + let libraries = [ + *vertex_input_lib, + *vertex_shader_lib, + *fragment_shader_lib, + *fragment_output_lib, + ]; + let pipeline = { + let mut linking_info = + vk::PipelineLibraryCreateInfoKHR::default().libraries(&libraries); + let pipeline_info = vk::GraphicsPipelineCreateInfo::default() + .flags(vk::PipelineCreateFlags::LINK_TIME_OPTIMIZATION_EXT) + .layout(*layout) + .push_next(&mut linking_info); + let pipeline = unsafe { + device.create_graphics_pipelines(vk::PipelineCache::null(), &[pipeline_info], None) + }; + pipeline.map_err(|(_, err)| err)?[0] + }; + + Ok(pipeline) + } +} + +impl Drop for RenderPipeline { + fn drop(&mut self) { + unsafe { + self.device.destroy_pipeline(self.vertex_input_lib, None); + self.device.destroy_pipeline(self.vertex_shader_lib, None); + self.device.destroy_pipeline(self.fragment_shader_lib, None); + self.device.destroy_pipeline(self.fragment_output_lib, None); + self.device.destroy_pipeline(self.pipeline, None); + self.device.destroy_pipeline_layout(self.layout, None); + } + } +} + +fn create_library<'a, F>( + device: &ash::Device, + kind: vk::GraphicsPipelineLibraryFlagsEXT, + f: F, +) -> VkResult +where + F: FnOnce(vk::GraphicsPipelineCreateInfo<'a>) -> vk::GraphicsPipelineCreateInfo<'a>, +{ + let mut library_type = vk::GraphicsPipelineLibraryCreateInfoEXT::default().flags(kind); + let pipeline = unsafe { + let pipeline_info = vk::GraphicsPipelineCreateInfo::default().flags( + vk::PipelineCreateFlags::LIBRARY_KHR + | vk::PipelineCreateFlags::RETAIN_LINK_TIME_OPTIMIZATION_INFO_EXT, + ); + + // WARN: `let` introduces implicit copy on the struct that contains pointers + let pipeline_info = f(pipeline_info).push_next(&mut library_type); + + device.create_graphics_pipelines( + vk::PipelineCache::null(), + std::slice::from_ref(&pipeline_info), + None, + ) + }; + + Ok(pipeline.map_err(|(_, err)| err)?[0]) +} + +slotmap::new_key_type! { + pub struct RenderHandle; + pub struct ComputeHandle; +} + +pub struct PipelineArena { + pub render: RenderArena, + pub compute: ComputeArena, + pub path_mapping: AHashMap>>, + pub shader_compiler: ShaderCompiler, + file_watcher: Watcher, + device: Arc, +} + +impl PipelineArena { + pub fn new(device: &Device, file_watcher: Watcher) -> Result { + Ok(Self { + render: RenderArena { + pipelines: SlotMap::with_key(), + }, + compute: ComputeArena { + pipelines: SlotMap::with_key(), + }, + shader_compiler: ShaderCompiler::new(&file_watcher)?, + file_watcher, + path_mapping: AHashMap::new(), + device: device.device.clone(), + }) + } + + pub fn create_compute_pipeline( + &mut self, + shader_path: impl AsRef, + push_constant_ranges: &[vk::PushConstantRange], + descriptor_set_layouts: &[vk::DescriptorSetLayout], + ) -> Result { + let path = shader_path.as_ref().canonicalize()?; + { + self.file_watcher.watch_file(&path)?; + let mut mapping = self.file_watcher.include_mapping.lock(); + mapping + .entry(path.clone()) + .or_default() + .insert(ShaderSource { + path: path.clone(), + kind: ShaderKind::Compute, + }); + } + let pipeline = ComputePipeline::new( + &self.device, + &self.shader_compiler, + &path, + push_constant_ranges, + descriptor_set_layouts, + )?; + let handle = self.compute.pipelines.insert(pipeline); + self.path_mapping + .entry(path) + .or_default() + .insert(Either::Right(handle)); + Ok(handle) + } + + pub fn create_render_pipeline( + &mut self, + vertex_input_desc: &VertexInputDesc, + vertex_shader_desc: &VertexShaderDesc, + fragment_shader_desc: &FragmentShaderDesc, + fragment_output_desc: &FragmentOutputDesc, + push_constant_ranges: &[vk::PushConstantRange], + descriptor_set_layouts: &[vk::DescriptorSetLayout], + ) -> Result { + let vs_path = vertex_shader_desc.shader_path.canonicalize()?; + let fs_path = fragment_shader_desc.shader_path.canonicalize()?; + for (path, kind) in [ + (vs_path.clone(), ShaderKind::Vertex), + (fs_path.clone(), ShaderKind::Fragment), + ] { + self.file_watcher.watch_file(&path)?; + let mut mapping = self.file_watcher.include_mapping.lock(); + mapping + .entry(path.clone()) + .or_default() + .insert(ShaderSource { path, kind }); + } + let pipeline = RenderPipeline::new( + &self.device, + &self.shader_compiler, + vertex_input_desc, + vertex_shader_desc, + fragment_shader_desc, + fragment_output_desc, + push_constant_ranges, + descriptor_set_layouts, + )?; + let handle = self.render.pipelines.insert(pipeline); + self.path_mapping + .entry(vs_path) + .or_default() + .insert(Either::Left(handle)); + self.path_mapping + .entry(fs_path) + .or_default() + .insert(Either::Left(handle)); + Ok(handle) + } + + pub fn get_pipeline(&self, handle: H) -> &H::Pipeline { + handle.get_pipeline(self) + } + + pub fn get_pipeline_mut(&mut self, handle: H) -> &mut H::Pipeline { + handle.get_pipeline_mut(self) + } +} + +pub struct RenderArena { + pub pipelines: SlotMap, +} + +pub struct ComputeArena { + pub pipelines: SlotMap, +} + +pub trait Handle { + type Pipeline; + fn get_pipeline(self, arena: &PipelineArena) -> &Self::Pipeline; + fn get_pipeline_mut(self, arena: &mut PipelineArena) -> &mut Self::Pipeline; +} + +impl Handle for RenderHandle { + type Pipeline = RenderPipeline; + + fn get_pipeline(self, arena: &PipelineArena) -> &Self::Pipeline { + &arena.render.pipelines[self] + } + + fn get_pipeline_mut(self, arena: &mut PipelineArena) -> &mut Self::Pipeline { + &mut arena.render.pipelines[self] + } +} + +impl Handle for ComputeHandle { + type Pipeline = ComputePipeline; + + fn get_pipeline(self, arena: &PipelineArena) -> &Self::Pipeline { + &arena.compute.pipelines[self] + } + + fn get_pipeline_mut(self, arena: &mut PipelineArena) -> &mut Self::Pipeline { + &mut arena.compute.pipelines[self] + } +} diff --git a/src/profiler_window.rs b/src/profiler_window.rs deleted file mode 100644 index 576f066..0000000 --- a/src/profiler_window.rs +++ /dev/null @@ -1,171 +0,0 @@ -use std::time::Instant; - -use egui::FontDefinitions; -use egui_wgpu_backend::{ - wgpu::{ - self, Backends, Device, Features, Instance, Limits, Queue, RequestAdapterOptions, Surface, - SurfaceConfiguration, - }, - RenderPass, ScreenDescriptor, -}; -use egui_winit_platform::{Platform, PlatformDescriptor}; -use eyre::Result; -use winit::{ - dpi::PhysicalSize, - event::Event, - event_loop::EventLoopWindowTarget, - window::{Window, WindowId}, -}; - -pub struct ProfilerWindow { - surface: Surface, - surface_config: SurfaceConfiguration, - device: Device, - queue: Queue, - platform: Platform, - render_pass: RenderPass, - window: Window, - previous_frame_time: Option, -} - -impl ProfilerWindow { - pub fn new(event_loop: &EventLoopWindowTarget) -> Result { - let instance = Instance::new(Backends::PRIMARY); - let window = Window::new(event_loop)?; - let surface = unsafe { instance.create_surface(&window) }; - let adapter = pollster::block_on(instance.request_adapter(&RequestAdapterOptions { - power_preference: egui_wgpu_backend::wgpu::PowerPreference::LowPower, - force_fallback_adapter: false, - compatible_surface: Some(&surface), - })) - .unwrap(); - - let (device, queue) = pollster::block_on(adapter.request_device( - &wgpu::DeviceDescriptor { - features: Features::default(), - limits: Limits::default(), - label: None, - }, - None, - ))?; - - let size = window.inner_size(); - let surface_format = surface.get_supported_formats(&adapter)[0].unwrap(); - let surface_config = wgpu::SurfaceConfiguration { - usage: wgpu::TextureUsages::RENDER_ATTACHMENT, - format: surface_format, - width: size.width as u32, - height: size.height as u32, - present_mode: wgpu::PresentMode::Immediate, - }; - surface.configure(&device, &surface_config); - - // We use the egui_winit_platform crate as the platform. - let platform = Platform::new(PlatformDescriptor { - physical_width: size.width as u32, - physical_height: size.height as u32, - scale_factor: window.scale_factor(), - font_definitions: FontDefinitions::default(), - style: Default::default(), - }); - - // We use the egui_wgpu_backend crate as the render backend. - let render_pass = RenderPass::new(&device, surface_format, 1); - - Ok(Self { - queue, - surface, - surface_config, - device, - platform, - render_pass, - window, - previous_frame_time: Some(0.), - }) - } - - pub fn handle_event(&mut self, event: &Event) { - self.platform.handle_event(event); - } - pub fn id(&self) -> WindowId { - self.window.id() - } - - pub fn resize(&mut self) { - let PhysicalSize { width, height } = self.window.inner_size(); - self.surface_config.width = width; - self.surface_config.height = height; - self.surface.configure(&self.device, &self.surface_config); - } - - pub fn request_redraw(&self) { - self.window.request_redraw() - } - - pub fn render(&mut self, start_time: &Instant) { - self.platform - .update_time(start_time.elapsed().as_secs_f64()); - - let output_frame = match self.surface.get_current_texture() { - Ok(frame) => frame, - Err(e) => { - eprintln!("Dropped frame with error: {}", e); - return; - } - }; - let output_view = output_frame - .texture - .create_view(&wgpu::TextureViewDescriptor::default()); - - // Begin to draw the UI frame. - let egui_start = Instant::now(); - self.platform.begin_frame(); - - let _ = puffin_egui::profiler_window(&self.platform.context()); - - // End the UI frame. We could now handle the output and draw the UI with the backend. - let (_output, paint_commands) = self.platform.end_frame(Some(&self.window)); - let paint_jobs = self.platform.context().tessellate(paint_commands); - - let frame_time = (Instant::now() - egui_start).as_secs_f64() as f32; - self.previous_frame_time = Some(frame_time); - - let mut encoder = self - .device - .create_command_encoder(&wgpu::CommandEncoderDescriptor { - label: Some("encoder"), - }); - - // Upload all resources for the GPU. - let screen_descriptor = ScreenDescriptor { - physical_width: self.surface_config.width, - physical_height: self.surface_config.height, - scale_factor: self.window.scale_factor() as f32, - }; - self.render_pass.update_texture( - &self.device, - &self.queue, - &self.platform.context().font_image(), - ); - self.render_pass - .update_user_textures(&self.device, &self.queue); - self.render_pass - .update_buffers(&self.device, &self.queue, &paint_jobs, &screen_descriptor); - - // Record all render passes. - self.render_pass - .execute( - &mut encoder, - &output_view, - &paint_jobs, - &screen_descriptor, - Some(wgpu::Color::BLACK), - ) - .unwrap(); - // Submit the commands. - self.queue.submit(std::iter::once(encoder.finish())); - - // Redraw egui - output_frame.present(); - } -} diff --git a/src/recorder.rs b/src/recorder.rs index a846d9a..1c97518 100644 --- a/src/recorder.rs +++ b/src/recorder.rs @@ -1,84 +1,107 @@ -use color_eyre::*; -use crossbeam_channel::{Receiver, Sender}; +use anyhow::{Context, Result}; use std::{ - error::Error, - fmt::{self, Display, Formatter}, - io::{self, BufWriter, Write}, + fs::File, + io::{BufWriter, Write}, path::Path, process::{Child, Command, Stdio}, - time::{Duration, Instant}, + thread::JoinHandle, + time::Instant, }; -#[cfg(windows)] -use std::os::windows::process::CommandExt; - -use pilka_types::ImageDimentions; - -use super::utils::create_folder; -use crate::VIDEO_FOLDER; +use crate::{create_folder, ImageDimensions, ManagedImage, SCREENSHOT_FOLDER, VIDEO_FOLDER}; +use crossbeam_channel::{Receiver, Sender}; pub enum RecordEvent { - Start(ImageDimentions), - Record(Vec), + Start(ImageDimensions), + Record(ManagedImage), Finish, + Screenshot(ManagedImage), + CloseThread, } -#[derive(Debug)] -pub enum ProcessError { - SpawnError(io::Error), - Other(io::Error), +pub struct Recorder { + pub sender: Sender, + ffmpeg_installed: bool, + pub ffmpeg_version: String, + pub thread_handle: Option>, + is_active: bool, } -impl Display for ProcessError { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - ProcessError::SpawnError(e) => { - write!(f, "Could not start ffmpeg. Make sure you have\nffmpeg installed and present in PATH\n\t{e}") - } - ProcessError::Other(e) => { - write!(f, "{}", e) - } +impl Recorder { + pub fn new() -> Self { + let mut command = Command::new("ffmpeg"); + command.arg("-version"); + let (version, installed) = match command.output() { + Ok(output) => ( + String::from_utf8(output.stdout) + .unwrap() + .lines() + .next() + .unwrap() + .to_string(), + true, + ), + Err(e) => (e.to_string(), false), + }; + + let (tx, rx) = crossbeam_channel::unbounded(); + let thread_handle = std::thread::spawn(move || record_thread(rx)); + + Self { + sender: tx, + ffmpeg_installed: installed, + ffmpeg_version: version, + thread_handle: Some(thread_handle), + is_active: false, } } -} -impl std::error::Error for ProcessError { - fn source(&self) -> Option<&(dyn Error + 'static)> { - match self { - ProcessError::Other(e) => Some(e), - ProcessError::SpawnError(e) => Some(e), - } + pub fn is_active(&self) -> bool { + self.is_active } -} -pub fn ffmpeg_version() -> Result<(String, bool), ProcessError> { - let mut command = Command::new("ffmpeg"); - command.arg("-version"); - - let res = match command.output().map_err(ProcessError::Other) { - Ok(output) => ( - String::from_utf8(output.stdout) - .unwrap() - .lines() - .next() - .unwrap() - .to_string(), - true, - ), - Err(e) => (e.to_string(), false), - }; - Ok(res) + pub fn ffmpeg_installed(&self) -> bool { + self.ffmpeg_installed + } + + pub fn screenshot(&self, image: ManagedImage) { + let _ = self + .sender + .send(RecordEvent::Screenshot(image)) + .context("Failed to send screenshot"); + } + + pub fn start(&mut self, dims: ImageDimensions) { + self.is_active = true; + self.send(RecordEvent::Start(dims)); + } + + pub fn record(&self, image: ManagedImage) { + self.send(RecordEvent::Record(image)); + } + + pub fn finish(&mut self) { + self.is_active = false; + self.send(RecordEvent::Finish); + } + + pub fn close_thread(&self) { + self.sender.send(RecordEvent::CloseThread).unwrap(); + } + + pub fn send(&self, event: RecordEvent) { + if !(self.ffmpeg_installed || matches!(event, RecordEvent::Screenshot(_))) { + return; + } + self.sender.send(event).unwrap() + } } -pub struct Recorder { +struct RecorderThread { process: Child, - image_dimentions: ImageDimentions, } -pub fn new_ffmpeg_command( - image_dimentions: ImageDimentions, - filename: &str, -) -> Result { +fn new_ffmpeg_command(image_dimensions: ImageDimensions, filename: &str) -> Result { #[rustfmt::skip] let args = [ "-framerate", "60", @@ -86,7 +109,7 @@ pub fn new_ffmpeg_command( "-f", "rawvideo", "-i", "pipe:", "-c:v", "libx264", - "-crf", "15", + "-crf", "25", "-preset", "ultrafast", "-tune", "animation", "-color_primaries", "bt709", @@ -104,8 +127,8 @@ pub fn new_ffmpeg_command( .arg("-video_size") .arg(format!( "{}x{}", - image_dimentions.unpadded_bytes_per_row / 4, - image_dimentions.height + image_dimensions.unpadded_bytes_per_row / 4, + image_dimensions.height )) .args(args) .arg(filename) @@ -120,117 +143,104 @@ pub fn new_ffmpeg_command( command.creation_flags(WINAPI_UM_WINBASE_CREATE_NO_WINDOW); } - let child = command.spawn().map_err(ProcessError::SpawnError)?; + let child = command.spawn()?; - Ok(Recorder { - process: child, - image_dimentions, - }) + Ok(RecorderThread { process: child }) } -pub fn record_thread(rx: crossbeam_channel::Receiver) { - puffin::profile_function!(); - +fn record_thread(rx: Receiver) { let mut recorder = None; while let Ok(event) = rx.recv() { match event { - RecordEvent::Start(image_dimentions) => { - puffin::profile_scope!("Start Recording"); - + RecordEvent::Start(image_dimensions) => { create_folder(VIDEO_FOLDER).unwrap(); let dir_path = Path::new(VIDEO_FOLDER); let filename = dir_path.join(format!( "record-{}.mp4", - chrono::Local::now().format("%d-%m-%Y-%H-%M-%S") + chrono::Local::now().format("%Y-%m-%d_%H-%M-%S") )); recorder = - Some(new_ffmpeg_command(image_dimentions, filename.to_str().unwrap()).unwrap()); + Some(new_ffmpeg_command(image_dimensions, filename.to_str().unwrap()).unwrap()); } - RecordEvent::Record(frame) => { - puffin::profile_scope!("Process Frame"); - + RecordEvent::Record(mut frame) => { if let Some(ref mut recorder) = recorder { let writer = recorder.process.stdin.as_mut().unwrap(); let mut writer = BufWriter::new(writer); - let padded_bytes = recorder.image_dimentions.padded_bytes_per_row as _; - let unpadded_bytes = recorder.image_dimentions.unpadded_bytes_per_row as _; - for chunk in frame + let padded_bytes = frame.image_dimensions.padded_bytes_per_row as _; + let unpadded_bytes = frame.image_dimensions.unpadded_bytes_per_row as _; + let data = match frame.map_memory() { + Ok(data) => data, + Err(err) => { + eprintln!("Failed to map memory: {err}"); + continue; + } + }; + + for chunk in data .chunks(padded_bytes) .map(|chunk| &chunk[..unpadded_bytes]) { - writer.write_all(chunk).unwrap(); + let _ = writer.write_all(chunk); } - // writer.write_all(&frame).unwrap(); - writer.flush().unwrap(); + let _ = writer.flush(); } } RecordEvent::Finish => { - puffin::profile_scope!("Stop Recording"); - - if let Some(ref mut process) = recorder { - process.process.wait().unwrap(); + if let Some(ref mut p) = recorder { + p.process.wait().unwrap(); } - drop(recorder); recorder = None; + eprintln!("Recording finished"); } - } - } -} - -/// ---------------RecordTimer------------------ -/// |<- until ->| -/// |<- start_rx ->|<- counter ->| -/// |<- tx ->| -pub struct RecordTimer { - until: Option, - pub counter: Option, - start_rx: Option>, - tx: Sender, -} - -impl RecordTimer { - const NUM_SKIPPED_FRAMES: usize = 3; - pub fn new(until: Option, tx: Sender) -> (Self, Sender<()>) { - let (start_tx, start_rx) = crossbeam_channel::bounded(Self::NUM_SKIPPED_FRAMES); - let counter = None; - ( - Self { - until, - counter, - start_rx: Some(start_rx), - tx, - }, - start_tx, - ) - } + RecordEvent::Screenshot(mut frame) => { + let image_dimensions = frame.image_dimensions; + let data = match frame.map_memory() { + Ok(data) => data, + Err(err) => { + eprintln!("Failed to map memory: {err}"); + continue; + } + }; - pub fn update( - &mut self, - video_recording: &mut bool, - image_dimentions: ImageDimentions, - ) -> Result<()> { - if let Some(until) = self.until { - if let Some(ref start_rx) = self.start_rx { - if start_rx.is_full() { - self.counter = Some(Instant::now()); - self.tx.send(RecordEvent::Start(image_dimentions))?; - *video_recording = true; - - self.start_rx = None; - } + let _ = save_screenshot(data, image_dimensions).map_err(|err| eprintln!("{err}")); } - - if let Some(now) = self.counter { - if until < now.elapsed() { - *video_recording = false; - self.tx.send(RecordEvent::Finish).unwrap(); - std::thread::sleep(Duration::from_millis(100)); - std::process::exit(0); - } + RecordEvent::CloseThread => { + return; } } - Ok(()) } } + +pub fn save_screenshot(frame: &[u8], image_dimensions: ImageDimensions) -> Result<()> { + let now = Instant::now(); + let screenshots_folder = Path::new(SCREENSHOT_FOLDER); + create_folder(screenshots_folder)?; + let path = screenshots_folder.join(format!( + "screenshot-{}.png", + chrono::Local::now().format("%Y-%m-%d_%H-%M-%S%.9f") + )); + let file = File::create(path)?; + let w = BufWriter::new(file); + let mut encoder = + png::Encoder::new(w, image_dimensions.width as _, image_dimensions.height as _); + encoder.set_color(png::ColorType::Rgba); + encoder.set_depth(png::BitDepth::Eight); + let padded_bytes = image_dimensions.padded_bytes_per_row; + let unpadded_bytes = image_dimensions.unpadded_bytes_per_row; + let mut writer = encoder + .write_header()? + .into_stream_writer_with_size(unpadded_bytes)?; + writer.set_filter(png::FilterType::Paeth); + writer.set_adaptive_filter(png::AdaptiveFilterType::Adaptive); + for chunk in frame + .chunks(padded_bytes) + .map(|chunk| &chunk[..unpadded_bytes]) + { + writer.write_all(chunk)?; + } + writer.finish()?; + eprintln!("Encode image: {:#.2?}", now.elapsed()); + Ok(()) +} diff --git a/src/render_bundle.rs b/src/render_bundle.rs deleted file mode 100644 index 63b1d71..0000000 --- a/src/render_bundle.rs +++ /dev/null @@ -1,348 +0,0 @@ -use std::path::PathBuf; - -use crate::shader_compiler::ShaderCompiler; -use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle}; - -use color_eyre::Result; -use pilka_ash::AshRender; -use pilka_types::{ - ContiniousHashMap, Frame, ImageDimentions, PipelineInfo, PushConstant, ShaderCreateInfo, -}; -use pilka_wgpu::WgpuRender; - -pub trait Renderer { - fn get_info(&self) -> String; - - fn pause(&mut self); - - fn resize(&mut self, width: u32, height: u32) -> Result<()>; - - fn render(&mut self, push_constant: PushConstant) -> Result<()>; - - fn capture_frame(&mut self) -> Result; - fn captured_frame_dimentions(&self) -> ImageDimentions; - - fn wait_idle(&self) {} - fn shut_down(&self) {} -} - -#[allow(clippy::large_enum_variant)] -pub enum Backend<'a> { - Ash(AshRender<'a>), - Wgpu(WgpuRender), -} - -pub struct RenderBundleStatic<'a> { - kind: Option>, - shader_set: ContiniousHashMap, - pipelines: Vec, - includes: Vec>, - push_constant_range: u32, - wh: (u32, u32), -} - -impl<'a> RenderBundleStatic<'a> { - pub fn new( - window: &W, - push_constant_range: u32, - (width, height): (u32, u32), - ) -> Result> { - let kind = match std::env::var("PILKA_BACKEND") - .unwrap_or_else(|_| "wgpu".into()) - .to_lowercase() - .as_str() - { - "wgpu" => Backend::Wgpu(WgpuRender::new(window, push_constant_range, width, height)?), - "ash" => Backend::Ash(AshRender::new(window, push_constant_range).unwrap()), - _ => Backend::Wgpu(WgpuRender::new(window, push_constant_range, width, height)?), - }; - Ok(Self { - kind: Some(kind), - shader_set: ContiniousHashMap::new(), - pipelines: vec![], - includes: vec![], - push_constant_range, - wh: (width, height), - }) - } - - pub fn push_pipeline( - &mut self, - pipeline: PipelineInfo, - includes: &[PathBuf], - shader_compiler: &mut ShaderCompiler, - ) -> Result<()> { - puffin::profile_function!(); - let pipeline_number = self.pipelines.len(); - match pipeline { - PipelineInfo::Rendering { ref vert, ref frag } => { - self.shader_set - .push_value(frag.path.canonicalize()?, pipeline_number); - self.shader_set - .push_value(vert.path.canonicalize()?, pipeline_number); - - let vert_artifact = - shader_compiler.create_shader_module(vert, shaderc::ShaderKind::Vertex)?; - let vert = ShaderCreateInfo::new(&vert_artifact, &vert.entry_point); - - let frag_arifact = - shader_compiler.create_shader_module(frag, shaderc::ShaderKind::Fragment)?; - let frag = ShaderCreateInfo::new(&frag_arifact, &frag.entry_point); - - match self.kind.as_mut().unwrap() { - Backend::Ash(ash) => ash.push_render_pipeline(vert, frag)?, - Backend::Wgpu(wgpu) => wgpu.push_render_pipeline(vert, frag)?, - } - } - PipelineInfo::Compute { ref comp } => { - self.shader_set - .push_value(comp.path.canonicalize()?, pipeline_number); - - let comp_artifact = - shader_compiler.create_shader_module(comp, shaderc::ShaderKind::Compute)?; - let comp = ShaderCreateInfo::new(&comp_artifact, &comp.entry_point); - - match self.kind.as_mut().unwrap() { - Backend::Ash(ash) => ash.push_compute_pipeline(comp)?, - Backend::Wgpu(wgpu) => wgpu.push_compute_pipeline(comp)?, - } - } - } - for include in includes { - self.shader_set - .push_value(include.canonicalize()?, pipeline_number); - } - self.pipelines.push(pipeline); - self.includes.push(includes.to_vec()); - - Ok(()) - } - - pub fn register_shader_change( - &mut self, - paths: &[PathBuf], - shader_compiler: &mut ShaderCompiler, - ) -> Result<()> { - puffin::profile_function!(); - self.wait_idle(); - for path in paths { - if let Some(pipeline_indices) = self.shader_set.get(path) { - for &index in pipeline_indices { - match &self.pipelines[index] { - PipelineInfo::Rendering { vert, frag } => { - let vert_artifact = shader_compiler - .create_shader_module(vert, shaderc::ShaderKind::Vertex)?; - let vert = ShaderCreateInfo::new(&vert_artifact, &vert.entry_point); - - let frag_arifact = shader_compiler - .create_shader_module(frag, shaderc::ShaderKind::Fragment)?; - let frag = ShaderCreateInfo::new(&frag_arifact, &frag.entry_point); - - match self.kind.as_mut().unwrap() { - Backend::Ash(ash) => { - ash.rebuild_render_pipeline(index, vert, frag)? - } - Backend::Wgpu(wgpu) => { - wgpu.rebuild_render_pipeline(index, vert, frag)? - } - } - } - - PipelineInfo::Compute { comp } => { - let comp_artifact = shader_compiler - .create_shader_module(comp, shaderc::ShaderKind::Compute)?; - let comp = ShaderCreateInfo::new(&comp_artifact, &comp.entry_point); - - match self.kind.as_mut().unwrap() { - Backend::Ash(ash) => ash.rebuild_compute_pipeline(index, comp)?, - Backend::Wgpu(wgpu) => { - wgpu.rebuild_compute_pipeline(index, comp)? - } - } - } - } - } - } - } - Ok(()) - } - - fn get_active(&self) -> &dyn Renderer { - match self.kind.as_ref().unwrap() { - Backend::Ash(ash) => ash, - Backend::Wgpu(wgpu) => wgpu, - } - } - fn get_active_mut(&mut self) -> &mut dyn Renderer { - match self.kind.as_mut().unwrap() { - Backend::Ash(ash) => ash, - Backend::Wgpu(wgpu) => wgpu, - } - } - pub fn shader_list(&self) -> Vec { - self.shader_set.keys().cloned().collect() - } - pub fn switch( - &mut self, - window: &W, - shader_compiler: &mut ShaderCompiler, - ) -> Result<()> { - puffin::profile_function!(); - self.wait_idle(); - #[derive(Debug)] - enum Kind { - Ash, - Wgpu, - } - let kind = match &self.kind { - Some(Backend::Ash(_)) => Kind::Ash, - Some(Backend::Wgpu(_)) => Kind::Wgpu, - _ => unreachable!(), - }; - let old = self.kind.take(); - drop(old); - - self.kind = match kind { - Kind::Ash => Some(Backend::Wgpu( - WgpuRender::new(window, self.push_constant_range, self.wh.0, self.wh.1).unwrap(), - )), - Kind::Wgpu => Some(Backend::Ash( - AshRender::new(window, self.push_constant_range).unwrap(), - )), - }; - - for pipeline in &self.pipelines { - match pipeline { - PipelineInfo::Rendering { vert, frag } => { - let vert_artifact = - shader_compiler.create_shader_module(vert, shaderc::ShaderKind::Vertex)?; - let vert = ShaderCreateInfo::new(&vert_artifact, &vert.entry_point); - - let frag_arifact = shader_compiler - .create_shader_module(frag, shaderc::ShaderKind::Fragment)?; - let frag = ShaderCreateInfo::new(&frag_arifact, &frag.entry_point); - - match self.kind.as_mut().unwrap() { - Backend::Ash(ash) => ash.push_render_pipeline(vert, frag)?, - Backend::Wgpu(wgpu) => wgpu.push_render_pipeline(vert, frag)?, - } - } - PipelineInfo::Compute { comp } => { - let comp_artifact = - shader_compiler.create_shader_module(comp, shaderc::ShaderKind::Compute)?; - let comp = ShaderCreateInfo::new(&comp_artifact, &comp.entry_point); - match self.kind.as_mut().unwrap() { - Backend::Ash(ash) => ash.push_compute_pipeline(comp)?, - Backend::Wgpu(wgpu) => wgpu.push_compute_pipeline(comp)?, - } - } - } - } - - println!( - "Switched to: {}", - match kind { - Kind::Ash => "Wgpu", - Kind::Wgpu => "Ash", - } - ); - - Ok(()) - } -} - -impl Renderer for RenderBundleStatic<'_> { - fn get_info(&self) -> String { - self.get_active().get_info() - } - - fn pause(&mut self) { - self.get_active_mut().pause() - } - fn resize(&mut self, width: u32, height: u32) -> Result<()> { - self.wh = (width, height); - self.get_active_mut().resize(width, height) - } - fn render(&mut self, push_constant: PushConstant) -> Result<()> { - puffin::profile_function!(); - self.get_active_mut().render(push_constant) - } - fn capture_frame(&mut self) -> Result { - puffin::profile_function!(); - self.get_active_mut().capture_frame() - } - fn captured_frame_dimentions(&self) -> ImageDimentions { - self.get_active().captured_frame_dimentions() - } - - fn wait_idle(&self) { - puffin::profile_function!(); - self.get_active().wait_idle() - } - fn shut_down(&self) { - self.get_active().shut_down() - } -} - -impl Renderer for AshRender<'_> { - fn get_info(&self) -> String { - self.get_info().to_string() - } - - fn pause(&mut self) { - self.paused = !self.paused; - } - - fn resize(&mut self, _width: u32, _height: u32) -> Result<()> { - Ok(self.resize()?) - } - - fn render(&mut self, push_constant: PushConstant) -> Result<()> { - Ok(self.render(push_constant)?) - } - - fn capture_frame(&mut self) -> Result { - Ok(self.capture_frame()?) - } - fn captured_frame_dimentions(&self) -> ImageDimentions { - self.screenshot_dimentions() - } - - fn wait_idle(&self) { - unsafe { self.device.device_wait_idle().unwrap() } - } - fn shut_down(&self) { - unsafe { self.device.device_wait_idle().unwrap() } - } -} - -impl Renderer for pilka_wgpu::WgpuRender { - fn get_info(&self) -> String { - self.get_info().to_string() - } - - fn pause(&mut self) { - self.paused = !self.paused; - } - - fn resize(&mut self, width: u32, height: u32) -> Result<()> { - self.resize(width, height); - Ok(()) - } - - fn render(&mut self, push_constant: PushConstant) -> Result<()> { - Ok(Self::render(self, push_constant)?) - } - - fn capture_frame(&mut self) -> Result { - Ok(self.capture_frame()?) - } - - fn captured_frame_dimentions(&self) -> ImageDimentions { - self.screenshot_dimentions() - } - - fn wait_idle(&self) { - self.wait_idle() - } -} diff --git a/src/shader_compiler.rs b/src/shader_compiler.rs index 41270e6..cd11ee2 100644 --- a/src/shader_compiler.rs +++ b/src/shader_compiler.rs @@ -1,50 +1,82 @@ -mod glsl; -mod wgsl; +use std::path::Path; -use color_eyre::Result; -pub use glsl::create_shader_module; -use pilka_types::{ShaderFlavor, ShaderInfo}; +use crate::{Watcher, SHADER_FOLDER}; +use anyhow::{Context, Result}; +use shaderc::{CompilationArtifact, IncludeType, ShaderKind}; pub struct ShaderCompiler { - wgsl: wgsl::ShaderCompiler, - glsl: shaderc::Compiler, + compiler: shaderc::Compiler, + options: shaderc::CompileOptions<'static>, } impl ShaderCompiler { - pub fn new() -> Self { - Self::default() - } + pub fn new(watcher: &Watcher) -> Result { + let mut options = + shaderc::CompileOptions::new().context("Failed to create shader compiler options")?; + options.set_target_env( + shaderc::TargetEnv::Vulkan, + shaderc::EnvVersion::Vulkan1_3 as u32, + ); + options.set_optimization_level(shaderc::OptimizationLevel::Performance); + options.set_target_spirv(shaderc::SpirvVersion::V1_6); + options.set_generate_debug_info(); - pub fn create_shader_module( - &mut self, - shader_info: &ShaderInfo, - shader_stage: shaderc::ShaderKind, - ) -> Result> { - let module = match shader_info.flavour { - ShaderFlavor::Wgsl => { - let stage = match shader_stage { - shaderc::ShaderKind::Compute => naga::ShaderStage::Compute, - shaderc::ShaderKind::Vertex => naga::ShaderStage::Vertex, - shaderc::ShaderKind::Fragment => naga::ShaderStage::Fragment, - _ => panic!("Unknown shader stage"), - }; - self.wgsl.create_shader_module(shader_info, stage)? - } - ShaderFlavor::Glsl => { - glsl::create_shader_module(shader_info, shader_stage, &mut self.glsl)? - .as_binary() - .to_vec() + let watcher_copy = watcher.clone(); + options.set_include_callback(move |name, include_type, source_file, _depth| { + let path = match include_type { + IncludeType::Relative => Path::new(source_file).parent().unwrap().join(name), + IncludeType::Standard => Path::new(SHADER_FOLDER).join(name), + }; + // TODO: recreate dependencies in case someone removes includes + match std::fs::read_to_string(&path) { + Ok(glsl_code) => { + let include_path = path.canonicalize().unwrap(); + { + let mut watcher = watcher_copy.watcher.lock(); + let _ = watcher + .watcher() + .watch(&include_path, notify::RecursiveMode::NonRecursive); + } + let source_path = Path::new(SHADER_FOLDER) + .join(source_file) + .canonicalize() + .unwrap(); + { + let mut mapping = watcher_copy.include_mapping.lock(); + let sources: Vec<_> = mapping[&source_path].iter().cloned().collect(); + for source in sources { + mapping + .entry(include_path.clone()) + .or_default() + .insert(source); + } + } + Ok(shaderc::ResolvedInclude { + resolved_name: String::from(name), + content: glsl_code, + }) + } + Err(err) => Err(format!( + "Failed to resolve include to {} in {} (was looking for {:?}): {}", + name, source_file, path, err + )), } - }; - Ok(module) + }); + + Ok(Self { + compiler: shaderc::Compiler::new().unwrap(), + options, + }) } -} -impl Default for ShaderCompiler { - fn default() -> Self { - Self { - wgsl: wgsl::ShaderCompiler::new(), - glsl: shaderc::Compiler::new().unwrap(), - } + pub fn compile(&self, path: impl AsRef, kind: ShaderKind) -> Result { + let source = std::fs::read_to_string(path.as_ref())?; + Ok(self.compiler.compile_into_spirv( + &source, + kind, + path.as_ref().file_name().and_then(|s| s.to_str()).unwrap(), + "main", + Some(&self.options), + )?) } } diff --git a/src/shader_compiler/glsl.rs b/src/shader_compiler/glsl.rs deleted file mode 100644 index ef09028..0000000 --- a/src/shader_compiler/glsl.rs +++ /dev/null @@ -1,78 +0,0 @@ -use std::path::Path; - -use crate::{ShaderInfo, SHADER_PATH}; - -pub fn create_shader_module( - shader_info: &ShaderInfo, - shader_type: shaderc::ShaderKind, - compiler: &mut shaderc::Compiler, -) -> shaderc::Result { - let shader_text = std::fs::read_to_string(&shader_info.path).unwrap(); - let mut compile_options = - shaderc::CompileOptions::new().expect("Failed to create shader compiler options"); - // compile_options.set_warnings_as_errors(); - compile_options.set_target_env( - shaderc::TargetEnv::Vulkan, - shaderc::EnvVersion::Vulkan1_2 as u32, - ); - - compile_options.set_optimization_level(shaderc::OptimizationLevel::Performance); - compile_options.set_generate_debug_info(); - - match shader_type { - shaderc::ShaderKind::Fragment => { - compile_options.add_macro_definition("FRAGMENT_SHADER", Some("1")) - } - shaderc::ShaderKind::Vertex => { - compile_options.add_macro_definition("VERTEX_SHADER", Some("1")) - } - shaderc::ShaderKind::Compute => { - compile_options.add_macro_definition("COMPUTE_SHADER", Some("1")) - } - _ => panic!("We doesn't support {:?} shaders yet", shader_type), - } - - if cfg!(debug_assertions) { - compile_options.add_macro_definition("DEBUG", Some("1")); - } else { - compile_options.add_macro_definition("NDEBUG", Some("1")); - } - - compile_options.set_include_callback(|name, include_type, source_file, _depth| { - let path = if include_type == shaderc::IncludeType::Relative { - Path::new(Path::new(source_file).parent().unwrap()).join(name) - } else { - Path::new(SHADER_PATH).join(name) - }; - match std::fs::read_to_string(&path) { - Ok(glsl_code) => Ok(shaderc::ResolvedInclude { - resolved_name: String::from(name), - content: glsl_code, - }), - Err(err) => Err(format!( - "Failed to resolve include to {} in {} (was looking for {:?}): {}", - name, source_file, path, err - )), - } - }); - - match compiler.compile_into_spirv( - &shader_text, - shader_type, - shader_info.path.to_str().unwrap(), - "main", - Some(&compile_options), - ) { - Ok(compilation_artifact) => { - if compilation_artifact.get_num_warnings() > 0 { - eprintln!( - "[WARNING] In shader {}:\n{}", - shader_info.path.display(), - compilation_artifact.get_warning_messages() - ); - } - Ok(compilation_artifact) - } - Err(e) => Err(e), - } -} diff --git a/src/shader_compiler/wgsl.rs b/src/shader_compiler/wgsl.rs deleted file mode 100644 index e68e54d..0000000 --- a/src/shader_compiler/wgsl.rs +++ /dev/null @@ -1,111 +0,0 @@ -use std::collections::BTreeMap; - -use color_eyre::Result; -use naga::{ - back::spv, - front::wgsl, - valid::{Capabilities, ValidationFlags, Validator}, -}; -use pilka_types::ShaderInfo; - -pub struct ShaderCompiler { - validator: Validator, - options: spv::Options, -} - -impl ShaderCompiler { - pub fn new() -> Self { - Self::default() - } - - pub fn create_shader_module( - &mut self, - shader_info: &ShaderInfo, - _shader_stage: naga::ShaderStage, - ) -> Result> { - let source = std::fs::read_to_string(&shader_info.path)?; - let module = match wgsl::parse_str(&source) { - Ok(m) => m, - Err(e) => { - e.emit_to_stderr(&source); - return Err(e.into()); - } - }; - let module_info = self.validator.validate(&module)?; - Ok(spv::write_vec( - &module, - &module_info, - &self.options, - None, - // Some(&options), - )?) - } -} - -impl Default for ShaderCompiler { - fn default() -> Self { - let validator = Validator::new(ValidationFlags::all(), Capabilities::all()); - let options = get_options(); - Self { validator, options } - } -} - -fn get_options() -> spv::Options { - let mut capabilities = vec![ - spv::Capability::Shader, - spv::Capability::Matrix, - spv::Capability::Sampled1D, - spv::Capability::Image1D, - spv::Capability::ImageQuery, - spv::Capability::DerivativeControl, - spv::Capability::SampledCubeArray, - spv::Capability::SampleRateShading, - //Note: this is requested always, no matter what the actual - // adapter supports. It's not the responsibility of SPV-out - // translation to handle the storage support for formats. - spv::Capability::StorageImageExtendedFormats, - //TODO: fill out the rest - ]; - - capabilities.push(spv::Capability::MultiView); - - let mut flags = spv::WriterFlags::empty(); - flags.set( - spv::WriterFlags::DEBUG, - true, - // self.instance.flags.contains(crate::InstanceFlags::DEBUG), - ); - flags.set( - spv::WriterFlags::LABEL_VARYINGS, - true, // self.phd_capabilities.properties.vendor_id != crate::auxil::db::qualcomm::VENDOR, - ); - flags.set( - spv::WriterFlags::FORCE_POINT_SIZE, - //Note: we could technically disable this when we are compiling separate entry points, - // and we know exactly that the primitive topology is not `PointList`. - // But this requires cloning the `spv::Options` struct, which has heap allocations. - true, // could check `super::Workarounds::SEPARATE_ENTRY_POINTS` - ); - spv::Options { - lang_version: (1, 0), - flags, - capabilities: Some(capabilities.iter().cloned().collect()), - bounds_check_policies: naga::proc::BoundsCheckPolicies { - index: naga::proc::BoundsCheckPolicy::Unchecked, - buffer: - // if self.private_caps.robust_buffer_access { - naga::proc::BoundsCheckPolicy::Unchecked, - // } else { - // naga::proc::BoundsCheckPolicy::Restrict, - // }, - image: - // if self.private_caps.robust_image_access { - naga::proc::BoundsCheckPolicy::Unchecked, - // } else { - // naga::proc::BoundsCheckPolicy::Restrict - // }, - binding_array: naga::proc::BoundsCheckPolicy::Unchecked, - }, - binding_map: BTreeMap::default(), - } -} diff --git a/src/surface.rs b/src/surface.rs new file mode 100644 index 0000000..2ef5a84 --- /dev/null +++ b/src/surface.rs @@ -0,0 +1,105 @@ +use std::ops::Deref; + +use anyhow::Result; +use ash::{khr, vk}; +use raw_window_handle::{HasDisplayHandle, HasWindowHandle}; + +use crate::device::Device; + +pub struct Surface { + loader: khr::surface::Instance, + inner: vk::SurfaceKHR, +} + +impl Deref for Surface { + type Target = vk::SurfaceKHR; + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +#[derive(Debug, Clone)] +pub struct SurfaceInfo { + pub capabilities: vk::SurfaceCapabilitiesKHR, + pub formats: Vec, + pub present_modes: Vec, +} + +impl Surface { + pub fn new( + entry: &ash::Entry, + instance: &ash::Instance, + handle: &(impl HasDisplayHandle + HasWindowHandle), + ) -> Result { + let inner = unsafe { + ash_window::create_surface( + entry, + instance, + handle.display_handle()?.as_raw(), + handle.window_handle()?.as_raw(), + None, + )? + }; + + let loader = khr::surface::Instance::new(entry, instance); + + Ok(Surface { inner, loader }) + } + + pub fn get_device_capabilities(&self, device: &Device) -> vk::SurfaceCapabilitiesKHR { + unsafe { + self.loader + .get_physical_device_surface_capabilities(device.physical_device, self.inner) + .unwrap() + } + } + + pub fn get_device_surface_support( + &self, + physical_device: vk::PhysicalDevice, + queue_family_index: u32, + ) -> bool { + unsafe { + self.loader + .get_physical_device_surface_support( + physical_device, + queue_family_index, + self.inner, + ) + .unwrap() + } + } + + pub fn info(&self, device: &Device) -> SurfaceInfo { + let physical_device = device.physical_device; + let formats = unsafe { + self.loader + .get_physical_device_surface_formats(physical_device, self.inner) + .unwrap() + }; + + let capabilities = unsafe { + self.loader + .get_physical_device_surface_capabilities(physical_device, self.inner) + .unwrap() + }; + + let present_modes = unsafe { + self.loader + .get_physical_device_surface_present_modes(physical_device, self.inner) + .unwrap() + }; + + SurfaceInfo { + capabilities, + formats, + present_modes, + } + } +} + +impl Drop for Surface { + fn drop(&mut self) { + unsafe { self.loader.destroy_surface(self.inner, None) }; + } +} diff --git a/src/swapchain.rs b/src/swapchain.rs new file mode 100644 index 0000000..1b77624 --- /dev/null +++ b/src/swapchain.rs @@ -0,0 +1,549 @@ +use std::{collections::VecDeque, slice, sync::Arc}; + +use ash::{ + khr, + prelude::VkResult, + vk::{self, CompositeAlphaFlagsKHR}, +}; + +use crate::{ + device::{Device, DeviceExt}, + surface::Surface, + ImageDimensions, RawDevice, +}; + +pub struct Frame { + command_buffer: vk::CommandBuffer, + image_available_semaphore: vk::Semaphore, + render_finished_semaphore: vk::Semaphore, + pub present_finished: vk::Fence, + device: Arc, +} + +impl Frame { + fn destroy(&mut self, pool: &vk::CommandPool) { + unsafe { + self.device.destroy_fence(self.present_finished, None); + self.device + .destroy_semaphore(self.image_available_semaphore, None); + self.device + .destroy_semaphore(self.render_finished_semaphore, None); + self.device + .free_command_buffers(*pool, &[self.command_buffer]); + } + } +} + +impl Frame { + fn new(device: &Arc, command_pool: &vk::CommandPool) -> VkResult { + let present_finished = unsafe { + device.create_fence( + &vk::FenceCreateInfo::default().flags(vk::FenceCreateFlags::default()), + None, + ) + }?; + let image_available_semaphore = + unsafe { device.create_semaphore(&vk::SemaphoreCreateInfo::default(), None)? }; + let render_finished_semaphore = + unsafe { device.create_semaphore(&vk::SemaphoreCreateInfo::default(), None)? }; + let alloc_info = vk::CommandBufferAllocateInfo::default() + .command_pool(*command_pool) + .level(vk::CommandBufferLevel::PRIMARY) + .command_buffer_count(1); + let command_buffer = unsafe { device.allocate_command_buffers(&alloc_info) }?[0]; + Ok(Self { + command_buffer, + image_available_semaphore, + render_finished_semaphore, + present_finished, + device: device.clone(), + }) + } +} + +pub struct FrameGuard { + frame: Frame, + extent: vk::Extent2D, + image_idx: usize, + device: Arc, + ext: Arc, +} + +pub struct Swapchain { + pub images: Vec, + pub views: Vec, + pub frames: VecDeque, + command_pool: vk::CommandPool, + pub current_image: usize, + pub format: vk::SurfaceFormatKHR, + pub extent: vk::Extent2D, + pub image_dimensions: ImageDimensions, + inner: vk::SwapchainKHR, + loader: khr::swapchain::Device, + device: Arc, + ext: Arc, +} + +impl Swapchain { + const SUBRANGE: vk::ImageSubresourceRange = vk::ImageSubresourceRange { + aspect_mask: vk::ImageAspectFlags::COLOR, + base_mip_level: 0, + level_count: 1, + base_array_layer: 0, + layer_count: 1, + }; + + pub fn format(&self) -> vk::Format { + self.format.format + } + + pub fn extent(&self) -> vk::Extent2D { + self.extent + } + + pub fn new( + device: &Device, + surface: &Surface, + swapchain_loader: khr::swapchain::Device, + ) -> VkResult { + let info = surface.info(device); + let capabilities = info.capabilities; + let format = info + .formats + .iter() + .find(|format| { + matches!( + format.format, + vk::Format::B8G8R8A8_SRGB | vk::Format::R8G8B8A8_SRGB + ) + }) + .unwrap_or(&info.formats[0]); + + let image_count = capabilities + .max_image_count + .min(3) + .max(capabilities.min_image_count); + + let queue_family_index = [device.main_queue_family_idx]; + + let mut extent = capabilities.current_extent; + //Sadly _current_extent_ can be outside the min/max capabilities :(. + extent.width = extent.width.min(capabilities.max_image_extent.width); + extent.height = extent.height.min(capabilities.max_image_extent.height); + + assert!(capabilities + .supported_composite_alpha + .contains(CompositeAlphaFlagsKHR::OPAQUE)); + let swapchain_create_info = vk::SwapchainCreateInfoKHR::default() + .surface(**surface) + .image_format(format.format) + .image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT | vk::ImageUsageFlags::TRANSFER_SRC) + .image_extent(extent) + .image_color_space(format.color_space) + .min_image_count(image_count) + .image_array_layers(capabilities.max_image_array_layers) + .queue_family_indices(&queue_family_index) + .image_sharing_mode(vk::SharingMode::EXCLUSIVE) + .pre_transform(vk::SurfaceTransformFlagsKHR::IDENTITY) + .composite_alpha(CompositeAlphaFlagsKHR::OPAQUE) + .present_mode(vk::PresentModeKHR::FIFO) + .clipped(true); + let swapchain = unsafe { swapchain_loader.create_swapchain(&swapchain_create_info, None)? }; + + let images = unsafe { swapchain_loader.get_swapchain_images(swapchain)? }; + let views = images + .iter() + .map(|img| device.create_2d_view(img, format.format)) + .collect::>>()?; + + let frames = VecDeque::new(); + + let command_pool = unsafe { + device.create_command_pool( + &vk::CommandPoolCreateInfo::default() + .flags(vk::CommandPoolCreateFlags::TRANSIENT) + .queue_family_index(device.main_queue_family_idx), + None, + )? + }; + + let memory_reqs = unsafe { device.get_image_memory_requirements(images[0]) }; + let image_dimensions = + ImageDimensions::new(extent.width as _, extent.height as _, memory_reqs.alignment); + + Ok(Self { + images, + views, + frames, + command_pool, + current_image: 0, + image_dimensions, + format: *format, + extent, + inner: swapchain, + loader: swapchain_loader, + device: device.device.clone(), + ext: device.ext.clone(), + }) + } + + pub fn destroy(&self) { + for view in self.views.iter() { + unsafe { self.device.destroy_image_view(*view, None) }; + } + unsafe { self.loader.destroy_swapchain(self.inner, None) }; + } + + pub fn recreate(&mut self, device: &Device, surface: &Surface) -> VkResult<()> { + let info = surface.info(device); + let capabilities = info.capabilities; + + for view in self.views.iter() { + unsafe { self.device.destroy_image_view(*view, None) }; + } + let old_swapchain = self.inner; + + let queue_family_index = [device.main_queue_family_idx]; + + let extent = capabilities.current_extent; + self.extent.width = extent.width.min(capabilities.max_image_extent.width); + self.extent.height = extent.height.min(capabilities.max_image_extent.height); + + let swapchain_create_info = vk::SwapchainCreateInfoKHR::default() + .surface(**surface) + .old_swapchain(old_swapchain) + .image_format(self.format.format) + .image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT | vk::ImageUsageFlags::TRANSFER_SRC) + .image_extent(self.extent) + .image_color_space(self.format.color_space) + .min_image_count(self.images.len() as u32) + .image_array_layers(capabilities.max_image_array_layers) + .queue_family_indices(&queue_family_index) + .image_sharing_mode(vk::SharingMode::EXCLUSIVE) + .pre_transform(vk::SurfaceTransformFlagsKHR::IDENTITY) + .composite_alpha(CompositeAlphaFlagsKHR::OPAQUE) + .present_mode(vk::PresentModeKHR::FIFO) + .clipped(true); + self.inner = unsafe { self.loader.create_swapchain(&swapchain_create_info, None)? }; + + unsafe { self.loader.destroy_swapchain(old_swapchain, None) }; + + self.images = unsafe { self.loader.get_swapchain_images(self.inner)? }; + self.views = self + .images + .iter() + .map(|img| device.create_2d_view(img, self.format.format)) + .collect::>>()?; + + let memory_reqs = unsafe { device.get_image_memory_requirements(self.images[0]) }; + self.image_dimensions = + ImageDimensions::new(extent.width as _, extent.height as _, memory_reqs.alignment); + + Ok(()) + } + + pub fn get_current_frame(&self) -> Option<&Frame> { + self.frames.back() + } + pub fn get_current_image(&self) -> &vk::Image { + &self.images[self.current_image] + } + pub fn get_current_image_view(&self) -> &vk::ImageView { + &self.views[self.current_image] + } + + pub fn acquire_next_image(&mut self) -> VkResult { + self.frames.retain_mut(|frame| { + let status = unsafe { self.device.get_fence_status(frame.present_finished) }; + if status == Ok(true) { + frame.destroy(&self.command_pool); + false + } else { + true + } + }); + + let mut frame = Frame::new(&self.device, &self.command_pool)?; + + let idx = match unsafe { + self.loader.acquire_next_image( + self.inner, + u64::MAX, + frame.image_available_semaphore, + vk::Fence::null(), + ) + } { + Ok((idx, false)) => idx, + Ok((_, true)) | Err(vk::Result::ERROR_OUT_OF_DATE_KHR) => { + frame.destroy(&self.command_pool); + return VkResult::Err(vk::Result::ERROR_OUT_OF_DATE_KHR); + } + Err(e) => return Err(e), + }; + + self.current_image = idx as usize; + unsafe { + self.device.begin_command_buffer( + frame.command_buffer, + &vk::CommandBufferBeginInfo::default() + .flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT), + )? + }; + + let image_barrier = vk::ImageMemoryBarrier2::default() + .src_stage_mask(vk::PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT) + .dst_stage_mask(vk::PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT) + .src_access_mask(vk::AccessFlags2::COLOR_ATTACHMENT_WRITE) + .subresource_range(Self::SUBRANGE) + .image(self.images[self.current_image]) + .old_layout(vk::ImageLayout::UNDEFINED) + .new_layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL); + let dependency_info = + vk::DependencyInfo::default().image_memory_barriers(slice::from_ref(&image_barrier)); + unsafe { + self.device + .cmd_pipeline_barrier2(frame.command_buffer, &dependency_info) + }; + + Ok(FrameGuard { + frame, + extent: self.extent, + image_idx: self.current_image, + device: self.device.clone(), + ext: self.ext.clone(), + }) + } + + pub fn submit_image(&mut self, queue: &vk::Queue, frame_guard: FrameGuard) -> VkResult<()> { + let frame = frame_guard.frame; + + let image_barrier = vk::ImageMemoryBarrier2::default() + .src_stage_mask(vk::PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT) + .dst_stage_mask(vk::PipelineStageFlags2::BOTTOM_OF_PIPE) + .src_access_mask(vk::AccessFlags2::COLOR_ATTACHMENT_WRITE) + .subresource_range(Self::SUBRANGE) + .image(self.images[frame_guard.image_idx]) + .old_layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL) + .new_layout(vk::ImageLayout::PRESENT_SRC_KHR); + let dependency_info = + vk::DependencyInfo::default().image_memory_barriers(slice::from_ref(&image_barrier)); + unsafe { + self.device + .cmd_pipeline_barrier2(frame.command_buffer, &dependency_info) + }; + + unsafe { self.device.end_command_buffer(frame.command_buffer) }?; + + let wait_semaphores = [frame.image_available_semaphore]; + let wait_stages = [vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT]; + let signal_semaphores = [frame.render_finished_semaphore]; + let submit_info = vk::SubmitInfo::default() + .wait_semaphores(&wait_semaphores) + .wait_dst_stage_mask(&wait_stages) + .command_buffers(slice::from_ref(&frame.command_buffer)) + .signal_semaphores(&signal_semaphores); + unsafe { + self.device + .queue_submit(*queue, &[submit_info], frame.present_finished)? + }; + + self.frames.push_back(frame); + + let image_indices = [frame_guard.image_idx as u32]; + let present_info = vk::PresentInfoKHR::default() + .wait_semaphores(&signal_semaphores) + .swapchains(slice::from_ref(&self.inner)) + .image_indices(&image_indices); + match unsafe { self.loader.queue_present(*queue, &present_info) } { + Ok(false) => Ok(()), + Ok(true) | Err(vk::Result::ERROR_OUT_OF_DATE_KHR) => { + VkResult::Err(vk::Result::ERROR_OUT_OF_DATE_KHR) + } + Err(e) => Err(e), + } + } +} + +impl Drop for Swapchain { + fn drop(&mut self) { + unsafe { + for view in self.views.iter() { + self.device.destroy_image_view(*view, None); + } + self.loader.destroy_swapchain(self.inner, None); + self.frames + .iter_mut() + .for_each(|f| f.destroy(&self.command_pool)); + self.device.destroy_command_pool(self.command_pool, None); + } + } +} + +impl FrameGuard { + pub fn command_buffer(&self) -> &vk::CommandBuffer { + &self.frame.command_buffer + } + + pub fn begin_rendering(&mut self, view: &vk::ImageView, color: [f32; 4]) { + let clear_color = vk::ClearValue { + color: vk::ClearColorValue { float32: color }, + }; + let color_attachments = [vk::RenderingAttachmentInfo::default() + .image_view(*view) + .image_layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL) + .resolve_image_layout(vk::ImageLayout::PRESENT_SRC_KHR) + .load_op(vk::AttachmentLoadOp::CLEAR) + .store_op(vk::AttachmentStoreOp::STORE) + .clear_value(clear_color)]; + let rendering_info = vk::RenderingInfo::default() + .render_area(self.extent.into()) + .layer_count(1) + .color_attachments(&color_attachments); + unsafe { + self.ext + .dynamic_rendering + .cmd_begin_rendering(self.frame.command_buffer, &rendering_info) + }; + let viewport = vk::Viewport { + x: 0.0, + y: self.extent.height as f32, + width: self.extent.width as f32, + height: -(self.extent.height as f32), + min_depth: 0.0, + max_depth: 1.0, + }; + self.set_viewports(&[viewport]); + self.set_scissors(&[vk::Rect2D { + offset: vk::Offset2D { x: 0, y: 0 }, + extent: self.extent, + }]); + } + + pub fn draw( + &mut self, + vertex_count: u32, + first_vertex: u32, + instance_count: u32, + first_instance: u32, + ) { + unsafe { + self.device.cmd_draw( + self.frame.command_buffer, + vertex_count, + instance_count, + first_vertex, + first_instance, + ) + }; + } + + pub fn draw_indexed( + &mut self, + index_count: u32, + first_index: u32, + vertex_offset: i32, + instance_count: u32, + first_instance: u32, + ) { + unsafe { + self.device.cmd_draw_indexed( + self.frame.command_buffer, + index_count, + instance_count, + first_index, + vertex_offset, + first_instance, + ) + }; + } + + pub fn bind_index_buffer(&self, buffer: vk::Buffer, offset: u64) { + unsafe { + self.device.cmd_bind_index_buffer( + self.frame.command_buffer, + buffer, + offset, + vk::IndexType::UINT32, + ) + }; + } + + pub fn bind_vertex_buffer(&self, buffer: vk::Buffer) { + let buffers = [buffer]; + let offsets = [0]; + unsafe { + self.device + .cmd_bind_vertex_buffers(self.frame.command_buffer, 0, &buffers, &offsets) + }; + } + + pub fn bind_descriptor_sets( + &self, + bind_point: vk::PipelineBindPoint, + pipeline_layout: vk::PipelineLayout, + descriptor_sets: &[vk::DescriptorSet], + ) { + unsafe { + self.device.cmd_bind_descriptor_sets( + self.frame.command_buffer, + bind_point, + pipeline_layout, + 0, + descriptor_sets, + &[], + ) + }; + } + + pub fn push_constant( + &self, + pipeline_layout: vk::PipelineLayout, + stages: vk::ShaderStageFlags, + data: &[T], + ) { + let ptr = core::ptr::from_ref(data); + let bytes = unsafe { core::slice::from_raw_parts(ptr.cast(), std::mem::size_of_val(data)) }; + unsafe { + self.device.cmd_push_constants( + self.frame.command_buffer, + pipeline_layout, + stages, + 0, + bytes, + ) + }; + } + + pub fn set_viewports(&self, viewports: &[vk::Viewport]) { + unsafe { + self.device + .cmd_set_viewport(self.frame.command_buffer, 0, viewports) + } + } + + pub fn set_scissors(&self, viewports: &[vk::Rect2D]) { + unsafe { + self.device + .cmd_set_scissor(self.frame.command_buffer, 0, viewports) + } + } + + pub fn bind_pipeline(&self, bind_point: vk::PipelineBindPoint, &pipeline: &vk::Pipeline) { + unsafe { + self.device + .cmd_bind_pipeline(self.frame.command_buffer, bind_point, pipeline) + } + } + + pub fn dispatch(&self, x: u32, y: u32, z: u32) { + unsafe { self.device.cmd_dispatch(self.frame.command_buffer, x, y, z) }; + } + + pub fn end_rendering(&mut self) { + unsafe { + self.ext + .dynamic_rendering + .cmd_end_rendering(self.frame.command_buffer) + }; + } +} diff --git a/src/texture_arena.rs b/src/texture_arena.rs new file mode 100644 index 0000000..7fcbe82 --- /dev/null +++ b/src/texture_arena.rs @@ -0,0 +1,374 @@ +use std::{mem::ManuallyDrop, sync::Arc}; + +use anyhow::Result; +use ash::{ + prelude::VkResult, + vk::{self, DeviceMemory}, +}; +use gpu_alloc::{GpuAllocator, MemoryBlock, UsageFlags}; +use gpu_alloc_ash::AshMemoryDevice; +use parking_lot::Mutex; + +use crate::{Device, ImageDimensions, RawDevice, COLOR_SUBRESOURCE_MASK}; + +pub const LINEAR_SAMPLER_IDX: usize = 0; +pub const NEAREST_SAMPLER_IDX: usize = 1; + +pub const PREV_FRAME_IMAGE_IDX: usize = 0; +pub const GENERIC_IMAGE1_IDX: usize = 1; +pub const GENERIC_IMAGE2_IDX: usize = 2; +pub const DITHER_IMAGE_IDX: usize = 3; +pub const NOISE_IMAGE_IDX: usize = 4; +pub const BLUE_IMAGE_IDX: usize = 5; +pub const SCREENSIZED_IMAGE_INDICES: [usize; 3] = + [PREV_FRAME_IMAGE_IDX, GENERIC_IMAGE1_IDX, GENERIC_IMAGE2_IDX]; + +pub struct Image { + pub image: vk::Image, + pub memory: ManuallyDrop>, + pub image_dimensions: ImageDimensions, +} + +impl Image { + pub fn new( + device: &RawDevice, + allocator: &mut GpuAllocator, + info: &vk::ImageCreateInfo, + usage: gpu_alloc::UsageFlags, + ) -> Result { + let image = unsafe { device.create_image(info, None)? }; + let memory_reqs = unsafe { device.get_image_memory_requirements(image) }; + let memory = device.alloc_memory(allocator, memory_reqs, usage)?; + unsafe { device.bind_image_memory(image, *memory.memory(), memory.offset()) }?; + let image_dimensions = ImageDimensions::new( + info.extent.width as _, + info.extent.height as _, + memory_reqs.alignment, + ); + Ok(Self { + image, + memory: ManuallyDrop::new(memory), + image_dimensions, + }) + } + + fn desctroy(&mut self, device: &ash::Device, allocator: &mut GpuAllocator) { + unsafe { + let memory = ManuallyDrop::take(&mut self.memory); + allocator.dealloc(AshMemoryDevice::wrap(device), memory); + device.destroy_image(self.image, None) + } + } +} + +const IMAGES_COUNT: u32 = 2048; +const SAMPLER_COUNT: u32 = 8; + +pub struct TextureArena { + pub images: Vec, + pub image_infos: Vec>, + pub views: Vec, + pub samplers: [vk::Sampler; SAMPLER_COUNT as usize], + descriptor_pool: vk::DescriptorPool, + pub images_set: vk::DescriptorSet, + pub images_set_layout: vk::DescriptorSetLayout, + device: Arc, + allocator: Arc>>, +} + +impl TextureArena { + pub fn image_count(&self) -> usize { + self.images.len() + } + + pub fn new(device: &Device, extent: vk::Extent2D) -> Result { + let pool_sizes = [ + vk::DescriptorPoolSize::default() + .ty(vk::DescriptorType::SAMPLED_IMAGE) + .descriptor_count(IMAGES_COUNT), + vk::DescriptorPoolSize::default() + .ty(vk::DescriptorType::SAMPLER) + .descriptor_count(SAMPLER_COUNT), + ]; + let descriptor_pool = unsafe { + device.create_descriptor_pool( + &vk::DescriptorPoolCreateInfo::default() + .flags( + vk::DescriptorPoolCreateFlags::UPDATE_AFTER_BIND + | vk::DescriptorPoolCreateFlags::FREE_DESCRIPTOR_SET, + ) + .pool_sizes(&pool_sizes) + .max_sets(1), + None, + )? + }; + + let binding_flags = vk::DescriptorBindingFlags::PARTIALLY_BOUND + | vk::DescriptorBindingFlags::UPDATE_AFTER_BIND + | vk::DescriptorBindingFlags::UPDATE_UNUSED_WHILE_PENDING; + let binding_flags = [ + binding_flags, + binding_flags | vk::DescriptorBindingFlags::VARIABLE_DESCRIPTOR_COUNT, + ]; + let mut binding_flags = + vk::DescriptorSetLayoutBindingFlagsCreateInfo::default().binding_flags(&binding_flags); + let sampler_set_layout_binding = vk::DescriptorSetLayoutBinding::default() + .binding(0) + .descriptor_type(vk::DescriptorType::SAMPLER) + .stage_flags(vk::ShaderStageFlags::ALL_GRAPHICS | vk::ShaderStageFlags::COMPUTE) + .descriptor_count( + device + .descriptor_indexing_props + .max_descriptor_set_update_after_bind_samplers, + ); + let image_set_layout_binding = vk::DescriptorSetLayoutBinding::default() + .binding(1) + .descriptor_type(vk::DescriptorType::SAMPLED_IMAGE) + .stage_flags(vk::ShaderStageFlags::ALL_GRAPHICS | vk::ShaderStageFlags::COMPUTE) + .descriptor_count( + device + .descriptor_indexing_props + .max_descriptor_set_update_after_bind_sampled_images, + ); + let bindings = [sampler_set_layout_binding, image_set_layout_binding]; + let images_set_layout = unsafe { + device.create_descriptor_set_layout( + &vk::DescriptorSetLayoutCreateInfo::default() + .bindings(&bindings) + .flags(vk::DescriptorSetLayoutCreateFlags::UPDATE_AFTER_BIND_POOL) + .push_next(&mut binding_flags), + None, + )? + }; + + let mut variable_info = vk::DescriptorSetVariableDescriptorCountAllocateInfo::default() + .descriptor_counts(&[IMAGES_COUNT]); + let allocate_info = vk::DescriptorSetAllocateInfo::default() + .descriptor_pool(descriptor_pool) + .set_layouts(std::slice::from_ref(&images_set_layout)) + .push_next(&mut variable_info); + let images_set = unsafe { device.allocate_descriptor_sets(&allocate_info)? }[0]; + + let image_infos: [_; 3] = std::array::from_fn(|_| { + vk::ImageCreateInfo::default() + .extent(vk::Extent3D { + width: extent.width, + height: extent.height, + depth: 1, + }) + .image_type(vk::ImageType::TYPE_2D) + .format(vk::Format::R8G8B8A8_SRGB) + .usage(vk::ImageUsageFlags::SAMPLED | vk::ImageUsageFlags::TRANSFER_DST) + .samples(vk::SampleCountFlags::TYPE_1) + .mip_levels(1) + .array_layers(1) + .tiling(vk::ImageTiling::OPTIMAL) + }); + + let images = image_infos + .iter() + .map(|info| { + let mut allocator = device.allocator.lock(); + Image::new( + device, + &mut allocator, + info, + gpu_alloc::UsageFlags::FAST_DEVICE_ACCESS, + ) + }) + .collect::>>()?; + + let views = images + .iter() + .zip(image_infos) + .map(|(image, info)| device.create_2d_view(&image.image, info.format)) + .collect::>>()?; + + for (i, view) in views.iter().enumerate() { + let image_info = vk::DescriptorImageInfo::default() + .image_view(*view) + .image_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL); + let write = vk::WriteDescriptorSet::default() + .dst_set(images_set) + .descriptor_type(vk::DescriptorType::SAMPLED_IMAGE) + .dst_binding(1) + .image_info(std::slice::from_ref(&image_info)) + .dst_array_element(i as _); + unsafe { device.update_descriptor_sets(&[write], &[]) }; + } + + let mut samplers = [vk::Sampler::null(); SAMPLER_COUNT as usize]; + let mut sampler_create_info = vk::SamplerCreateInfo::default() + .min_filter(vk::Filter::LINEAR) + .mag_filter(vk::Filter::LINEAR) + .mipmap_mode(vk::SamplerMipmapMode::NEAREST) + .address_mode_u(vk::SamplerAddressMode::MIRRORED_REPEAT) + .address_mode_v(vk::SamplerAddressMode::MIRRORED_REPEAT) + .address_mode_w(vk::SamplerAddressMode::MIRRORED_REPEAT) + .max_lod(vk::LOD_CLAMP_NONE); + let sampler = unsafe { device.create_sampler(&sampler_create_info, None)? }; + let descriptor_image_info = vk::DescriptorImageInfo::default().sampler(sampler); + let mut desc_write = vk::WriteDescriptorSet::default() + .descriptor_type(vk::DescriptorType::SAMPLER) + .dst_set(images_set) + .dst_binding(0) + .image_info(std::slice::from_ref(&descriptor_image_info)) + .dst_array_element(0); + unsafe { device.update_descriptor_sets(&[desc_write], &[]) }; + samplers[0] = sampler; + + sampler_create_info = sampler_create_info + .mag_filter(vk::Filter::NEAREST) + .min_filter(vk::Filter::NEAREST); + let sampler = unsafe { device.create_sampler(&sampler_create_info, None)? }; + let descriptor_image_info = vk::DescriptorImageInfo::default().sampler(sampler); + desc_write = desc_write.image_info(std::slice::from_ref(&descriptor_image_info)); + unsafe { device.update_descriptor_sets(&[desc_write], &[]) }; + samplers[1] = sampler; + + Ok(Self { + images, + image_infos: image_infos.to_vec(), + views, + samplers, + descriptor_pool, + images_set, + images_set_layout, + device: device.device.clone(), + allocator: device.allocator.clone(), + }) + } + + pub fn push_image( + &mut self, + device: &Device, + queue: &vk::Queue, + info: vk::ImageCreateInfo, + data: &[u8], + ) -> Result { + let image = { + let mut allocator = device.allocator.lock(); + Image::new( + device, + &mut allocator, + &info, + UsageFlags::FAST_DEVICE_ACCESS, + )? + }; + let mut staging = device.create_host_buffer( + image.memory.size(), + vk::BufferUsageFlags::TRANSFER_SRC, + UsageFlags::UPLOAD, + )?; + staging[..data.len()].copy_from_slice(data); + + device.one_time_submit(queue, |device, cbuff| unsafe { + let mut image_barrier = vk::ImageMemoryBarrier2::default() + .subresource_range(COLOR_SUBRESOURCE_MASK) + .old_layout(vk::ImageLayout::UNDEFINED) + .new_layout(vk::ImageLayout::TRANSFER_DST_OPTIMAL) + .image(image.image); + let dependency_info = vk::DependencyInfo::default() + .image_memory_barriers(std::slice::from_ref(&image_barrier)); + device.cmd_pipeline_barrier2(cbuff, &dependency_info); + let regions = vk::BufferImageCopy::default() + .image_extent(info.extent) + .image_subresource(vk::ImageSubresourceLayers { + aspect_mask: vk::ImageAspectFlags::COLOR, + base_array_layer: 0, + layer_count: 1, + mip_level: 0, + }); + device.cmd_copy_buffer_to_image( + cbuff, + staging.buffer, + image.image, + vk::ImageLayout::TRANSFER_DST_OPTIMAL, + &[regions], + ); + image_barrier.old_layout = vk::ImageLayout::TRANSFER_DST_OPTIMAL; + image_barrier.new_layout = vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL; + let dependency_info = vk::DependencyInfo::default() + .image_memory_barriers(std::slice::from_ref(&image_barrier)); + device.cmd_pipeline_barrier2(cbuff, &dependency_info); + })?; + + let view = self.device.create_2d_view(&image.image, info.format)?; + let idx = self.images.len() as u32; + + let image_info = vk::DescriptorImageInfo::default() + .image_view(view) + .image_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL); + let write = vk::WriteDescriptorSet::default() + .dst_set(self.images_set) + .descriptor_type(vk::DescriptorType::SAMPLED_IMAGE) + .dst_binding(1) + .image_info(std::slice::from_ref(&image_info)) + .dst_array_element(idx); + unsafe { device.update_descriptor_sets(&[write], &[]) }; + + self.images.push(image); + self.views.push(view); + + Ok(idx) + } + + pub fn update_images(&mut self, indices: &[usize]) -> Result<()> { + let mut allocator = self.allocator.lock(); + for (i, info) in indices.iter().map(|&i| (i, &self.image_infos[i])) { + let image = { + Image::new( + &self.device, + &mut allocator, + info, + gpu_alloc::UsageFlags::FAST_DEVICE_ACCESS, + )? + }; + let view = self.device.create_2d_view(&image.image, info.format)?; + + let image_info = vk::DescriptorImageInfo::default() + .image_view(view) + .image_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL); + let write = vk::WriteDescriptorSet::default() + .dst_set(self.images_set) + .descriptor_type(vk::DescriptorType::SAMPLED_IMAGE) + .dst_binding(1) + .image_info(std::slice::from_ref(&image_info)) + .dst_array_element(i as _); + unsafe { self.device.update_descriptor_sets(&[write], &[]) }; + + self.images[i].desctroy(&self.device, &mut allocator); + unsafe { self.device.destroy_image_view(self.views[i], None) }; + self.images[i] = image; + self.views[i] = view; + } + + Ok(()) + } +} + +impl Drop for TextureArena { + fn drop(&mut self) { + unsafe { + { + let mut allocator = self.allocator.lock(); + self.images.iter_mut().for_each(|image| { + image.desctroy(&self.device, &mut allocator); + }); + } + self.views + .iter() + .for_each(|&view| self.device.destroy_image_view(view, None)); + self.samplers + .iter() + .for_each(|&sampler| self.device.destroy_sampler(sampler, None)); + let _ = self + .device + .free_descriptor_sets(self.descriptor_pool, &[self.images_set]); + self.device + .destroy_descriptor_set_layout(self.images_set_layout, None); + self.device + .destroy_descriptor_pool(self.descriptor_pool, None); + } + } +} diff --git a/src/utils.rs b/src/utils.rs deleted file mode 100644 index 7993f77..0000000 --- a/src/utils.rs +++ /dev/null @@ -1,193 +0,0 @@ -use color_eyre::*; - -use crate::{SCREENSHOTS_FOLDER, SHADER_DUMP_FOLDER, SHADER_PATH}; -use pilka_types::{ImageDimentions, ShaderFlavor}; - -use std::{ - ffi::OsStr, - fs::File, - io::{self, BufWriter, Write}, - path::{Path, PathBuf}, - time::{Duration, Instant}, -}; - -pub fn print_help() { - println!("\n- `F1`: Print help"); - println!("- `F2`: Toggle play/pause"); - println!("- `F3`: Pause and step back one frame"); - println!("- `F4`: Pause and step forward one frame"); - println!("- `F5`: Restart playback at frame 0 (`Time` and `Pos` = 0)"); - println!("- `F6`: Print parameters"); - println!("- `F7`: Toggle profiler"); - println!("- `F8`: Switch backend"); - println!("- `F10`: Save shaders"); - println!("- `F11`: Take Screenshot"); - println!("- `F12`: Start/Stop record video"); - println!("- `ESC`: Exit the application"); - println!("- `Arrows`: Change `Pos`\n"); -} - -pub fn create_folder>(name: P) -> io::Result<()> { - match std::fs::create_dir(name) { - Ok(_) => {} - Err(e) if e.kind() == io::ErrorKind::AlreadyExists => {} - Err(e) => return Err(e), - } - - Ok(()) -} - -#[derive(Debug)] -pub struct Args { - pub inner_size: Option<(u32, u32)>, - pub record_time: Option, - pub wgsl_mode: Option<()>, -} - -pub fn parse_args() -> Args { - let mut inner_size = None; - let mut record_time = None; - let mut wgsl_mode = None; - let args = std::env::args().skip(1).collect::>(); - for arg in args.iter().zip(args.iter().cycle().skip(1)) { - match arg.0.as_str() { - "--record" => { - record_time = - Some(Duration::from_secs_f32(arg.1.parse().expect( - &format!("Record duration should be a number: {}", arg.1)[..], - ))) - } - "--size" => { - let mut iter = arg - .1 - .split('x') - .map(str::parse) - .map(|x| x.expect(&format!("Failed to parse window size: {}", arg.1)[..])); - inner_size = Some((iter.next().unwrap(), iter.next().unwrap())); - } - "--wgsl" => wgsl_mode = Some(()), - _ => {} - } - } - - Args { - record_time, - inner_size, - wgsl_mode, - } -} - -pub fn save_screenshot( - frame: Vec, - image_dimentions: ImageDimentions, -) -> std::thread::JoinHandle> { - std::thread::spawn(move || { - let now = Instant::now(); - let screenshots_folder = Path::new(SCREENSHOTS_FOLDER); - create_folder(screenshots_folder)?; - let path = screenshots_folder.join(format!( - "screenshot-{}.png", - chrono::Local::now().format("%d-%m-%Y-%H-%M-%S") - )); - let file = File::create(path)?; - let w = BufWriter::new(file); - let mut encoder = - png::Encoder::new(w, image_dimentions.width as _, image_dimentions.height as _); - encoder.set_color(png::ColorType::Rgba); - encoder.set_depth(png::BitDepth::Eight); - let padded_bytes = image_dimentions.padded_bytes_per_row as _; - let unpadded_bytes = image_dimentions.unpadded_bytes_per_row as _; - let mut writer = encoder - .write_header()? - .into_stream_writer_with_size(unpadded_bytes)?; - for chunk in frame - .chunks(padded_bytes) - .map(|chunk| &chunk[..unpadded_bytes]) - { - writer.write_all(chunk)?; - } - writer.finish()?; - eprintln!("Encode image: {:#.2?}", now.elapsed()); - Ok(()) - }) -} - -pub fn save_shaders>(paths: &[P]) -> Result<()> { - let dump_folder = Path::new(SHADER_DUMP_FOLDER); - create_folder(dump_folder)?; - let dump_folder = - dump_folder.join(chrono::Local::now().format("%d-%m-%Y-%H-%M-%S").to_string()); - create_folder(&dump_folder)?; - let dump_folder = dump_folder.join(SHADER_PATH); - create_folder(&dump_folder)?; - - for path in paths { - let to = dump_folder.join( - path.as_ref() - .strip_prefix(Path::new(SHADER_PATH).canonicalize()?)?, - ); - if !to.exists() { - std::fs::create_dir_all(&to.parent().unwrap().canonicalize()?)?; - File::create(&to)?; - } - std::fs::copy(path, &to)?; - eprintln!("Saved: {}", &to.display()); - } - - Ok(()) -} - -#[derive(Debug, Clone)] -pub struct PilkaSpec { - pub frag: ShaderInfo, - pub comp: ShaderInfo, - pub vert: ShaderInfo, - pub glsl_prelude: Option, -} - -#[derive(Debug, Clone)] -pub struct ShaderInfo { - pub path: PathBuf, - pub ty: ShaderFlavor, -} - -pub fn parse_folder(folder: &str) -> Result> { - let mut frag_si = None; - let mut comp_si = None; - let mut vert_si = None; - let mut prelude = None; - let shader_dir = PathBuf::new().join(folder); - for path in shader_dir.read_dir()? { - let path = path?.path(); - - let ty = match path.extension().and_then(OsStr::to_str) { - Some("wgsl") => ShaderFlavor::Wgsl, - Some("glsl" | "frag" | "comp" | "vert") => ShaderFlavor::Glsl, - _ => { - println!("This file have been ignored: {}", path.display()); - continue; - } - }; - - let si = ShaderInfo { path, ty }; - let file_name = si.path.to_str().unwrap(); - if file_name.contains("frag") && frag_si.is_none() { - frag_si = Some(si); - } else if file_name.contains("comp") && comp_si.is_none() { - comp_si = Some(si); - } else if file_name.contains("vert") && vert_si.is_none() { - vert_si = Some(si); - } else if file_name.contains("prelude") { - prelude = Some(si.path); - } else { - println!("This file have been rejected: {}", si.path.display()); - } - } - - Ok(PilkaSpec { - frag: frag_si.expect("Fragment shader is not provided"), - vert: vert_si.expect("Vertex shader is not provided"), - comp: comp_si.expect("Compute shader is not provided"), - glsl_prelude: prelude, - }) -} diff --git a/src/watcher.rs b/src/watcher.rs new file mode 100644 index 0000000..b2d469b --- /dev/null +++ b/src/watcher.rs @@ -0,0 +1,75 @@ +use ahash::{AHashMap, AHashSet}; +use anyhow::Result; +use notify_debouncer_mini::{DebounceEventResult, DebouncedEventKind}; +use winit::event_loop::EventLoopProxy; + +use std::{ + ffi::OsStr, + path::{Path, PathBuf}, + sync::Arc, + time::Duration, +}; + +use crate::{ShaderSource, UserEvent}; + +use parking_lot::Mutex; + +#[derive(Clone)] +pub struct Watcher { + pub watcher: Arc>>, + pub include_mapping: Arc>>>, +} + +impl Watcher { + pub fn new(proxy: EventLoopProxy) -> Result { + let watcher = notify_debouncer_mini::new_debouncer( + Duration::from_millis(350), + watch_callback(proxy), + )?; + + Ok(Self { + watcher: Arc::new(Mutex::new(watcher)), + include_mapping: Arc::new(Mutex::new(AHashMap::new())), + }) + } + + pub fn unwatch_file(&mut self, path: impl AsRef) -> Result<()> { + let mut watcher = self.watcher.lock(); + watcher.watcher().unwatch(path.as_ref())?; + Ok(()) + } + + pub fn watch_file(&mut self, path: impl AsRef) -> Result<()> { + let mut watcher = self.watcher.lock(); + watcher + .watcher() + .watch(path.as_ref(), notify::RecursiveMode::NonRecursive)?; + Ok(()) + } +} + +fn watch_callback(proxy: EventLoopProxy) -> impl FnMut(DebounceEventResult) { + move |event| match event { + Ok(events) => { + if let Some(path) = events + .into_iter() + .filter(|e| e.kind == DebouncedEventKind::Any) + .map(|event| event.path) + .next() + { + if path.extension() == Some(OsStr::new("glsl")) + || path.extension() == Some(OsStr::new("frag")) + || path.extension() == Some(OsStr::new("vert")) + || path.extension() == Some(OsStr::new("comp")) + { + let _ = proxy + .send_event(UserEvent::Glsl { + path: path.canonicalize().unwrap(), + }) + .map_err(|err| eprintln!("Event Loop has been dropped: {err}")); + } + } + } + Err(errors) => eprintln!("File watcher error: {errors}"), + } +}