diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml new file mode 100644 index 0000000..2da06ab --- /dev/null +++ b/.github/workflows/rust.yml @@ -0,0 +1,49 @@ +name: Release + +permissions: + contents: write + +on: + push: + tags: + - v[0-9]+.* + +jobs: + create-release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: taiki-e/create-gh-release-action@v1 + with: + # (required) GitHub token for creating GitHub Releases. + token: ${{ secrets.PERSONAL_GITHUB_TOKEN }} + + upload-assets: + strategy: + matrix: + os: + #- ubuntu-latest + #- macos-latest + - windows-latest + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + - uses: taiki-e/upload-rust-binary-action@v1 + with: + # (required) Comma-separated list of binary names (non-extension portion of filename) to build and upload. + # Note that glob pattern is not supported yet. + bin: vr-screen-cap + # (optional) On which platform to distribute the `.tar.gz` file. + # [default value: unix] + # [possible values: all, unix, windows, none] + #tar: unix + # (optional) On which platform to distribute the `.zip` file. + # [default value: windows] + # [possible values: all, unix, windows, none] + zip: windows + # (optional) Whether to disable cargo build default features + no_default_features: true + # (optional) Comma-separated list of cargo build features to enable + features: dist + # (required) GitHub token for uploading assets to GitHub Releases. + token: ${{ secrets.PERSONAL_GITHUB_TOKEN }} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index e72424f..3200898 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -7,7 +7,6 @@ "program": "${workspaceRoot}/target/debug/vr-screen-cap.exe", "cwd": "${workspaceRoot}/target/debug", "preLaunchTask": "build", - "args": ["--config-file", "E:/ArtumRepos/Rust/VRScreenCap/target/release/config.json"], "environment": [ { "name": "RUST_BACKTRACE", @@ -26,7 +25,6 @@ "program": "${workspaceRoot}/target/release/vr-screen-cap.exe", "cwd": "${workspaceRoot}/target/release", "preLaunchTask": "build-release", - "args": ["--config-file", "E:/ArtumRepos/Rust/VRScreenCap/target/release/config.json"], "environment": [ { "name": "RUST_BACKTRACE", diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..ec17418 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "rust-analyzer.linkedProjects": [ + ".\\Cargo.toml" + ] +} \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index b3e7497..134042f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.19.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "gimli", ] @@ -40,6 +40,21 @@ dependencies = [ "version_check", ] +[[package]] +name = "aho-corasick" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab" +dependencies = [ + "memchr", +] + +[[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" version = "0.1.5" @@ -51,30 +66,29 @@ dependencies = [ [[package]] name = "anstream" -version = "0.3.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e579a7752471abc2a8268df8b20005e3eadd975f585398f17efcfd8d4927371" +checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", - "is-terminal", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" +checksum = "b84bf0a05bbb2a83e5eb6fa36bb6e87baa08193c35ff52bbf6b38d8af2890e46" [[package]] name = "anstyle-parse" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" +checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" dependencies = [ "utf8parse", ] @@ -90,9 +104,9 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "1.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcd8291a340dd8ac70e18878bc4501dd7b4ff970cfa21c207d36ece51ea88fd" +checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd" dependencies = [ "anstyle", "windows-sys 0.48.0", @@ -100,9 +114,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.70" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "approx" @@ -121,43 +135,19 @@ checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" [[package]] name = "arrayvec" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "ash" -version = "0.37.2+1.3.238" +version = "0.37.3+1.3.251" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28bf19c1f0a470be5fbf7522a308a05df06610252c5bcf5143e1b23f629a9a03" +checksum = "39e9c3835d686b0a6084ab4234fcd1b07dbf6e4767dce60874b12356a25ecd4a" dependencies = [ "libloading 0.7.4", ] -[[package]] -name = "atk" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c3d816ce6f0e2909a96830d6911c2aff044370b1ef92d7f267b43bae5addedd" -dependencies = [ - "atk-sys", - "bitflags 1.3.2", - "glib", - "libc", -] - -[[package]] -name = "atk-sys" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58aeb089fb698e06db8089971c7ee317ab9644bade33383f63631437b03aafb6" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - [[package]] name = "autocfg" version = "1.1.0" @@ -166,15 +156,15 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.67" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", "cfg-if", "libc", - "miniz_oxide 0.6.2", + "miniz_oxide", "object", "rustc-demangle", ] @@ -202,9 +192,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.1.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c70beb79cbb5ce9c4f8e20849978f34225931f665bb49efa6982875a4d5facb3" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" [[package]] name = "block" @@ -214,28 +204,28 @@ checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" [[package]] name = "bumpalo" -version = "3.12.1" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b1ce199063694f33ffb7dd4e0ee620741495c32833cde5aa08f02a0bf96f0c8" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "bytemuck" -version = "1.13.1" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" +checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdde5c9cd29ebd706ce1b35600920a33550e402fc998a2e53ad3b42c3c47a192" +checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.37", ] [[package]] @@ -246,56 +236,35 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] -name = "cairo-rs" -version = "0.15.12" +name = "captrs" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c76ee391b03d35510d9fa917357c7f1855bd9a6659c95a1b392e33f49b3369bc" +checksum = "dad312f1be0ea3cce9ad0cdbace33350ea0781f138d7b49bfe191df0aa83db1b" dependencies = [ - "bitflags 1.3.2", - "cairo-sys-rs", - "glib", - "libc", - "thiserror", + "dxgcap", + "x11cap", ] [[package]] -name = "cairo-sys-rs" -version = "0.15.1" +name = "cc" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c55d429bef56ac9172d25fecb85dc8068307d17acd74b377866b7a1ef25d3c8" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ - "glib-sys", "libc", - "system-deps", ] -[[package]] -name = "cc" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" - [[package]] name = "cesu8" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" -[[package]] -name = "cfg-expr" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8790cf1286da485c72cf5fc7aeba308438800036ec67d89425924c4807268c9" -dependencies = [ - "smallvec", - "target-lexicon", -] - [[package]] name = "cfg-if" version = "1.0.0" @@ -315,60 +284,57 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.24" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" dependencies = [ + "android-tzdata", "iana-time-zone", "js-sys", - "num-integer", "num-traits", - "time", "wasm-bindgen", - "winapi", + "windows-targets 0.48.5", ] [[package]] name = "clap" -version = "4.2.4" +version = "4.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956ac1f6381d8d82ab4684768f89c0ea3afe66925ceadb4eeb3fc452ffc55d62" +checksum = "b1d7b8d5ec32af0fadc644bf1fd509a688c2103b185644bb1e29d164e0703136" dependencies = [ "clap_builder", "clap_derive", - "once_cell", ] [[package]] name = "clap_builder" -version = "4.2.4" +version = "4.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84080e799e54cff944f4b4a4b0e71630b0e0443b25b985175c7dddc1a859b749" +checksum = "5179bb514e4d7c2051749d8fcefa2ed6d06a9f4e6d69faf3805f5d80b8cf8d56" dependencies = [ "anstream", "anstyle", - "bitflags 1.3.2", "clap_lex", "strsim", ] [[package]] name = "clap_derive" -version = "4.2.0" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9644cd56d6b87dbe899ef8b053e331c0637664e9e21a33dfcdc36093f5c5c4" +checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.37", ] [[package]] name = "clap_lex" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1" +checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" [[package]] name = "cmake" @@ -390,22 +356,21 @@ dependencies = [ "cocoa-foundation", "core-foundation", "core-graphics", - "foreign-types", + "foreign-types 0.3.2", "libc", "objc", ] [[package]] name = "cocoa-foundation" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "931d3837c286f56e3c58423ce4eba12d08db2374461a785c86f672b08b5650d6" +checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" dependencies = [ "bitflags 1.3.2", "block", "core-foundation", "core-graphics-types", - "foreign-types", "libc", "objc", ] @@ -473,19 +438,18 @@ dependencies = [ "bitflags 1.3.2", "core-foundation", "core-graphics-types", - "foreign-types", + "foreign-types 0.3.2", "libc", ] [[package]] name = "core-graphics-types" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" +checksum = "2bb142d41022986c1d8ff29103a1411c8a3dfad3552f87a4f8dc50d61d4f4e33" dependencies = [ "bitflags 1.3.2", "core-foundation", - "foreign-types", "libc", ] @@ -510,64 +474,21 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.15" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ "cfg-if", ] -[[package]] -name = "cxx" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f61f1b6389c3fe1c316bf8a4dccc90a38208354b330925bce1f74a6c4756eb93" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cee708e8962df2aeb38f594aae5d827c022b6460ac71a7a3e2c3c2aae5a07b" -dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn 2.0.15", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7944172ae7e4068c533afbb984114a56c46e9ccddda550499caa222902c7f7bb" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.15", -] - [[package]] name = "d3d12" -version = "0.6.0" -source = "git+https://github.com/gfx-rs/d3d12-rs?rev=b940b1d71#b940b1d71ab7083ae80eec697872672dc1f2bd32" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16e44ab292b1dddfdaf7be62cfd8877df52f2f3fde5858d95bab606be259f20" dependencies = [ - "bitflags 1.3.2", - "libloading 0.7.4", + "bitflags 2.4.0", + "libloading 0.8.0", "winapi", ] @@ -640,25 +561,20 @@ dependencies = [ ] [[package]] -name = "errno" -version = "0.3.1" +name = "dxgcap" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +checksum = "18a3f3df51c509e7c8d2807c63abfecdea1a83def81baec83d68c6f5bb8ac654" dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys 0.48.0", + "winapi", + "wio", ] [[package]] -name = "errno-dragonfly" -version = "0.1.2" +name = "equivalent" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "fdeflate" @@ -669,36 +585,26 @@ dependencies = [ "simd-adler32", ] -[[package]] -name = "field-offset" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3cf3a800ff6e860c863ca6d4b16fd999db8b752819c1606884047b73e468535" -dependencies = [ - "memoffset", - "rustc_version", -] - [[package]] name = "filetime" -version = "0.2.21" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153" +checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.3.5", "windows-sys 0.48.0", ] [[package]] name = "flate2" -version = "1.0.25" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" +checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" dependencies = [ "crc32fast", - "miniz_oxide 0.6.2", + "miniz_oxide", ] [[package]] @@ -722,7 +628,28 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" dependencies = [ - "foreign-types-shared", + "foreign-types-shared 0.1.1", +] + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared 0.3.1", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", ] [[package]] @@ -731,6 +658,12 @@ 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 = "fsevent-sys" version = "4.1.0" @@ -740,6 +673,21 @@ dependencies = [ "libc", ] +[[package]] +name = "futures" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.28" @@ -747,6 +695,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ "futures-core", + "futures-sink", ] [[package]] @@ -772,6 +721,23 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +[[package]] +name = "futures-macro" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", +] + +[[package]] +name = "futures-sink" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" + [[package]] name = "futures-task" version = "0.3.28" @@ -784,77 +750,23 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ + "futures-channel", "futures-core", + "futures-io", + "futures-macro", + "futures-sink", "futures-task", + "memchr", "pin-project-lite", "pin-utils", "slab", ] -[[package]] -name = "gdk" -version = "0.15.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6e05c1f572ab0e1f15be94217f0dc29088c248b14f792a5ff0af0d84bcda9e8" -dependencies = [ - "bitflags 1.3.2", - "cairo-rs", - "gdk-pixbuf", - "gdk-sys", - "gio", - "glib", - "libc", - "pango", -] - -[[package]] -name = "gdk-pixbuf" -version = "0.15.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad38dd9cc8b099cceecdf41375bb6d481b1b5a7cd5cd603e10a69a9383f8619a" -dependencies = [ - "bitflags 1.3.2", - "gdk-pixbuf-sys", - "gio", - "glib", - "libc", -] - -[[package]] -name = "gdk-pixbuf-sys" -version = "0.15.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "140b2f5378256527150350a8346dbdb08fadc13453a7a2d73aecd5fab3c402a7" -dependencies = [ - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "gdk-sys" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32e7a08c1e8f06f4177fb7e51a777b8c1689f743a7bc11ea91d44d2226073a88" -dependencies = [ - "cairo-sys-rs", - "gdk-pixbuf-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "pango-sys", - "pkg-config", - "system-deps", -] - [[package]] name = "generator" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3e123d9ae7c02966b4d892e550bdc32164f05853cd40ab570650ad600596a8a" +checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" dependencies = [ "cc", "libc", @@ -865,101 +777,26 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", ] [[package]] name = "gimli" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" - -[[package]] -name = "gio" -version = "0.15.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68fdbc90312d462781a395f7a16d96a2b379bb6ef8cd6310a2df272771c4283b" -dependencies = [ - "bitflags 1.3.2", - "futures-channel", - "futures-core", - "futures-io", - "gio-sys", - "glib", - "libc", - "once_cell", - "thiserror", -] - -[[package]] -name = "gio-sys" -version = "0.15.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32157a475271e2c4a023382e9cab31c4584ee30a97da41d3c4e9fdd605abcf8d" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", - "winapi", -] - -[[package]] -name = "glib" -version = "0.15.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edb0306fbad0ab5428b0ca674a23893db909a98582969c9b537be4ced78c505d" -dependencies = [ - "bitflags 1.3.2", - "futures-channel", - "futures-core", - "futures-executor", - "futures-task", - "glib-macros", - "glib-sys", - "gobject-sys", - "libc", - "once_cell", - "smallvec", - "thiserror", -] - -[[package]] -name = "glib-macros" -version = "0.15.13" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10c6ae9f6fa26f4fb2ac16b528d138d971ead56141de489f8111e259b9df3c4a" -dependencies = [ - "anyhow", - "heck", - "proc-macro-crate", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "glib-sys" -version = "0.15.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef4b192f8e65e9cf76cbf4ea71fa8e3be4a0e18ffe3d68b8da6836974cc5bad4" -dependencies = [ - "libc", - "system-deps", -] +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" [[package]] name = "glow" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e007a07a24de5ecae94160f141029e9a347282cfe25d1d58d85d845cf3130f1" +checksum = "ca0fe580e4b60a8ab24a868bc08e2f03cbcb20d3d676601fa909386713333728" dependencies = [ "js-sys", "slotmap", @@ -967,34 +804,23 @@ dependencies = [ "web-sys", ] -[[package]] -name = "gobject-sys" -version = "0.15.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d57ce44246becd17153bd035ab4d32cfee096a657fc01f2231c9278378d1e0a" -dependencies = [ - "glib-sys", - "libc", - "system-deps", -] - [[package]] name = "gpu-alloc" -version = "0.5.3" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fc59e5f710e310e76e6707f86c561dd646f69a8876da9131703b2f717de818d" +checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.0", "gpu-alloc-types", ] [[package]] name = "gpu-alloc-types" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54804d0d6bc9d7f26db4eaec1ad10def69b599315f487d32c334a80d1efe67a5" +checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.0", ] [[package]] @@ -1018,7 +844,7 @@ checksum = "0b0c02e1ba0bdb14e965058ca34e09c020f8e507a760df1121728e0aef68d57a" dependencies = [ "bitflags 1.3.2", "gpu-descriptor-types", - "hashbrown", + "hashbrown 0.12.3", ] [[package]] @@ -1030,61 +856,6 @@ dependencies = [ "bitflags 1.3.2", ] -[[package]] -name = "gtk" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e3004a2d5d6d8b5057d2b57b3712c9529b62e82c77f25c1fecde1fd5c23bd0" -dependencies = [ - "atk", - "bitflags 1.3.2", - "cairo-rs", - "field-offset", - "futures-channel", - "gdk", - "gdk-pixbuf", - "gio", - "glib", - "gtk-sys", - "gtk3-macros", - "libc", - "once_cell", - "pango", - "pkg-config", -] - -[[package]] -name = "gtk-sys" -version = "0.15.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5bc2f0587cba247f60246a0ca11fe25fb733eabc3de12d1965fc07efab87c84" -dependencies = [ - "atk-sys", - "cairo-sys-rs", - "gdk-pixbuf-sys", - "gdk-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "pango-sys", - "system-deps", -] - -[[package]] -name = "gtk3-macros" -version = "0.15.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "684c0456c086e8e7e9af73ec5b84e35938df394712054550e81558d21c44ab0d" -dependencies = [ - "anyhow", - "proc-macro-crate", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "hashbrown" version = "0.12.3" @@ -1094,6 +865,12 @@ dependencies = [ "ahash 0.7.6", ] +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + [[package]] name = "hassle-rs" version = "0.10.0" @@ -1115,12 +892,6 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -[[package]] -name = "hermit-abi" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" - [[package]] name = "hexf-parse" version = "0.2.1" @@ -1135,9 +906,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "iana-time-zone" -version = "0.1.56" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" +checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1149,12 +920,11 @@ dependencies = [ [[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]] @@ -1165,9 +935,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "image" -version = "0.24.6" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "527909aa81e20ac3a44803521443a765550f09b5130c2c2fa1ea59c2f8f50a3a" +checksum = "6f3dfdbdd72063086ff443e297b61695500514b1e41095b6fb9a5ab48a70a711" dependencies = [ "bytemuck", "byteorder", @@ -1185,7 +955,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown 0.14.0", ] [[package]] @@ -1209,47 +989,10 @@ dependencies = [ ] [[package]] -name = "io-lifetimes" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" -dependencies = [ - "hermit-abi", - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "is-terminal" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" -dependencies = [ - "hermit-abi", - "io-lifetimes", - "rustix", - "windows-sys 0.48.0", -] - -[[package]] -name = "itoa" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" - -[[package]] -name = "jni" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" -dependencies = [ - "cesu8", - "combine", - "jni-sys", - "log", - "thiserror", - "walkdir", -] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "jni" @@ -1281,9 +1024,9 @@ checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e" [[package]] name = "js-sys" -version = "0.3.61" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" dependencies = [ "wasm-bindgen", ] @@ -1301,9 +1044,9 @@ dependencies = [ [[package]] name = "kqueue" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c8fc60ba15bf51257aa9807a48a61013db043fcf3a78cb0d916e8e396dcad98" +checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c" dependencies = [ "kqueue-sys", "libc", @@ -1311,9 +1054,9 @@ 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 1.3.2", "libc", @@ -1325,35 +1068,11 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -[[package]] -name = "libappindicator" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2d3cb96d092b4824cb306c9e544c856a4cb6210c1081945187f7f1924b47e8" -dependencies = [ - "glib", - "gtk", - "gtk-sys", - "libappindicator-sys", - "log", -] - -[[package]] -name = "libappindicator-sys" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1b3b6681973cea8cc3bce7391e6d7d5502720b80a581c9a95c9cbaf592826aa" -dependencies = [ - "gtk-sys", - "libloading 0.7.4", - "once_cell", -] - [[package]] name = "libc" -version = "0.2.142" +version = "0.2.148" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317" +checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" [[package]] name = "libloading" @@ -1375,32 +1094,17 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "link-cplusplus" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" -dependencies = [ - "cc", -] - [[package]] name = "linked-hash-map" version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" -[[package]] -name = "linux-raw-sys" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b085a4f2cde5781fc4b1717f2e86c62f5cda49de7ba99a7c2eae02b61c9064c" - [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" dependencies = [ "autocfg", "scopeguard", @@ -1408,11 +1112,10 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" dependencies = [ - "cfg-if", "serde", ] @@ -1486,45 +1189,27 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" dependencies = [ - "regex-automata", + "regex-automata 0.1.10", ] [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "memoffset" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" -dependencies = [ - "autocfg", -] +checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" [[package]] name = "metal" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de11355d1f6781482d027a3b4d4de7825dcedb197bf573e0596d00008402d060" +version = "0.26.0" +source = "git+https://github.com/gfx-rs/metal-rs/?rev=d24f1a4#d24f1a4ae92470bf87a0c65ecfe78c9299835505" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.0", "block", "core-graphics-types", - "foreign-types", + "foreign-types 0.5.0", "log", "objc", -] - -[[package]] -name = "miniz_oxide" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" -dependencies = [ - "adler", + "paste", ] [[package]] @@ -1555,26 +1240,26 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", "log", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.45.0", + "wasi", + "windows-sys 0.48.0", ] [[package]] name = "naga" -version = "0.12.0" -source = "git+https://github.com/gfx-rs/naga?rev=b99d58ea435090e561377949f428bce2c18451bb#b99d58ea435090e561377949f428bce2c18451bb" +version = "0.13.0" +source = "git+https://github.com/gfx-rs/naga?rev=df8107b7#df8107b78812cc2b1e3d5de35279cedc1f0da3fb" dependencies = [ "bit-set", - "bitflags 1.3.2", + "bitflags 2.4.0", "codespan-reporting", "hexf-parse", - "indexmap", + "indexmap 2.0.0", "log", "num-traits", "rustc-hash", @@ -1644,20 +1329,21 @@ dependencies = [ [[package]] name = "notify" -version = "5.1.0" +version = "6.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58ea850aa68a06e48fdb069c0ec44d0d64c8dbffa49bf3b6f7f0a901fdea1ba9" +checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.0", "crossbeam-channel", "filetime", "fsevent-sys", "inotify", "kqueue", "libc", + "log", "mio", "walkdir", - "windows-sys 0.42.0", + "windows-sys 0.48.0", ] [[package]] @@ -1693,9 +1379,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg", ] @@ -1762,27 +1448,26 @@ dependencies = [ [[package]] name = "object" -version = "0.30.3" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.17.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "openxr" version = "0.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7d5c194407c4fb5d3bf08c34ae57f3ea6cc9d9cfbe0594ce066896c809d9215" +source = "git+https://github.com/artumino/openxrs.git#3818adb6b71ffddd84bf397eaab5b90034de6ea6" dependencies = [ "libc", - "libloading 0.7.4", + "libloading 0.8.0", "ndk-context", "openxr-sys", ] @@ -1790,11 +1475,9 @@ dependencies = [ [[package]] name = "openxr-sys" version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa8f022053ecd7989d86f867b4fb8c3520347612b9d637e217077a0d6b4a6634" +source = "git+https://github.com/artumino/openxrs.git#3818adb6b71ffddd84bf397eaab5b90034de6ea6" dependencies = [ "cmake", - "jni 0.19.0", "libc", "mint", ] @@ -1820,31 +1503,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c10569378a1dacd9f30dbe7ae49e054d2c45dc2f8ee49899903e09c3924e8b6f" -[[package]] -name = "pango" -version = "0.15.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e4045548659aee5313bde6c582b0d83a627b7904dd20dc2d9ef0895d414e4f" -dependencies = [ - "bitflags 1.3.2", - "glib", - "libc", - "once_cell", - "pango-sys", -] - -[[package]] -name = "pango-sys" -version = "0.15.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2a00081cde4661982ed91d80ef437c20eacaf6aa1a5962c0279ae194662c3aa" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - [[package]] name = "parking_lot" version = "0.12.1" @@ -1857,22 +1515,28 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.3.5", "smallvec", - "windows-sys 0.45.0", + "windows-targets 0.48.5", ] +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -1882,21 +1546,21 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "png" -version = "0.17.8" +version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaeebc51f9e7d2c150d3f3bfeb667f2aa985db5ef1e3d212847bdedb488beeaa" +checksum = "dd75bf2d8dd3702b9707cdbc56a5b9ef42cec752eb8b3bafc01234558442aa64" dependencies = [ "bitflags 1.3.2", "crc32fast", "fdeflate", "flate2", - "miniz_oxide 0.7.1", + "miniz_oxide", ] [[package]] @@ -1909,44 +1573,20 @@ dependencies = [ "toml_edit", ] -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - [[package]] name = "proc-macro2" -version = "1.0.56" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" +checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" dependencies = [ "unicode-ident", ] [[package]] name = "profiling" -version = "1.0.8" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "332cd62e95873ea4f41f3dfd6bbbfc5b52aec892d7e8d534197c4720a0bbbab2" +checksum = "f89dff0959d98c9758c88826cc002e2c3d0b9dfac4139711d1f30de442f1139b" dependencies = [ "profiling-procmacros", "tracy-client", @@ -1954,19 +1594,19 @@ dependencies = [ [[package]] name = "profiling-procmacros" -version = "1.0.8" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a10adb8d151bb1280afb8bed41ae5db26be1b056964947133c7525b0bf39c0b0" +checksum = "eb156a45b6b9fe8027497422179fb65afc84d36707a7ca98297bf06bccb8d43f" dependencies = [ "quote", - "syn 1.0.109", + "syn 2.0.37", ] [[package]] name = "quote" -version = "1.0.26" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -1992,13 +1632,25 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "regex" -version = "1.8.1" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" +checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47" dependencies = [ - "regex-syntax 0.7.1", + "aho-corasick", + "memchr", + "regex-automata 0.3.8", + "regex-syntax 0.7.5", ] [[package]] @@ -2010,6 +1662,17 @@ dependencies = [ "regex-syntax 0.6.29", ] +[[package]] +name = "regex-automata" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.7.5", +] + [[package]] name = "regex-syntax" version = "0.6.29" @@ -2018,9 +1681,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.1" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "renderdoc" @@ -2055,40 +1718,17 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - -[[package]] -name = "rustix" -version = "0.37.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f79bef90eb6d984c72722595b5b1348ab39275a5e5123faca6863bf07d75a4e0" -dependencies = [ - "bitflags 1.3.2", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys", - "windows-sys 0.48.0", -] - [[package]] name = "rustversion" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "same-file" @@ -2107,27 +1747,15 @@ 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.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" - -[[package]] -name = "semver" -version = "1.0.17" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.160" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" dependencies = [ "serde_derive", ] @@ -2144,42 +1772,33 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.160" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.37", ] [[package]] name = "serde_json" -version = "1.0.96" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" dependencies = [ "itoa", "ryu", "serde", ] -[[package]] -name = "serde_spanned" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4" -dependencies = [ - "serde", -] - [[package]] name = "serde_yaml" version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b" dependencies = [ - "indexmap", + "indexmap 1.9.3", "ryu", "serde", "yaml-rust", @@ -2196,15 +1815,15 @@ dependencies = [ [[package]] name = "simd-adler32" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "238abfbb77c1915110ad968465608b68e869e0772622c9656714e73e5a1a522f" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] @@ -2220,9 +1839,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.10.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" [[package]] name = "spirv" @@ -2259,9 +1878,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.15" +version = "2.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" +checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" dependencies = [ "proc-macro2", "quote", @@ -2278,52 +1897,33 @@ dependencies = [ "libc", ] -[[package]] -name = "system-deps" -version = "6.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0fe581ad25d11420b873cf9aedaca0419c2b411487b134d4d21065f3d092055" -dependencies = [ - "cfg-expr", - "heck", - "pkg-config", - "toml 0.7.3", - "version-compare", -] - -[[package]] -name = "target-lexicon" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae9980cab1db3fceee2f6c6f643d5d8de2997c58ee8d25fb0cc8a9e9e7348e5" - [[package]] name = "termcolor" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" dependencies = [ "winapi-util", ] [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.37", ] [[package]] @@ -2334,12 +1934,12 @@ checksum = "3bf63baf9f5039dadc247375c29eb13706706cfde997d0330d05aa63a77d8820" [[package]] name = "thread-id" -version = "4.0.0" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fdfe0627923f7411a43ec9ec9c39c3a9b4151be313e0922042581fb6c9b717f" +checksum = "79474f573561cdc4871a0de34a51c92f7f5a56039113fbb5b9c9f96bdb756669" dependencies = [ "libc", - "redox_syscall", + "redox_syscall 0.2.16", "winapi", ] @@ -2368,64 +1968,58 @@ dependencies = [ ] [[package]] -name = "time" -version = "0.1.45" +name = "tobj" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +checksum = "b450e3ba06251ec4fc76917dafeaf55805ffb26dbf7d5500bfb9511ce63a0d1f" dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", + "ahash 0.8.3", ] [[package]] -name = "tobj" -version = "3.2.5" +name = "tokio" +version = "1.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57381207291289bad19de63acd3fbf5948ff99b2868116c367b7224c37d55f90" +checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" dependencies = [ - "ahash 0.8.3", + "backtrace", + "pin-project-lite", + "tokio-macros", ] [[package]] -name = "toml" -version = "0.5.11" +name = "tokio-macros" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ - "serde", + "proc-macro2", + "quote", + "syn 2.0.37", ] [[package]] name = "toml" -version = "0.7.3" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b403acf6f2bb0859c93c7f0d967cb4a75a7ac552100f9322faf64dc047669b21" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", ] [[package]] name = "toml_datetime" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" -dependencies = [ - "serde", -] +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" [[package]] name = "toml_edit" -version = "0.19.8" +version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap", - "serde", - "serde_spanned", + "indexmap 2.0.0", "toml_datetime", "winnow", ] @@ -2444,20 +2038,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.23" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.37", ] [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" dependencies = [ "once_cell", "valuable", @@ -2494,9 +2088,9 @@ dependencies = [ [[package]] name = "tracy-client" -version = "0.15.2" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "434ecabbda9f67eeea1eab44d52f4a20538afa3e2c2770f2efc161142b25b608" +checksum = "546e6c86bca7bd67b86437eade85e98b327de24cdb8429c701a98af755034572" dependencies = [ "loom", "once_cell", @@ -2505,29 +2099,27 @@ dependencies = [ [[package]] name = "tracy-client-sys" -version = "0.21.0" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d99f5fc382239d08b6bf05bb6206a585bfdb988c878f2499081d0f285ef7819" +checksum = "2cb915ea3af048554640d76dd6f1492589a6401a41a30d789b983c1ec280455a" dependencies = [ "cc", ] [[package]] name = "tray-item" -version = "0.7.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0914b62e00e8f51241806cb9f9c4ea6b10c75d94cae02c89278de6f4b98c7d0f" +checksum = "76e87dd77acd3451f2a894d1596cdd73f931972eef8847696a3c8376fce3f760" dependencies = [ "cocoa", "core-graphics", - "gtk", - "libappindicator", "libc", "objc", "objc-foundation", "objc_id", "padlock", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -2541,15 +2133,15 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-width" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" [[package]] name = "unicode-xid" @@ -2578,12 +2170,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" -[[package]] -name = "version-compare" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" - [[package]] name = "version_check" version = "0.9.4" @@ -2592,16 +2178,17 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "vr-screen-cap" -version = "0.4.0" +version = "0.4.0-dev8" dependencies = [ "anyhow", "ash", "bytemuck", + "captrs", "cgmath", "clap", "dhat", "image", - "jni 0.21.1", + "jni", "log", "log-panics", "log4rs", @@ -2620,26 +2207,21 @@ dependencies = [ "tray-item", "wgpu", "wgpu-hal", - "windows 0.48.0", + "win_desktop_duplication", + "windows 0.51.1", "winres", ] [[package]] name = "walkdir" -version = "2.3.3" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" dependencies = [ "same-file", "winapi-util", ] -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -2648,9 +2230,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2658,24 +2240,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.37", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.34" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" dependencies = [ "cfg-if", "js-sys", @@ -2685,9 +2267,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2695,28 +2277,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.37", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "web-sys" -version = "0.3.61" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" dependencies = [ "js-sys", "wasm-bindgen", @@ -2724,8 +2306,8 @@ dependencies = [ [[package]] name = "wgpu" -version = "0.16.0" -source = "git+https://github.com/artumino/wgpu.git?branch=feature/multiview_relaxed_validation#5b80c9e2bc73cd3e62445b420e22311aa74c2d66" +version = "0.17.0" +source = "git+https://github.com/artumino/wgpu.git?branch=fix/multiview_validation#f3929bba77daed346bfdbd080f7fdac19cc1e4da" dependencies = [ "arrayvec", "cfg-if", @@ -2747,12 +2329,12 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "0.16.0" -source = "git+https://github.com/artumino/wgpu.git?branch=feature/multiview_relaxed_validation#5b80c9e2bc73cd3e62445b420e22311aa74c2d66" +version = "0.17.0" +source = "git+https://github.com/artumino/wgpu.git?branch=fix/multiview_validation#f3929bba77daed346bfdbd080f7fdac19cc1e4da" dependencies = [ "arrayvec", "bit-vec", - "bitflags 2.1.0", + "bitflags 2.4.0", "codespan-reporting", "log", "naga", @@ -2769,18 +2351,17 @@ dependencies = [ [[package]] name = "wgpu-hal" -version = "0.16.0" -source = "git+https://github.com/artumino/wgpu.git?branch=feature/multiview_relaxed_validation#5b80c9e2bc73cd3e62445b420e22311aa74c2d66" +version = "0.17.0" +source = "git+https://github.com/artumino/wgpu.git?branch=fix/multiview_validation#f3929bba77daed346bfdbd080f7fdac19cc1e4da" dependencies = [ "android_system_properties", "arrayvec", "ash", "bit-set", - "bitflags 2.1.0", + "bitflags 2.4.0", "block", "core-graphics-types", "d3d12", - "foreign-types", "glow", "gpu-alloc", "gpu-allocator", @@ -2789,7 +2370,7 @@ dependencies = [ "js-sys", "khronos-egl", "libc", - "libloading 0.8.0", + "libloading 0.7.4", "log", "metal", "naga", @@ -2810,10 +2391,10 @@ dependencies = [ [[package]] name = "wgpu-types" -version = "0.16.0" -source = "git+https://github.com/artumino/wgpu.git?branch=feature/multiview_relaxed_validation#5b80c9e2bc73cd3e62445b420e22311aa74c2d66" +version = "0.17.0" +source = "git+https://github.com/artumino/wgpu.git?branch=fix/multiview_validation#f3929bba77daed346bfdbd080f7fdac19cc1e4da" dependencies = [ - "bitflags 2.1.0", + "bitflags 2.4.0", "js-sys", "web-sys", ] @@ -2824,6 +2405,17 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" +[[package]] +name = "win_desktop_duplication" +version = "0.12.0" +source = "git+https://github.com/artumino/win_desktop_duplication.git?branch=dev#e684fadcb1ab3ed918dd0bcff1cd80c9dec2d689" +dependencies = [ + "futures", + "log", + "tokio", + "windows 0.51.1", +] + [[package]] name = "winapi" version = "0.3.9" @@ -2842,9 +2434,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ "winapi", ] @@ -2870,22 +2462,26 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-targets 0.48.0", + "windows-targets 0.48.5", ] [[package]] -name = "windows-sys" -version = "0.42.0" +name = "windows" +version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" dependencies = [ - "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", + "windows-core", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-core" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +dependencies = [ + "windows-targets 0.48.5", ] [[package]] @@ -2903,7 +2499,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.0", + "windows-targets 0.48.5", ] [[package]] @@ -2923,17 +2519,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "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]] @@ -2944,9 +2540,9 @@ checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_msvc" @@ -2956,9 +2552,9 @@ checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_i686_gnu" @@ -2968,9 +2564,9 @@ checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_msvc" @@ -2980,9 +2576,9 @@ checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_x86_64_gnu" @@ -2992,9 +2588,9 @@ checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnullvm" @@ -3004,9 +2600,9 @@ checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_msvc" @@ -3016,15 +2612,15 @@ checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winnow" -version = "0.4.1" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28" +checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" dependencies = [ "memchr", ] @@ -3035,7 +2631,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b68db261ef59e9e52806f688020631e987592bd83619edccda9c47d42cde4f6c" dependencies = [ - "toml 0.5.11", + "toml", ] [[package]] @@ -3047,6 +2643,26 @@ dependencies = [ "winapi", ] +[[package]] +name = "x11" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "x11cap" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16ccedf556cb1f784d462dd8f24a7804f766d57c0051439d3e4052465263c399" +dependencies = [ + "libc", + "x11", +] + [[package]] name = "yaml-rust" version = "0.4.5" diff --git a/Cargo.toml b/Cargo.toml index bfcbb17..e0bb195 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "vr-screen-cap" -version = "0.4.0" +version = "0.4.0-dev8" edition = "2021" build = "build.rs" authors = ["Jacopo Libe "] @@ -15,32 +15,32 @@ crate-type = ["lib", "cdylib"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -wgpu = { git = "https://github.com/artumino/wgpu.git", branch = "feature/multiview_relaxed_validation" } -wgpu-hal = { git = "https://github.com/artumino/wgpu.git", branch = "feature/multiview_relaxed_validation", features = ["vulkan"] } -ash = "0.37.2" +wgpu = { version = "0.17.0", git = "https://github.com/artumino/wgpu.git", branch = "fix/multiview_validation" } +wgpu-hal = { version = "0.17.0", git = "https://github.com/artumino/wgpu.git", branch = "fix/multiview_validation", features = ["vulkan"] } +ash = "0.37.3" mint = "0.5.9" cgmath = { version = "0.18.0", features=["mint"] } -bytemuck = { version = "1.13.1", features = [ "derive" ] } +bytemuck = { version = "1.14.0", features = [ "derive" ] } log4rs = "1.2.0" -log = "0.4.17" +log = "0.4.20" log-panics = { version = "2.1.0", features=["with-backtrace"] } -clap = { version = "4.2.2", features=["derive"] } +clap = { version = "4.4.2", features=["derive"] } thread-priority = "0.13.1" -serde = "1.0.160" -serde_json = "1.0.96" -notify = "5.1.0" +serde = "1.0.188" +serde_json = "1.0.105" +notify = "6.1.1" image = { version = "0.24", default-features = false, features = ["png", "jpeg"] } dhat = { version = "0.3.2", optional = true } renderdoc = { version = "0.11.0", optional = true } -profiling = { version = "1.0.8", optional = true, features = ["profile-with-tracy"] } -tracy-client = { version = "0.15.2", optional = true } -anyhow = "1.0.70" -tobj = "3.2.5" +profiling = { version = "1.0.10", optional = true, features = ["profile-with-tracy"] } +tracy-client = { version = "0.16.1", optional = true } +anyhow = "1.0.75" +tobj = "4.0.0" # PLATFORM DEPENDENT -[target.'cfg(not(target_os = "android"))'.dependencies] -tray-item = "0.7.1" -windows = { version = "0.48.0", features = [ +[target.'cfg(not(any(target_os = "android", target_os = "linux")))'.dependencies] +tray-item = "0.8.0" +windows = { version = "0.51.1", features = [ "Win32_System_Memory", "Win32_Security", "Win32_Foundation", @@ -51,10 +51,12 @@ windows = { version = "0.48.0", features = [ "Win32_Graphics_Dxgi", "Win32_System_Threading" ]} -openxr = { version = "0.17.1", features = [ "static", "mint" ] } +captrs = "0.3.1" +win_desktop_duplication = { git = "https://github.com/artumino/win_desktop_duplication.git", branch = "dev" } +openxr = { version = "0.17.1", features = [ "static", "mint" ], git = "https://github.com/artumino/openxrs.git" } [target.'cfg(target_os = "android")'.dependencies] -openxr = { version = "0.17.1", features = [ "loaded", "mint" ] } +openxr = { version = "0.17.1", features = [ "loaded", "mint" ], git = "https://github.com/artumino/openxrs.git" } jni = "0.21.1" ndk = "0.7" ndk-glue = "0.7" @@ -69,6 +71,7 @@ default = ["renderdoc"] dhat-heap = ["dep:dhat"] renderdoc = ["dep:renderdoc"] profiling = ["dep:profiling", "dep:tracy-client"] +dist = [] # ANDROID [package.metadata.android] @@ -129,3 +132,6 @@ keystore_password = "test1234" [package.metadata.android.signing.release] path = "keys/artum-dev.keystore" keystore_password = "test1234" + +[profile.release] +lto = true diff --git a/README.md b/README.md index 4f842c7..4af85b4 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,8 @@ vr-screen-cap.exe [OPTIONS] --flip-y=false --distance=20.0 --scale=10.0 - --ambient=false + --ambient=true + --no-input=false --config-file= ``` Where every distance is in meters. The effects of horizontal and vertical curvature are summed together, with a curvature of 1.0 the center of the screen will be bent inwards of about half its size. @@ -61,14 +62,14 @@ A json configuration file can be provided and it will be watched for changes, th ### Windows The release version published here were compiled with the following configuration: ``` -cargo build --release --no-default-features +cargo build --release --no-default-features --features dist ``` ### Android Targets Standalone is still in experimental phase: 1. Install *cargo-apk* `cargo install cargo-apk` 2. Add android targets to your rust installation `rustup target add aarch64-linux-android` -3. Build through `cargo apk build --no-default-features` +3. Build through `cargo apk build --no-default-features --features dist` ## WMR Users Disclaimer diff --git a/src/config.rs b/src/config.rs index 650d18d..c3ed047 100644 --- a/src/config.rs +++ b/src/config.rs @@ -4,6 +4,8 @@ use clap::Parser; use notify::{RecommendedWatcher, RecursiveMode, Watcher}; use serde::{Deserialize, Serialize}; +use crate::loaders::StereoMode; + #[repr(C)] #[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] pub struct ScreenParamsUniform { @@ -15,6 +17,8 @@ pub struct ScreenParamsUniform { aspect_ratio: f32, screen_width: u32, ambient_width: u32, + stereo_x: f32, + stereo_y: f32, } #[derive(Parser, Serialize, Deserialize, Debug, Clone)] @@ -41,20 +45,25 @@ pub struct AppConfig { // Screen scaling factor (screen width in meters), default: 40.0, usage: --scale=40.0 #[clap(short, long, value_parser, default_value_t = 40.0)] pub scale: f32, - // Wether ambient light should be used, default: false, usage: --ambient=true - #[clap(short, long, value_parser, default_value_t = false)] + // Wether ambient light should be used, default: false, usage: --ambient=false + #[clap(short, long, value_parser, default_value_t = true)] pub ambient: bool, + // Disables all input from controllers, usefull when using hand-tracking mode from Virtual Desktop: false, usage: --no-input=false + #[clap(short, long, value_parser, default_value_t = false)] + pub no_input: bool, // Configuration file to watch for live changes, usage: --config-file=config.json #[clap(short, long, value_parser)] pub config_file: Option, } impl AppConfig { + #[cfg_attr(feature = "profiling", profiling::function)] pub fn uniform( &self, aspect_ratio: f32, screen_width: u32, ambient_width: u32, + stereo_mode: &StereoMode, ) -> ScreenParamsUniform { ScreenParamsUniform { x_curvature: self.x_curvature, @@ -74,11 +83,20 @@ impl AppConfig { aspect_ratio, screen_width, ambient_width, + stereo_x: match stereo_mode { + StereoMode::Sbs | StereoMode::FullSbs => 1.0, + _ => 0.0, + }, + stereo_y: match stereo_mode { + StereoMode::Tab | StereoMode::FullTab => 1.0, + _ => 0.0, + }, } } } impl Default for AppConfig { + #[cfg_attr(feature = "profiling", profiling::function)] fn default() -> Self { Self { x_curvature: 0.4, @@ -89,7 +107,8 @@ impl Default for AppConfig { distance: 20.0, scale: 40.0, config_file: None, - ambient: false, + no_input: false, + ambient: true, } } } @@ -135,6 +154,7 @@ pub struct ConfigContext { } impl ConfigContext { + #[cfg_attr(feature = "profiling", profiling::function)] pub fn try_setup() -> anyhow::Result> { let config = AppConfig::parse(); if let Some(config_file_path) = config.config_file { @@ -158,6 +178,7 @@ impl ConfigContext { Ok(None) } + #[cfg_attr(feature = "profiling", profiling::function)] pub fn update_config(&mut self) -> anyhow::Result<()> { if let Some(config_file_path) = self.config_file.clone() { let params = serde_json::from_reader(std::io::BufReader::new(std::fs::File::open( diff --git a/src/conversions.rs b/src/conversions.rs index 1470ab4..0bf5b45 100644 --- a/src/conversions.rs +++ b/src/conversions.rs @@ -1,9 +1,11 @@ -use ash::vk; +use ash::vk::{self, Format}; use wgpu::{Device, TextureDescriptor, TextureFormat}; use wgpu_hal::api::Vulkan; -#[cfg(target_os = "windows")] use windows::Win32::Graphics::Dxgi::Common::*; +use crate::{engine::formats::InternalColorFormat, macros::auto_map}; + +#[cfg_attr(feature = "profiling", profiling::function)] pub fn vulkan_image_to_texture( device: &Device, image: vk::Image, @@ -21,200 +23,249 @@ pub fn vulkan_image_to_texture( unsafe { device.create_texture_from_hal::(texture, &tex_desc) } } -#[cfg(target_os = "windows")] -pub fn unmap_texture_format(format: DXGI_FORMAT) -> TextureFormat { - match format { - DXGI_FORMAT_R8_UNORM => TextureFormat::R8Unorm, - DXGI_FORMAT_R8_SNORM => TextureFormat::R8Snorm, - DXGI_FORMAT_R8_UINT => TextureFormat::R8Uint, - DXGI_FORMAT_R8_SINT => TextureFormat::R8Sint, - DXGI_FORMAT_R16_UINT => TextureFormat::R16Uint, - DXGI_FORMAT_R16_SINT => TextureFormat::R16Sint, - DXGI_FORMAT_R16_UNORM => TextureFormat::R16Unorm, - DXGI_FORMAT_R16_SNORM => TextureFormat::R16Snorm, - DXGI_FORMAT_R16_FLOAT => TextureFormat::R16Float, - DXGI_FORMAT_R8G8_UNORM => TextureFormat::Rg8Unorm, - DXGI_FORMAT_R8G8_SNORM => TextureFormat::Rg8Snorm, - DXGI_FORMAT_R8G8_UINT => TextureFormat::Rg8Uint, - DXGI_FORMAT_R8G8_SINT => TextureFormat::Rg8Sint, - DXGI_FORMAT_R16G16_UNORM => TextureFormat::Rg16Unorm, - DXGI_FORMAT_R16G16_SNORM => TextureFormat::Rg16Snorm, - DXGI_FORMAT_R32_UINT => TextureFormat::R32Uint, - DXGI_FORMAT_R32_SINT => TextureFormat::R32Sint, - DXGI_FORMAT_R32_FLOAT => TextureFormat::R32Float, - DXGI_FORMAT_R16G16_UINT => TextureFormat::Rg16Uint, - DXGI_FORMAT_R16G16_SINT => TextureFormat::Rg16Sint, - DXGI_FORMAT_R16G16_FLOAT => TextureFormat::Rg16Float, - DXGI_FORMAT_R8G8B8A8_TYPELESS => TextureFormat::Rgba8Unorm, - DXGI_FORMAT_R8G8B8A8_UNORM => TextureFormat::Rgba8Unorm, - DXGI_FORMAT_R8G8B8A8_UNORM_SRGB => TextureFormat::Rgba8UnormSrgb, - DXGI_FORMAT_B8G8R8A8_UNORM_SRGB => TextureFormat::Bgra8UnormSrgb, - DXGI_FORMAT_R8G8B8A8_SNORM => TextureFormat::Rgba8Snorm, - DXGI_FORMAT_B8G8R8A8_UNORM => TextureFormat::Bgra8Unorm, - DXGI_FORMAT_R8G8B8A8_UINT => TextureFormat::Rgba8Uint, - DXGI_FORMAT_R8G8B8A8_SINT => TextureFormat::Rgba8Sint, - DXGI_FORMAT_R10G10B10A2_UNORM => TextureFormat::Rgb10a2Unorm, - DXGI_FORMAT_R11G11B10_FLOAT => TextureFormat::Rg11b10Float, - DXGI_FORMAT_R32G32_UINT => TextureFormat::Rg32Uint, - DXGI_FORMAT_R32G32_SINT => TextureFormat::Rg32Sint, - DXGI_FORMAT_R32G32_FLOAT => TextureFormat::Rg32Float, - DXGI_FORMAT_R16G16B16A16_UINT => TextureFormat::Rgba16Uint, - DXGI_FORMAT_R16G16B16A16_SINT => TextureFormat::Rgba16Sint, - DXGI_FORMAT_R16G16B16A16_UNORM => TextureFormat::Rgba16Unorm, - DXGI_FORMAT_R16G16B16A16_SNORM => TextureFormat::Rgba16Snorm, - DXGI_FORMAT_R16G16B16A16_FLOAT => TextureFormat::Rgba16Float, - DXGI_FORMAT_R32G32B32A32_UINT => TextureFormat::Rgba32Uint, - DXGI_FORMAT_R32G32B32A32_SINT => TextureFormat::Rgba32Sint, - DXGI_FORMAT_R32G32B32A32_FLOAT => TextureFormat::Rgba32Float, - DXGI_FORMAT_D32_FLOAT => TextureFormat::Depth32Float, - DXGI_FORMAT_D32_FLOAT_S8X24_UINT => TextureFormat::Depth32FloatStencil8, - DXGI_FORMAT_D24_UNORM_S8_UINT => TextureFormat::Depth24PlusStencil8, - DXGI_FORMAT_R9G9B9E5_SHAREDEXP => TextureFormat::Rgb9e5Ufloat, - DXGI_FORMAT_BC1_UNORM => TextureFormat::Bc1RgbaUnorm, - DXGI_FORMAT_BC1_UNORM_SRGB => TextureFormat::Bc1RgbaUnormSrgb, - DXGI_FORMAT_BC2_UNORM => TextureFormat::Bc2RgbaUnorm, - DXGI_FORMAT_BC2_UNORM_SRGB => TextureFormat::Bc2RgbaUnormSrgb, - DXGI_FORMAT_BC3_UNORM => TextureFormat::Bc3RgbaUnorm, - DXGI_FORMAT_BC3_UNORM_SRGB => TextureFormat::Bc3RgbaUnormSrgb, - DXGI_FORMAT_BC4_UNORM => TextureFormat::Bc4RUnorm, - DXGI_FORMAT_BC4_SNORM => TextureFormat::Bc4RSnorm, - DXGI_FORMAT_BC5_UNORM => TextureFormat::Bc5RgUnorm, - DXGI_FORMAT_BC5_SNORM => TextureFormat::Bc5RgSnorm, - DXGI_FORMAT_BC6H_UF16 => TextureFormat::Bc6hRgbUfloat, - DXGI_FORMAT_BC6H_SF16 => TextureFormat::Bc6hRgbFloat, - DXGI_FORMAT_BC7_UNORM => TextureFormat::Bc7RgbaUnorm, - DXGI_FORMAT_BC7_UNORM_SRGB => TextureFormat::Bc7RgbaUnormSrgb, - DXGI_FORMAT_D16_UNORM => TextureFormat::Depth16Unorm, - _ => panic!("Unsupported texture format: {:?}", format), - } +#[cfg_attr(feature = "profiling", profiling::function)] +pub fn build_view_formats( + view_format: Option, +) -> anyhow::Result> { + let view_formats = if let Some(view_format) = view_format { + vec![view_format.try_into()?] + } else { + vec![] + }; + Ok(view_formats) } -pub fn map_texture_format(format: wgpu::TextureFormat) -> vk::Format { - use ash::vk::Format as F; - use wgpu::TextureFormat as Tf; - use wgpu::{AstcBlock, AstcChannel}; - match format { - Tf::R8Unorm => F::R8_UNORM, - Tf::R8Snorm => F::R8_SNORM, - Tf::R8Uint => F::R8_UINT, - Tf::R8Sint => F::R8_SINT, - Tf::R16Uint => F::R16_UINT, - Tf::R16Sint => F::R16_SINT, - Tf::R16Unorm => F::R16_UNORM, - Tf::R16Snorm => F::R16_SNORM, - Tf::R16Float => F::R16_SFLOAT, - Tf::Rg8Unorm => F::R8G8_UNORM, - Tf::Rg8Snorm => F::R8G8_SNORM, - Tf::Rg8Uint => F::R8G8_UINT, - Tf::Rg8Sint => F::R8G8_SINT, - Tf::Rg16Unorm => F::R16G16_UNORM, - Tf::Rg16Snorm => F::R16G16_SNORM, - Tf::R32Uint => F::R32_UINT, - Tf::R32Sint => F::R32_SINT, - Tf::R32Float => F::R32_SFLOAT, - Tf::Rg16Uint => F::R16G16_UINT, - Tf::Rg16Sint => F::R16G16_SINT, - Tf::Rg16Float => F::R16G16_SFLOAT, - Tf::Rgba8Unorm => F::R8G8B8A8_UNORM, - Tf::Rgba8UnormSrgb => F::R8G8B8A8_SRGB, - Tf::Bgra8UnormSrgb => F::B8G8R8A8_SRGB, - Tf::Rgba8Snorm => F::R8G8B8A8_SNORM, - Tf::Bgra8Unorm => F::B8G8R8A8_UNORM, - Tf::Rgba8Uint => F::R8G8B8A8_UINT, - Tf::Rgba8Sint => F::R8G8B8A8_SINT, - Tf::Rgb10a2Unorm => F::A2B10G10R10_UNORM_PACK32, - Tf::Rg11b10Float => F::B10G11R11_UFLOAT_PACK32, - Tf::Rg32Uint => F::R32G32_UINT, - Tf::Rg32Sint => F::R32G32_SINT, - Tf::Rg32Float => F::R32G32_SFLOAT, - Tf::Rgba16Uint => F::R16G16B16A16_UINT, - Tf::Rgba16Sint => F::R16G16B16A16_SINT, - Tf::Rgba16Unorm => F::R16G16B16A16_UNORM, - Tf::Rgba16Snorm => F::R16G16B16A16_SNORM, - Tf::Rgba16Float => F::R16G16B16A16_SFLOAT, - Tf::Rgba32Uint => F::R32G32B32A32_UINT, - Tf::Rgba32Sint => F::R32G32B32A32_SINT, - Tf::Rgba32Float => F::R32G32B32A32_SFLOAT, - Tf::Depth32Float => F::D32_SFLOAT, - Tf::Depth32FloatStencil8 => F::D32_SFLOAT_S8_UINT, - Tf::Depth24Plus => F::D32_SFLOAT, - Tf::Depth24PlusStencil8 => F::D24_UNORM_S8_UINT, - Tf::Depth16Unorm => F::D16_UNORM, - Tf::Rgb9e5Ufloat => F::E5B9G9R9_UFLOAT_PACK32, - Tf::Bc1RgbaUnorm => F::BC1_RGBA_UNORM_BLOCK, - Tf::Bc1RgbaUnormSrgb => F::BC1_RGBA_SRGB_BLOCK, - Tf::Bc2RgbaUnorm => F::BC2_UNORM_BLOCK, - Tf::Bc2RgbaUnormSrgb => F::BC2_SRGB_BLOCK, - Tf::Bc3RgbaUnorm => F::BC3_UNORM_BLOCK, - Tf::Bc3RgbaUnormSrgb => F::BC3_SRGB_BLOCK, - Tf::Bc4RUnorm => F::BC4_UNORM_BLOCK, - Tf::Bc4RSnorm => F::BC4_SNORM_BLOCK, - Tf::Bc5RgUnorm => F::BC5_UNORM_BLOCK, - Tf::Bc5RgSnorm => F::BC5_SNORM_BLOCK, - Tf::Bc6hRgbUfloat => F::BC6H_UFLOAT_BLOCK, - Tf::Bc6hRgbFloat => F::BC6H_SFLOAT_BLOCK, - Tf::Bc7RgbaUnorm => F::BC7_UNORM_BLOCK, - Tf::Bc7RgbaUnormSrgb => F::BC7_SRGB_BLOCK, - Tf::Etc2Rgb8Unorm => F::ETC2_R8G8B8_UNORM_BLOCK, - Tf::Etc2Rgb8UnormSrgb => F::ETC2_R8G8B8_SRGB_BLOCK, - Tf::Etc2Rgb8A1Unorm => F::ETC2_R8G8B8A1_UNORM_BLOCK, - Tf::Etc2Rgb8A1UnormSrgb => F::ETC2_R8G8B8A1_SRGB_BLOCK, - Tf::Etc2Rgba8Unorm => F::ETC2_R8G8B8A8_UNORM_BLOCK, - Tf::Etc2Rgba8UnormSrgb => F::ETC2_R8G8B8A8_SRGB_BLOCK, - Tf::EacR11Unorm => F::EAC_R11_UNORM_BLOCK, - Tf::EacR11Snorm => F::EAC_R11_SNORM_BLOCK, - Tf::EacRg11Unorm => F::EAC_R11G11_UNORM_BLOCK, - Tf::EacRg11Snorm => F::EAC_R11G11_SNORM_BLOCK, - Tf::Astc { block, channel } => match channel { - AstcChannel::Unorm => match block { - AstcBlock::B4x4 => F::ASTC_4X4_UNORM_BLOCK, - AstcBlock::B5x4 => F::ASTC_5X4_UNORM_BLOCK, - AstcBlock::B5x5 => F::ASTC_5X5_UNORM_BLOCK, - AstcBlock::B6x5 => F::ASTC_6X5_UNORM_BLOCK, - AstcBlock::B6x6 => F::ASTC_6X6_UNORM_BLOCK, - AstcBlock::B8x5 => F::ASTC_8X5_UNORM_BLOCK, - AstcBlock::B8x6 => F::ASTC_8X6_UNORM_BLOCK, - AstcBlock::B8x8 => F::ASTC_8X8_UNORM_BLOCK, - AstcBlock::B10x5 => F::ASTC_10X5_UNORM_BLOCK, - AstcBlock::B10x6 => F::ASTC_10X6_UNORM_BLOCK, - AstcBlock::B10x8 => F::ASTC_10X8_UNORM_BLOCK, - AstcBlock::B10x10 => F::ASTC_10X10_UNORM_BLOCK, - AstcBlock::B12x10 => F::ASTC_12X10_UNORM_BLOCK, - AstcBlock::B12x12 => F::ASTC_12X12_UNORM_BLOCK, - }, - AstcChannel::UnormSrgb => match block { - AstcBlock::B4x4 => F::ASTC_4X4_SRGB_BLOCK, - AstcBlock::B5x4 => F::ASTC_5X4_SRGB_BLOCK, - AstcBlock::B5x5 => F::ASTC_5X5_SRGB_BLOCK, - AstcBlock::B6x5 => F::ASTC_6X5_SRGB_BLOCK, - AstcBlock::B6x6 => F::ASTC_6X6_SRGB_BLOCK, - AstcBlock::B8x5 => F::ASTC_8X5_SRGB_BLOCK, - AstcBlock::B8x6 => F::ASTC_8X6_SRGB_BLOCK, - AstcBlock::B8x8 => F::ASTC_8X8_SRGB_BLOCK, - AstcBlock::B10x5 => F::ASTC_10X5_SRGB_BLOCK, - AstcBlock::B10x6 => F::ASTC_10X6_SRGB_BLOCK, - AstcBlock::B10x8 => F::ASTC_10X8_SRGB_BLOCK, - AstcBlock::B10x10 => F::ASTC_10X10_SRGB_BLOCK, - AstcBlock::B12x10 => F::ASTC_12X10_SRGB_BLOCK, - AstcBlock::B12x12 => F::ASTC_12X12_SRGB_BLOCK, - }, - AstcChannel::Hdr => match block { - AstcBlock::B4x4 => F::ASTC_4X4_SFLOAT_BLOCK_EXT, - AstcBlock::B5x4 => F::ASTC_5X4_SFLOAT_BLOCK_EXT, - AstcBlock::B5x5 => F::ASTC_5X5_SFLOAT_BLOCK_EXT, - AstcBlock::B6x5 => F::ASTC_6X5_SFLOAT_BLOCK_EXT, - AstcBlock::B6x6 => F::ASTC_6X6_SFLOAT_BLOCK_EXT, - AstcBlock::B8x5 => F::ASTC_8X5_SFLOAT_BLOCK_EXT, - AstcBlock::B8x6 => F::ASTC_8X6_SFLOAT_BLOCK_EXT, - AstcBlock::B8x8 => F::ASTC_8X8_SFLOAT_BLOCK_EXT, - AstcBlock::B10x5 => F::ASTC_10X5_SFLOAT_BLOCK_EXT, - AstcBlock::B10x6 => F::ASTC_10X6_SFLOAT_BLOCK_EXT, - AstcBlock::B10x8 => F::ASTC_10X8_SFLOAT_BLOCK_EXT, - AstcBlock::B10x10 => F::ASTC_10X10_SFLOAT_BLOCK_EXT, - AstcBlock::B12x10 => F::ASTC_12X10_SFLOAT_BLOCK_EXT, - AstcBlock::B12x12 => F::ASTC_12X12_SFLOAT_BLOCK_EXT, - }, - }, - Tf::Stencil8 => F::S8_UINT, +// Color Format Mappings +auto_map!(TextureFormat InternalColorFormat { + (TextureFormat::R8Unorm, InternalColorFormat::R8Unorm), + (TextureFormat::R8Snorm, InternalColorFormat::R8Snorm), + (TextureFormat::R8Uint, InternalColorFormat::R8Uint), + (TextureFormat::R8Sint, InternalColorFormat::R8Sint), + (TextureFormat::R16Uint, InternalColorFormat::R16Uint), + (TextureFormat::R16Sint, InternalColorFormat::R16Sint), + (TextureFormat::R16Unorm, InternalColorFormat::R16Unorm), + (TextureFormat::R16Snorm, InternalColorFormat::R16Snorm), + (TextureFormat::R16Float, InternalColorFormat::R16Float), + (TextureFormat::Rg8Unorm, InternalColorFormat::Rg8Unorm), + (TextureFormat::Rg8Snorm, InternalColorFormat::Rg8Snorm), + (TextureFormat::Rg8Uint, InternalColorFormat::Rg8Uint), + (TextureFormat::Rg8Sint, InternalColorFormat::Rg8Sint), + (TextureFormat::Rg16Unorm, InternalColorFormat::Rg16Unorm), + (TextureFormat::Rg16Snorm, InternalColorFormat::Rg16Snorm), + (TextureFormat::R32Uint, InternalColorFormat::R32Uint), + (TextureFormat::R32Sint, InternalColorFormat::R32Sint), + (TextureFormat::R32Float, InternalColorFormat::R32Float), + (TextureFormat::Rg16Uint, InternalColorFormat::Rg16Uint), + (TextureFormat::Rg16Sint, InternalColorFormat::Rg16Sint), + (TextureFormat::Rg16Float, InternalColorFormat::Rg16Float), + (TextureFormat::Rgba8Unorm, InternalColorFormat::Rgba8Unorm), + (TextureFormat::Rgba8Unorm, InternalColorFormat::Rgba8Unorm), + (TextureFormat::Rgba8UnormSrgb, InternalColorFormat::Rgba8UnormSrgb), + (TextureFormat::Bgra8UnormSrgb, InternalColorFormat::Bgra8UnormSrgb), + (TextureFormat::Rgba8Snorm, InternalColorFormat::Rgba8Snorm), + (TextureFormat::Bgra8Unorm, InternalColorFormat::Bgra8Unorm), + (TextureFormat::Rgba8Uint, InternalColorFormat::Rgba8Uint), + (TextureFormat::Rgba8Sint, InternalColorFormat::Rgba8Sint), + (TextureFormat::Rgb10a2Unorm, InternalColorFormat::Rgb10a2Unorm), + (TextureFormat::Rg11b10Float, InternalColorFormat::Rg11b10Float), + (TextureFormat::Rg32Uint, InternalColorFormat::Rg32Uint), + (TextureFormat::Rg32Sint, InternalColorFormat::Rg32Sint), + (TextureFormat::Rg32Float, InternalColorFormat::Rg32Float), + (TextureFormat::Rgba16Uint, InternalColorFormat::Rgba16Uint), + (TextureFormat::Rgba16Sint, InternalColorFormat::Rgba16Sint), + (TextureFormat::Rgba16Unorm, InternalColorFormat::Rgba16Unorm), + (TextureFormat::Rgba16Snorm, InternalColorFormat::Rgba16Snorm), + (TextureFormat::Rgba16Float, InternalColorFormat::Rgba16Float), + (TextureFormat::Rgba32Uint, InternalColorFormat::Rgba32Uint), + (TextureFormat::Rgba32Sint, InternalColorFormat::Rgba32Sint), + (TextureFormat::Rgba32Float, InternalColorFormat::Rgba32Float), + (TextureFormat::Depth32Float, InternalColorFormat::Depth32Float), + (TextureFormat::Depth32FloatStencil8, InternalColorFormat::Depth32FloatStencil8), + (TextureFormat::Depth24PlusStencil8, InternalColorFormat::Depth24PlusStencil8), + (TextureFormat::Rgb9e5Ufloat, InternalColorFormat::Rgb9e5Ufloat), + (TextureFormat::Bc1RgbaUnorm, InternalColorFormat::Bc1RgbaUnorm), + (TextureFormat::Bc1RgbaUnormSrgb, InternalColorFormat::Bc1RgbaUnormSrgb), + (TextureFormat::Bc2RgbaUnorm, InternalColorFormat::Bc2RgbaUnorm), + (TextureFormat::Bc2RgbaUnormSrgb, InternalColorFormat::Bc2RgbaUnormSrgb), + (TextureFormat::Bc3RgbaUnorm, InternalColorFormat::Bc3RgbaUnorm), + (TextureFormat::Bc3RgbaUnormSrgb, InternalColorFormat::Bc3RgbaUnormSrgb), + (TextureFormat::Bc4RUnorm, InternalColorFormat::Bc4RUnorm), + (TextureFormat::Bc4RSnorm, InternalColorFormat::Bc4RSnorm), + (TextureFormat::Bc5RgUnorm, InternalColorFormat::Bc5RgUnorm), + (TextureFormat::Bc5RgSnorm, InternalColorFormat::Bc5RgSnorm), + (TextureFormat::Bc6hRgbUfloat, InternalColorFormat::Bc6hRgbUfloat), + (TextureFormat::Bc6hRgbFloat, InternalColorFormat::Bc6hRgbFloat), + (TextureFormat::Bc7RgbaUnorm, InternalColorFormat::Bc7RgbaUnorm), + (TextureFormat::Bc7RgbaUnormSrgb, InternalColorFormat::Bc7RgbaUnormSrgb), + (TextureFormat::Depth16Unorm, InternalColorFormat::Depth16Unorm) +}); + +auto_map!(InternalColorFormat Format { + (InternalColorFormat::R8Unorm, ash::vk::Format::R8_UNORM), + (InternalColorFormat::R8Snorm, ash::vk::Format::R8_SNORM), + (InternalColorFormat::R8Uint, ash::vk::Format::R8_UINT), + (InternalColorFormat::R8Sint, ash::vk::Format::R8_SINT), + (InternalColorFormat::R16Uint, ash::vk::Format::R16_UINT), + (InternalColorFormat::R16Sint, ash::vk::Format::R16_SINT), + (InternalColorFormat::R16Unorm, ash::vk::Format::R16_UNORM), + (InternalColorFormat::R16Snorm, ash::vk::Format::R16_SNORM), + (InternalColorFormat::R16Float, ash::vk::Format::R16_SFLOAT), + (InternalColorFormat::Rg8Unorm, ash::vk::Format::R8G8_UNORM), + (InternalColorFormat::Rg8Snorm, ash::vk::Format::R8G8_SNORM), + (InternalColorFormat::Rg8Uint, ash::vk::Format::R8G8_UINT), + (InternalColorFormat::Rg8Sint, ash::vk::Format::R8G8_SINT), + (InternalColorFormat::Rg16Unorm, ash::vk::Format::R16G16_UNORM), + (InternalColorFormat::Rg16Snorm, ash::vk::Format::R16G16_SNORM), + (InternalColorFormat::R32Uint, ash::vk::Format::R32_UINT), + (InternalColorFormat::R32Sint, ash::vk::Format::R32_SINT), + (InternalColorFormat::R32Float, ash::vk::Format::R32_SFLOAT), + (InternalColorFormat::Rg16Uint, ash::vk::Format::R16G16_UINT), + (InternalColorFormat::Rg16Sint, ash::vk::Format::R16G16_SINT), + (InternalColorFormat::Rg16Float, ash::vk::Format::R16G16_SFLOAT), + (InternalColorFormat::Rgba8Unorm, ash::vk::Format::R8G8B8A8_UNORM), + (InternalColorFormat::Rgba8UnormSrgb, ash::vk::Format::R8G8B8A8_SRGB), + (InternalColorFormat::Bgra8UnormSrgb, ash::vk::Format::B8G8R8A8_SRGB), + (InternalColorFormat::Rgba8Snorm, ash::vk::Format::R8G8B8A8_SNORM), + (InternalColorFormat::Bgra8Unorm, ash::vk::Format::B8G8R8A8_UNORM), + (InternalColorFormat::Rgba8Uint, ash::vk::Format::R8G8B8A8_UINT), + (InternalColorFormat::Rgba8Sint, ash::vk::Format::R8G8B8A8_SINT), + (InternalColorFormat::Rgb10a2Unorm, ash::vk::Format::A2B10G10R10_UNORM_PACK32), + (InternalColorFormat::Rg11b10Float, ash::vk::Format::B10G11R11_UFLOAT_PACK32), + (InternalColorFormat::Rg32Uint, ash::vk::Format::R32G32_UINT), + (InternalColorFormat::Rg32Sint, ash::vk::Format::R32G32_SINT), + (InternalColorFormat::Rg32Float, ash::vk::Format::R32G32_SFLOAT), + (InternalColorFormat::Rgba16Uint, ash::vk::Format::R16G16B16A16_UINT), + (InternalColorFormat::Rgba16Sint, ash::vk::Format::R16G16B16A16_SINT), + (InternalColorFormat::Rgba16Unorm, ash::vk::Format::R16G16B16A16_UNORM), + (InternalColorFormat::Rgba16Snorm, ash::vk::Format::R16G16B16A16_SNORM), + (InternalColorFormat::Rgba16Float, ash::vk::Format::R16G16B16A16_SFLOAT), + (InternalColorFormat::Rgba32Uint, ash::vk::Format::R32G32B32A32_UINT), + (InternalColorFormat::Rgba32Sint, ash::vk::Format::R32G32B32A32_SINT), + (InternalColorFormat::Rgba32Float, ash::vk::Format::R32G32B32A32_SFLOAT), + (InternalColorFormat::Depth32Float, ash::vk::Format::D32_SFLOAT), + (InternalColorFormat::Depth32FloatStencil8, ash::vk::Format::D32_SFLOAT_S8_UINT), + (InternalColorFormat::Depth24Plus, ash::vk::Format::D32_SFLOAT), + (InternalColorFormat::Depth24PlusStencil8, ash::vk::Format::D24_UNORM_S8_UINT), + (InternalColorFormat::Depth16Unorm, ash::vk::Format::D16_UNORM), + (InternalColorFormat::Rgb9e5Ufloat, ash::vk::Format::E5B9G9R9_UFLOAT_PACK32), + (InternalColorFormat::Bc1RgbaUnorm, ash::vk::Format::BC1_RGBA_UNORM_BLOCK), + (InternalColorFormat::Bc1RgbaUnormSrgb, ash::vk::Format::BC1_RGBA_SRGB_BLOCK), + (InternalColorFormat::Bc2RgbaUnorm, ash::vk::Format::BC2_UNORM_BLOCK), + (InternalColorFormat::Bc2RgbaUnormSrgb, ash::vk::Format::BC2_SRGB_BLOCK), + (InternalColorFormat::Bc3RgbaUnorm, ash::vk::Format::BC3_UNORM_BLOCK), + (InternalColorFormat::Bc3RgbaUnormSrgb, ash::vk::Format::BC3_SRGB_BLOCK), + (InternalColorFormat::Bc4RUnorm, ash::vk::Format::BC4_UNORM_BLOCK), + (InternalColorFormat::Bc4RSnorm, ash::vk::Format::BC4_SNORM_BLOCK), + (InternalColorFormat::Bc5RgUnorm, ash::vk::Format::BC5_UNORM_BLOCK), + (InternalColorFormat::Bc5RgSnorm, ash::vk::Format::BC5_SNORM_BLOCK), + (InternalColorFormat::Bc6hRgbUfloat, ash::vk::Format::BC6H_UFLOAT_BLOCK), + (InternalColorFormat::Bc6hRgbFloat, ash::vk::Format::BC6H_SFLOAT_BLOCK), + (InternalColorFormat::Bc7RgbaUnorm, ash::vk::Format::BC7_UNORM_BLOCK), + (InternalColorFormat::Bc7RgbaUnormSrgb, ash::vk::Format::BC7_SRGB_BLOCK), + (InternalColorFormat::Etc2Rgb8Unorm, ash::vk::Format::ETC2_R8G8B8_UNORM_BLOCK), + (InternalColorFormat::Etc2Rgb8UnormSrgb, ash::vk::Format::ETC2_R8G8B8_SRGB_BLOCK), + (InternalColorFormat::Etc2Rgb8A1Unorm, ash::vk::Format::ETC2_R8G8B8A1_UNORM_BLOCK), + (InternalColorFormat::Etc2Rgb8A1UnormSrgb, ash::vk::Format::ETC2_R8G8B8A1_SRGB_BLOCK), + (InternalColorFormat::Etc2Rgba8Unorm, ash::vk::Format::ETC2_R8G8B8A8_UNORM_BLOCK), + (InternalColorFormat::Etc2Rgba8UnormSrgb, ash::vk::Format::ETC2_R8G8B8A8_SRGB_BLOCK), + (InternalColorFormat::EacR11Unorm, ash::vk::Format::EAC_R11_UNORM_BLOCK), + (InternalColorFormat::EacR11Snorm, ash::vk::Format::EAC_R11_SNORM_BLOCK), + (InternalColorFormat::EacRg11Unorm, ash::vk::Format::EAC_R11G11_UNORM_BLOCK), + (InternalColorFormat::EacRg11Snorm, ash::vk::Format::EAC_R11G11_SNORM_BLOCK), + (InternalColorFormat::Stencil8, ash::vk::Format::S8_UINT), + (InternalColorFormat::Abgr8Unorm, ash::vk::Format::A8B8G8R8_UNORM_PACK32) +}); + +#[cfg(target_os = "windows")] +auto_map!(DXGI_FORMAT InternalColorFormat { + (DXGI_FORMAT_R8_UNORM, InternalColorFormat::R8Unorm), + (DXGI_FORMAT_R8_SNORM, InternalColorFormat::R8Snorm), + (DXGI_FORMAT_R8_UINT, InternalColorFormat::R8Uint), + (DXGI_FORMAT_R8_SINT, InternalColorFormat::R8Sint), + (DXGI_FORMAT_R16_UINT, InternalColorFormat::R16Uint), + (DXGI_FORMAT_R16_SINT, InternalColorFormat::R16Sint), + (DXGI_FORMAT_R16_UNORM, InternalColorFormat::R16Unorm), + (DXGI_FORMAT_R16_SNORM, InternalColorFormat::R16Snorm), + (DXGI_FORMAT_R16_FLOAT, InternalColorFormat::R16Float), + (DXGI_FORMAT_R8G8_UNORM, InternalColorFormat::Rg8Unorm), + (DXGI_FORMAT_R8G8_SNORM, InternalColorFormat::Rg8Snorm), + (DXGI_FORMAT_R8G8_UINT, InternalColorFormat::Rg8Uint), + (DXGI_FORMAT_R8G8_SINT, InternalColorFormat::Rg8Sint), + (DXGI_FORMAT_R16G16_UNORM, InternalColorFormat::Rg16Unorm), + (DXGI_FORMAT_R16G16_SNORM, InternalColorFormat::Rg16Snorm), + (DXGI_FORMAT_R32_UINT, InternalColorFormat::R32Uint), + (DXGI_FORMAT_R32_SINT, InternalColorFormat::R32Sint), + (DXGI_FORMAT_R32_FLOAT, InternalColorFormat::R32Float), + (DXGI_FORMAT_R16G16_UINT, InternalColorFormat::Rg16Uint), + (DXGI_FORMAT_R16G16_SINT, InternalColorFormat::Rg16Sint), + (DXGI_FORMAT_R16G16_FLOAT, InternalColorFormat::Rg16Float), + (DXGI_FORMAT_R8G8B8A8_UNORM, InternalColorFormat::Rgba8Unorm), + (DXGI_FORMAT_R8G8B8A8_TYPELESS, InternalColorFormat::Rgba8Unorm), + (DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, InternalColorFormat::Rgba8UnormSrgb), + (DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, InternalColorFormat::Bgra8UnormSrgb), + (DXGI_FORMAT_R8G8B8A8_SNORM, InternalColorFormat::Rgba8Snorm), + (DXGI_FORMAT_B8G8R8A8_UNORM, InternalColorFormat::Bgra8Unorm), + (DXGI_FORMAT_R8G8B8A8_UINT, InternalColorFormat::Rgba8Uint), + (DXGI_FORMAT_R8G8B8A8_SINT, InternalColorFormat::Rgba8Sint), + (DXGI_FORMAT_R10G10B10A2_UNORM, InternalColorFormat::Rgb10a2Unorm), + (DXGI_FORMAT_R11G11B10_FLOAT, InternalColorFormat::Rg11b10Float), + (DXGI_FORMAT_R32G32_UINT, InternalColorFormat::Rg32Uint), + (DXGI_FORMAT_R32G32_SINT, InternalColorFormat::Rg32Sint), + (DXGI_FORMAT_R32G32_FLOAT, InternalColorFormat::Rg32Float), + (DXGI_FORMAT_R16G16B16A16_UINT, InternalColorFormat::Rgba16Uint), + (DXGI_FORMAT_R16G16B16A16_SINT, InternalColorFormat::Rgba16Sint), + (DXGI_FORMAT_R16G16B16A16_UNORM, InternalColorFormat::Rgba16Unorm), + (DXGI_FORMAT_R16G16B16A16_SNORM, InternalColorFormat::Rgba16Snorm), + (DXGI_FORMAT_R16G16B16A16_FLOAT, InternalColorFormat::Rgba16Float), + (DXGI_FORMAT_R32G32B32A32_UINT, InternalColorFormat::Rgba32Uint), + (DXGI_FORMAT_R32G32B32A32_SINT, InternalColorFormat::Rgba32Sint), + (DXGI_FORMAT_R32G32B32A32_FLOAT, InternalColorFormat::Rgba32Float), + (DXGI_FORMAT_D32_FLOAT, InternalColorFormat::Depth32Float), + (DXGI_FORMAT_D32_FLOAT_S8X24_UINT, InternalColorFormat::Depth32FloatStencil8), + (DXGI_FORMAT_D24_UNORM_S8_UINT, InternalColorFormat::Depth24PlusStencil8), + (DXGI_FORMAT_R9G9B9E5_SHAREDEXP, InternalColorFormat::Rgb9e5Ufloat), + (DXGI_FORMAT_BC1_UNORM, InternalColorFormat::Bc1RgbaUnorm), + (DXGI_FORMAT_BC1_UNORM_SRGB, InternalColorFormat::Bc1RgbaUnormSrgb), + (DXGI_FORMAT_BC2_UNORM, InternalColorFormat::Bc2RgbaUnorm), + (DXGI_FORMAT_BC2_UNORM_SRGB, InternalColorFormat::Bc2RgbaUnormSrgb), + (DXGI_FORMAT_BC3_UNORM, InternalColorFormat::Bc3RgbaUnorm), + (DXGI_FORMAT_BC3_UNORM_SRGB, InternalColorFormat::Bc3RgbaUnormSrgb), + (DXGI_FORMAT_BC4_UNORM, InternalColorFormat::Bc4RUnorm), + (DXGI_FORMAT_BC4_SNORM, InternalColorFormat::Bc4RSnorm), + (DXGI_FORMAT_BC5_UNORM, InternalColorFormat::Bc5RgUnorm), + (DXGI_FORMAT_BC5_SNORM, InternalColorFormat::Bc5RgSnorm), + (DXGI_FORMAT_BC6H_UF16, InternalColorFormat::Bc6hRgbUfloat), + (DXGI_FORMAT_BC6H_SF16, InternalColorFormat::Bc6hRgbFloat), + (DXGI_FORMAT_BC7_UNORM, InternalColorFormat::Bc7RgbaUnorm), + (DXGI_FORMAT_BC7_UNORM_SRGB, InternalColorFormat::Bc7RgbaUnormSrgb), + (DXGI_FORMAT_D16_UNORM, InternalColorFormat::Depth16Unorm), + (DXGI_FORMAT_AYUV, InternalColorFormat::Ayuv), + (DXGI_FORMAT_NV12, InternalColorFormat::Nv12), + (DXGI_FORMAT_Y410, InternalColorFormat::Y410), + (DXGI_FORMAT_P010, InternalColorFormat::P010) +}); + +#[cfg(test)] +mod test { + use wgpu::TextureFormat; + use windows::Win32::Graphics::Dxgi::Common::{DXGI_FORMAT, DXGI_FORMAT_R8G8B8A8_UNORM}; + + use crate::engine::formats::InternalColorFormat; + + #[test] + fn dxgi_conversion_test() -> anyhow::Result<()> { + let internal_format = InternalColorFormat::Rgba8Unorm; + let dxgi_equivalent = DXGI_FORMAT_R8G8B8A8_UNORM; + + let mapped_dxgi: DXGI_FORMAT = internal_format.try_into()?; + let mapped_internal: InternalColorFormat = dxgi_equivalent.try_into()?; + + assert_eq!(mapped_dxgi, dxgi_equivalent); + assert_eq!(mapped_internal, internal_format); + + let error: Result = InternalColorFormat::Y410.try_into(); + assert!(error.is_err()); + + Ok(()) } } diff --git a/src/engine.rs b/src/engine.rs index e86443e..21d9048 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -2,23 +2,28 @@ use ash::vk; pub mod camera; pub mod entity; +pub mod formats; pub mod geometry; pub mod input; pub mod jitter; pub mod screen; +pub mod space; +pub mod swapchain; pub mod texture; pub mod vr; pub const TARGET_VULKAN_VERSION: u32 = vk::make_api_version(0, 1, 1, 0); //TODO: Actually modularize engine... - +// Be mindful of dropping order pub struct WgpuContext { + debug_utils: Option, + debug_messenger: Option, pub vk_entry: ash::Entry, pub vk_instance_ptr: u64, pub vk_phys_device_ptr: u64, pub vk_device_ptr: u64, - pub queue_index: u32, + pub family_queue_index: u32, pub instance: wgpu::Instance, pub device: wgpu::Device, pub physical_device: wgpu::Adapter, diff --git a/src/engine/camera.rs b/src/engine/camera.rs index 5637cd6..1bfac2b 100644 --- a/src/engine/camera.rs +++ b/src/engine/camera.rs @@ -23,6 +23,7 @@ impl Default for Camera { } impl Camera { + #[cfg_attr(feature = "profiling", profiling::function)] pub fn update_projection_from_tangents(&mut self, fov: Fovf) { let tan_right = fov.angle_right.tan(); let tan_left = fov.angle_left.tan(); @@ -52,10 +53,12 @@ impl Camera { } #[allow(unused)] + #[cfg_attr(feature = "profiling", profiling::function)] pub fn update_projection(&mut self, fov: Rad, aspect_ratio: f32) { self.projection = cgmath::perspective(fov, aspect_ratio, self.near, self.far) } + #[cfg_attr(feature = "profiling", profiling::function)] pub fn build_view_projection_matrix(&self) -> anyhow::Result> { Ok(self.projection * self @@ -77,12 +80,14 @@ pub struct CameraUniform { } impl CameraUniform { + #[cfg_attr(feature = "profiling", profiling::function)] pub fn new() -> Self { Self { view_proj: cgmath::Matrix4::identity().into(), } } + #[cfg_attr(feature = "profiling", profiling::function)] pub fn update_view_proj(&mut self, camera: &Camera) -> anyhow::Result<()> { self.view_proj = camera.build_view_projection_matrix()?.into(); Ok(()) diff --git a/src/engine/entity.rs b/src/engine/entity.rs index f8caf60..4425232 100644 --- a/src/engine/entity.rs +++ b/src/engine/entity.rs @@ -12,6 +12,7 @@ pub struct Entity { } impl Default for Entity { + #[cfg_attr(feature = "profiling", profiling::function)] fn default() -> Self { //TODO registry Self::new( @@ -24,6 +25,7 @@ impl Default for Entity { } impl Entity { + #[cfg_attr(feature = "profiling", profiling::function)] pub fn new( id: usize, position: Vector3, @@ -45,6 +47,7 @@ impl Entity { entity } + #[cfg_attr(feature = "profiling", profiling::function)] pub fn update_matrices(&mut self, registry: &[Entity]) { self.local_matrix = Matrix4::from_translation(self.position) * Matrix4::from(self.rotation) @@ -59,6 +62,7 @@ impl Entity { self.uniform_matrix.model_matrix = self.world_matrix.into(); } + #[cfg_attr(feature = "profiling", profiling::function)] pub fn uniform(&self) -> ModelUniform { self.uniform_matrix } @@ -75,6 +79,7 @@ pub struct ModelUniform { } impl ModelUniform { + #[cfg_attr(feature = "profiling", profiling::function)] pub fn new() -> Self { Self { model_matrix: cgmath::Matrix4::identity().into(), diff --git a/src/engine/formats.rs b/src/engine/formats.rs new file mode 100644 index 0000000..f95b6a2 --- /dev/null +++ b/src/engine/formats.rs @@ -0,0 +1,97 @@ +#[derive(Debug, PartialEq, Clone, Copy, Default)] +pub enum InternalColorFormat { + R8Unorm, + R8Snorm, + R8Uint, + R8Sint, + R16Uint, + R16Sint, + R16Unorm, + R16Snorm, + R16Float, + Rg8Unorm, + Rg8Snorm, + Rg8Uint, + Rg8Sint, + R32Uint, + R32Sint, + R32Float, + Rg16Uint, + Rg16Sint, + Rg16Unorm, + Rg16Snorm, + Rg16Float, + Rgba8Unorm, + #[default] + Rgba8UnormSrgb, + Rgba8Snorm, + Rgba8Uint, + Rgba8Sint, + Bgra8Unorm, + Bgra8UnormSrgb, + Abgr8Unorm, + Rgb9e5Ufloat, + Rgb10a2Unorm, + Rg11b10Float, + Rg32Uint, + Rg32Sint, + Rg32Float, + Rgba16Uint, + Rgba16Sint, + Rgba16Unorm, + Rgba16Snorm, + Rgba16Float, + Rgba32Uint, + Rgba32Sint, + Rgba32Float, + Stencil8, + Depth16Unorm, + Depth24Plus, + Depth24PlusStencil8, + Depth32Float, + Depth32FloatStencil8, + Bc1RgbaUnorm, + Bc1RgbaUnormSrgb, + Bc2RgbaUnorm, + Bc2RgbaUnormSrgb, + Bc3RgbaUnorm, + Bc3RgbaUnormSrgb, + Bc4RUnorm, + Bc4RSnorm, + Bc5RgUnorm, + Bc5RgSnorm, + Bc6hRgbUfloat, + Bc6hRgbFloat, + Bc7RgbaUnorm, + Bc7RgbaUnormSrgb, + Etc2Rgb8Unorm, + Etc2Rgb8UnormSrgb, + Etc2Rgb8A1Unorm, + Etc2Rgb8A1UnormSrgb, + Etc2Rgba8Unorm, + Etc2Rgba8UnormSrgb, + EacR11Unorm, + EacR11Snorm, + EacRg11Unorm, + EacRg11Snorm, + Ayuv, + Nv12, + Y410, + P010, +} + +impl InternalColorFormat { + pub const fn to_norm(self) -> InternalColorFormat { + match self { + InternalColorFormat::Etc2Rgba8UnormSrgb => InternalColorFormat::Etc2Rgba8Unorm, + InternalColorFormat::Etc2Rgb8UnormSrgb => InternalColorFormat::Etc2Rgb8Unorm, + InternalColorFormat::Bc1RgbaUnormSrgb => InternalColorFormat::Bc1RgbaUnorm, + InternalColorFormat::Bc2RgbaUnormSrgb => InternalColorFormat::Bc2RgbaUnorm, + InternalColorFormat::Bc3RgbaUnormSrgb => InternalColorFormat::Bc3RgbaUnorm, + InternalColorFormat::Bc7RgbaUnormSrgb => InternalColorFormat::Bc7RgbaUnorm, + InternalColorFormat::Bgra8UnormSrgb => InternalColorFormat::Bgra8Unorm, + InternalColorFormat::Rgba8UnormSrgb => InternalColorFormat::Rgba8Unorm, + _ => self, + } + } +} diff --git a/src/engine/geometry.rs b/src/engine/geometry.rs index 6480836..73bca32 100644 --- a/src/engine/geometry.rs +++ b/src/engine/geometry.rs @@ -20,13 +20,14 @@ impl ModelVertex { } impl Vertex for ModelVertex { + #[cfg_attr(feature = "profiling", profiling::function)] fn desc<'a>() -> wgpu::VertexBufferLayout<'a> { use std::mem; wgpu::VertexBufferLayout { array_stride: mem::size_of::() as wgpu::BufferAddress, step_mode: wgpu::VertexStepMode::Vertex, - attributes: &Self::ATTRIBS, + attributes: Self::ATTRIBS, } } } @@ -38,6 +39,7 @@ pub struct Mesh { } impl Mesh { + #[cfg_attr(feature = "profiling", profiling::function)] fn get_buffers( device: &wgpu::Device, vertices: &[ModelVertex], @@ -70,6 +72,7 @@ impl Mesh { } //TODO: Actually use entity + mesh and world matrix in shader + #[cfg_attr(feature = "profiling", profiling::function)] pub fn get_plane_rectangle( device: &wgpu::Device, rows: u32, @@ -80,7 +83,7 @@ impl Mesh { ) -> Mesh { let mut vertices = vec![]; let x_increment = 2.0 / (columns as f32); - let y_increment = 2.0 / (columns as f32); + let y_increment = 2.0 / (rows as f32); for row in 0..rows { for column in 0..columns { vertices.push(ModelVertex { @@ -90,8 +93,8 @@ impl Mesh { distance, ], tex_coords: [ - (column as f32) / (columns as f32), - 1.0 - (row as f32) / (rows as f32), + (column as f32) / ((columns - 1) as f32), + 1.0 - (row as f32) / ((rows - 1) as f32), ], }); } @@ -109,7 +112,7 @@ impl Mesh { } } - let (vertex_buffer, index_buffer) = Mesh::get_buffers(&device, &vertices, &indices); + let (vertex_buffer, index_buffer) = Mesh::get_buffers(device, &vertices, &indices); Mesh { //FIXME: Handle flipping properly num_indeces: indices.len() as u32, @@ -118,6 +121,7 @@ impl Mesh { } } + #[cfg_attr(feature = "profiling", profiling::function)] pub fn from_asset( device: &wgpu::Device, asset: &'static [u8], @@ -148,12 +152,11 @@ impl Mesh { tex_coords: [mesh.texcoords[i * 2], mesh.texcoords[i * 2 + 1]], }) .collect::>(); - let indices = mesh.indices.clone(); - let (vertex_buffer, index_buffer) = Mesh::get_buffers(&device, &vertices, &indices); + let (vertex_buffer, index_buffer) = Mesh::get_buffers(device, &vertices, &mesh.indices); Mesh { - num_indeces: indices.len() as u32, - vertex_buffer: vertex_buffer, - index_buffer: index_buffer, + num_indeces: mesh.indices.len() as u32, + vertex_buffer, + index_buffer, } } } diff --git a/src/engine/input.rs b/src/engine/input.rs index 7ab1e1d..ab38c26 100644 --- a/src/engine/input.rs +++ b/src/engine/input.rs @@ -7,8 +7,8 @@ pub struct InputContext { pub default: ActionSet, pub default_right_hand: Action, pub default_left_hand: Action, - pub default_right_hand_space: Option, - pub default_left_hand_space: Option, + default_right_hand_space: Option, + default_left_hand_space: Option, pub input_state: Option, } @@ -19,13 +19,19 @@ pub struct InputState { } impl InputContext { + #[cfg_attr(feature = "profiling", profiling::function)] pub fn init(xr_instance: &Instance) -> anyhow::Result { let default_set = xr_instance.create_action_set("default", "Default controller actions", 0)?; - let right_hand = default_set.create_action("right_hand", "Right Hand Controller", &[])?; + let right_hand = default_set.create_action::( + "right_hand", + "Right Hand Controller", + &[], + )?; - let left_hand = default_set.create_action("left_hand", "Left Hand Controller", &[])?; + let left_hand = + default_set.create_action::("left_hand", "Left Hand Controller", &[])?; xr_instance.suggest_interaction_profile_bindings( xr_instance.string_to_path("/interaction_profiles/khr/simple_controller")?, @@ -51,25 +57,15 @@ impl InputContext { }) } + #[cfg_attr(feature = "profiling", profiling::function)] pub fn attach_to_session(&mut self, xr_session: &Session) -> anyhow::Result<()> { xr_session.attach_action_sets(&[&self.default])?; - self.default_right_hand_space = Some(self.default_right_hand.create_space( - xr_session.clone(), - Path::NULL, - Posef::IDENTITY, - )?); - - self.default_left_hand_space = Some(self.default_left_hand.create_space( - xr_session.clone(), - Path::NULL, - Posef::IDENTITY, - )?); - Ok(()) } - pub fn process_inputs( + #[cfg_attr(feature = "profiling", profiling::function)] + pub fn process_inputs( &mut self, xr_session: &Session, xr_frame_state: &FrameState, @@ -78,17 +74,22 @@ impl InputContext { ) -> anyhow::Result<()> { xr_session.sync_actions(&[(&self.default).into()])?; - let right_location = self - .default_right_hand_space - .as_ref() - .context("Right hand space not initialized")? - .locate(xr_view_space, xr_frame_state.predicted_display_time)?; + let left_space = Self::get_or_create_action_space( + xr_session, + &mut self.default_left_hand_space, + &self.default_left_hand, + )?; + let right_space = Self::get_or_create_action_space( + xr_session, + &mut self.default_right_hand_space, + &self.default_right_hand, + )?; + + let right_location = + right_space.locate(xr_view_space, xr_frame_state.predicted_display_time)?; - let left_location = self - .default_left_hand_space - .as_ref() - .context("Left hand space not initialized")? - .locate(xr_view_space, xr_frame_state.predicted_display_time)?; + let left_location = + left_space.locate(xr_view_space, xr_frame_state.predicted_display_time)?; let right_hand_distance = (right_location.pose.position.x.powi(2) + right_location.pose.position.y.powi(2) @@ -127,6 +128,20 @@ impl InputContext { Ok(()) } + #[cfg_attr(feature = "profiling", profiling::function)] + fn get_or_create_action_space<'a, T: openxr::Graphics>( + session: &Session, + space: &'a mut Option, + action: &Action, + ) -> anyhow::Result<&'a Space> { + if space.is_none() { + *space = Some(action.create_space(session.clone(), Path::NULL, Posef::IDENTITY)?); + } + + space.as_ref().context("Cannot get or create action space") + } + + #[cfg_attr(feature = "profiling", profiling::function)] fn compute_input_state( input_state: &Option, right_active: bool, @@ -164,4 +179,10 @@ impl InputContext { count_change, } } + + #[cfg_attr(feature = "profiling", profiling::function)] + pub fn reset_space(&mut self) { + self.default_left_hand_space = None; + self.default_right_hand_space = None; + } } diff --git a/src/engine/jitter.rs b/src/engine/jitter.rs index a64757f..ffafb68 100644 --- a/src/engine/jitter.rs +++ b/src/engine/jitter.rs @@ -1,3 +1,4 @@ +#[cfg_attr(feature = "profiling", profiling::function)] pub fn halton(i: u32, b: u32) -> f32 { let mut f = 1.0; let mut r = 0.0; @@ -10,6 +11,7 @@ pub fn halton(i: u32, b: u32) -> f32 { r } +#[cfg_attr(feature = "profiling", profiling::function)] pub fn get_jitter(jitter_index: u32, resolution: &[f32; 2]) -> [f32; 2] { let jitter = [ 2.0 * halton(jitter_index, 2) - 1.0, diff --git a/src/engine/screen.rs b/src/engine/screen.rs index 2456a40..7686693 100644 --- a/src/engine/screen.rs +++ b/src/engine/screen.rs @@ -12,6 +12,7 @@ pub struct Screen { } impl Screen { + #[cfg_attr(feature = "profiling", profiling::function)] pub fn new( device: &wgpu::Device, distance: f32, @@ -48,12 +49,14 @@ impl Screen { } } + #[cfg_attr(feature = "profiling", profiling::function)] pub fn change_aspect_ratio(&mut self, aspect_ratio: f32) { self.aspect_ratio = aspect_ratio; self.entity.scale.y = self.scale / (2.0 * self.aspect_ratio); self.entity.update_matrices(&[]); } + #[cfg_attr(feature = "profiling", profiling::function)] pub fn change_scale(&mut self, scale: f32) { self.scale = scale; self.entity.scale.x = self.scale / 2.0; @@ -62,11 +65,13 @@ impl Screen { self.entity.update_matrices(&[]); } + #[cfg_attr(feature = "profiling", profiling::function)] pub fn change_distance(&mut self, distance: f32) { self.entity.position.z = distance; self.entity.update_matrices(&[]); } + #[cfg_attr(feature = "profiling", profiling::function)] pub fn change_ambient_mode(&mut self, ambient_mode: bool) { self.ambient_enabled = ambient_mode; } diff --git a/src/engine/space.rs b/src/engine/space.rs new file mode 100644 index 0000000..cd1b659 --- /dev/null +++ b/src/engine/space.rs @@ -0,0 +1,78 @@ +use cgmath::Rotation3; + +pub struct AppSpace { + reference_space: openxr::Space, + view_space: openxr::Space, + override_space: Option, +} + +impl AppSpace { + pub fn new(session: &openxr::Session) -> anyhow::Result { + Ok(Self { + reference_space: session.create_reference_space( + openxr::ReferenceSpaceType::LOCAL, + openxr::Posef::IDENTITY, + )?, + view_space: session.create_reference_space( + openxr::ReferenceSpaceType::VIEW, + openxr::Posef::IDENTITY, + )?, + override_space: None, + }) + } + + pub fn space(&self) -> &openxr::Space { + match self.override_space { + Some(ref space) => space, + None => &self.reference_space, + } + } + + pub fn view_space(&self) -> &openxr::Space { + &self.view_space + } + + pub fn reference_space(&self) -> &openxr::Space { + &self.reference_space + } + + pub fn recenter( + &mut self, + session: &openxr::Session, + last_predicted_frame_time: openxr::Time, + horizon_locked: bool, + delay: i64, + ) -> anyhow::Result<()> { + let mut view_location_pose = self + .view_space + .locate( + &self.reference_space, + openxr::Time::from_nanos(last_predicted_frame_time.as_nanos() - delay), + )? + .pose; + let quaternion = + cgmath::Quaternion::from(mint::Quaternion::from(view_location_pose.orientation)); + let forward = cgmath::Vector3::new(0.0, 0.0, 1.0); + let look_dir = quaternion * forward; + let yaw = cgmath::Rad(look_dir.x.atan2(look_dir.z)); + let clean_orientation = if horizon_locked { + cgmath::Quaternion::from_angle_y(yaw) + } else { + let padj = (look_dir.x * look_dir.x + look_dir.z * look_dir.z).sqrt(); + let pitch = -cgmath::Rad(look_dir.y.atan2(padj)); + cgmath::Quaternion::from_angle_y(yaw) * cgmath::Quaternion::from_angle_x(pitch) + }; + view_location_pose.orientation = openxr::Quaternionf { + x: clean_orientation.v.x, + y: clean_orientation.v.y, + z: clean_orientation.v.z, + w: clean_orientation.s, + }; + + self.override_space = Some( + session + .create_reference_space(openxr::ReferenceSpaceType::LOCAL, view_location_pose)?, + ); + Ok(()) + } +} diff --git a/src/engine/swapchain.rs b/src/engine/swapchain.rs new file mode 100644 index 0000000..1a8290d --- /dev/null +++ b/src/engine/swapchain.rs @@ -0,0 +1,122 @@ +use ash::vk::{self, Handle}; +use openxr::SwapchainUsageFlags; +use wgpu::{Device, Extent3d}; + +use super::{ + formats::InternalColorFormat, + texture::{Texture2D, Unbound}, +}; + +pub struct Swapchain { + internal_swapchain: openxr::Swapchain, + textures: Vec>, +} + +pub struct SwapchainCreationInfo { + pub resolution: vk::Extent2D, + pub format: InternalColorFormat, + pub view_format: Option, + pub usage_flags: openxr::SwapchainUsageFlags, + pub view_count: u32, +} + +impl Swapchain { + #[cfg_attr(feature = "profiling", profiling::function)] + pub fn new( + label: &'static str, + xr_session: &openxr::Session, + device: &Device, + creation_info: SwapchainCreationInfo, + ) -> anyhow::Result { + let SwapchainCreationInfo { + resolution, + format, + view_format, + usage_flags, + view_count, + } = creation_info; + + let vk_format: vk::Format = format.try_into()?; + let xr_swapchain = xr_session.create_swapchain(&openxr::SwapchainCreateInfo { + create_flags: openxr::SwapchainCreateFlags::EMPTY, + usage_flags, + format: vk_format.as_raw() as _, + sample_count: 1, + width: resolution.width, + height: resolution.height, + face_count: 1, + array_size: view_count, + mip_count: 1, + })?; + let swapcain_textures: Vec<_> = xr_swapchain + .enumerate_images()? + .into_iter() + .map(vk::Image::from_raw) + .enumerate() + .filter_map(|(idx, image)| { + Texture2D::::from_vk_image( + format!("{} {}", label, idx).as_str(), + device, + image, + Extent3d { + width: resolution.width, + height: resolution.height, + depth_or_array_layers: view_count, + }, + format, + view_format, + map_swapchain_usage(usage_flags), + ) + .ok() + }) + .collect(); + Ok(Self { + internal_swapchain: xr_swapchain, + textures: swapcain_textures, + }) + } + + pub fn is_empty(&self) -> bool { + self.textures.is_empty() + } + + pub fn internal(&self) -> &openxr::Swapchain { + &self.internal_swapchain + } + + #[cfg_attr(feature = "profiling", profiling::function)] + pub fn wait_next_image(&mut self) -> Result<&wgpu::TextureView, anyhow::Error> { + let image_index = self.internal_swapchain.acquire_image()?; + self.internal_swapchain + .wait_image(openxr::Duration::INFINITE)?; + Ok(&self.textures[image_index as usize].view) + } + + #[cfg_attr(feature = "profiling", profiling::function)] + pub fn release_image(&mut self) -> Result<(), anyhow::Error> { + self.internal_swapchain.release_image()?; + Ok(()) + } +} + +pub fn map_swapchain_usage(usage: openxr::SwapchainUsageFlags) -> wgpu::TextureUsages { + let mut u = wgpu::TextureUsages::empty(); + u.set( + wgpu::TextureUsages::COPY_SRC, + usage.contains(SwapchainUsageFlags::TRANSFER_SRC), + ); + u.set( + wgpu::TextureUsages::COPY_DST, + usage.contains(SwapchainUsageFlags::TRANSFER_DST), + ); + u.set( + wgpu::TextureUsages::TEXTURE_BINDING, + usage.contains(SwapchainUsageFlags::SAMPLED), + ); + u.set( + wgpu::TextureUsages::RENDER_ATTACHMENT, + usage.contains(SwapchainUsageFlags::COLOR_ATTACHMENT) + || usage.contains(SwapchainUsageFlags::DEPTH_STENCIL_ATTACHMENT), + ); + u +} diff --git a/src/engine/texture.rs b/src/engine/texture.rs index 7fe9f4e..a608d4a 100644 --- a/src/engine/texture.rs +++ b/src/engine/texture.rs @@ -1,8 +1,12 @@ use anyhow::*; +use ash::vk; use image::GenericImageView; -use wgpu::TextureDescriptor; +use wgpu::{Extent3d, TextureDescriptor}; +use wgpu_hal::MemoryFlags; -use super::WgpuContext; +use crate::conversions::{build_view_formats, vulkan_image_to_texture}; + +use super::{formats::InternalColorFormat, WgpuContext}; pub struct Bound; pub struct Unbound; @@ -16,25 +20,35 @@ pub struct Texture2D { } impl Texture2D { + #[cfg_attr(feature = "profiling", profiling::function)] pub fn from_bytes( device: &wgpu::Device, queue: &wgpu::Queue, bytes: &[u8], label: &str, + view_format: Option, ) -> anyhow::Result> { let img = image::load_from_memory(bytes)?; - Ok(Self::from_image(device, queue, &img, Some(label))) + Ok(Self::from_image( + device, + queue, + &img, + Some(label), + view_format, + )?) } + #[cfg_attr(feature = "profiling", profiling::function)] pub fn from_image( device: &wgpu::Device, queue: &wgpu::Queue, img: &image::DynamicImage, label: Option<&str>, - ) -> Texture2D { + view_format: Option, + ) -> anyhow::Result> { let rgba = img.to_rgba8(); let dimensions = img.dimensions(); - + let view_formats = build_view_formats(view_format)?; let size = wgpu::Extent3d { width: dimensions.0, height: dimensions.1, @@ -48,7 +62,7 @@ impl Texture2D { dimension: wgpu::TextureDimension::D2, format: wgpu::TextureFormat::Rgba8UnormSrgb, usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, - view_formats: &[], + view_formats: &view_formats, }); queue.write_texture( @@ -68,49 +82,56 @@ impl Texture2D { ); let (view, sampler) = - Self::get_view_and_sampler(device, &texture, wgpu::FilterMode::Linear); + Self::get_view_and_sampler(device, &texture, wgpu::FilterMode::Linear, view_format); - Texture2D:: { + Ok(Texture2D:: { texture, view, sampler, bind_group: None, state: std::marker::PhantomData, - } + }) } + #[cfg_attr(feature = "profiling", profiling::function)] pub fn as_render_target_with_extent( &self, label: &str, extent: wgpu::Extent3d, - format: wgpu::TextureFormat, + format: InternalColorFormat, + view_format: Option, device: &wgpu::Device, - ) -> Texture2D { + ) -> anyhow::Result> { let desc = &TextureDescriptor { label: Some(label), size: extent, mip_level_count: 1, sample_count: 1, dimension: self.texture.dimension(), - format: format, + format: format.try_into()?, usage: self.texture.usage() | wgpu::TextureUsages::RENDER_ATTACHMENT, - view_formats: &[], + view_formats: &build_view_formats(view_format)?, }; let texture = device.create_texture(desc); let (view, sampler) = - Self::get_view_and_sampler(device, &texture, wgpu::FilterMode::Linear); - Texture2D:: { + Self::get_view_and_sampler(device, &texture, wgpu::FilterMode::Linear, view_format); + Ok(Texture2D:: { texture, view, sampler, bind_group: None, state: std::marker::PhantomData, - } + }) } - pub fn from_wgpu(device: &wgpu::Device, texture: wgpu::Texture) -> Texture2D { + #[cfg_attr(feature = "profiling", profiling::function)] + pub fn from_wgpu( + device: &wgpu::Device, + texture: wgpu::Texture, + view_format: Option, + ) -> Texture2D { let (view, sampler) = - Self::get_view_and_sampler(device, &texture, wgpu::FilterMode::Linear); + Self::get_view_and_sampler(device, &texture, wgpu::FilterMode::Linear, view_format); Texture2D:: { texture, view, @@ -120,13 +141,68 @@ impl Texture2D { } } + #[cfg_attr(feature = "profiling", profiling::function)] + pub fn from_vk_image( + label: &str, + device: &wgpu::Device, + image: vk::Image, + size: Extent3d, + format: InternalColorFormat, + view_format: Option, + usage: wgpu::TextureUsages, + ) -> anyhow::Result> { + let view_formats = build_view_formats(view_format)?; + + let wgpu_tex_desc = wgpu::TextureDescriptor { + label: Some(label), + size, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: format.try_into()?, + view_formats: &view_formats, + usage, + }; + + let hal_usage = map_texture_usage(usage, wgpu_tex_desc.format.into()) + | if wgpu_tex_desc.format.is_depth_stencil_format() { + wgpu_hal::TextureUses::DEPTH_STENCIL_WRITE + } else if wgpu_tex_desc.usage.contains(wgpu::TextureUsages::COPY_DST) { + wgpu_hal::TextureUses::COPY_DST // (set already) + } else { + wgpu_hal::TextureUses::COLOR_TARGET + }; + + let wgpu_hal_tex_desc = wgpu_hal::TextureDescriptor { + label: wgpu_tex_desc.label, + size: wgpu_tex_desc.size, + mip_level_count: wgpu_tex_desc.mip_level_count, + sample_count: wgpu_tex_desc.sample_count, + dimension: wgpu_tex_desc.dimension, + format: wgpu_tex_desc.format, + view_formats: view_formats.clone(), + usage: hal_usage, + memory_flags: MemoryFlags::empty(), + }; + + // Create a WGPU image view for this image + let wgpu_texture = vulkan_image_to_texture(device, image, wgpu_tex_desc, wgpu_hal_tex_desc); + + Ok(Self::from_wgpu(device, wgpu_texture, view_format)) + } + + #[cfg_attr(feature = "profiling", profiling::function)] fn get_view_and_sampler( device: &wgpu::Device, texture: &wgpu::Texture, filter_mode: wgpu::FilterMode, + view_format: Option, ) -> (wgpu::TextureView, wgpu::Sampler) { ( - texture.create_view(&wgpu::TextureViewDescriptor::default()), + texture.create_view(&wgpu::TextureViewDescriptor { + format: view_format.and_then(|f| f.try_into().ok()), + ..Default::default() + }), device.create_sampler(&wgpu::SamplerDescriptor { address_mode_u: wgpu::AddressMode::ClampToEdge, address_mode_v: wgpu::AddressMode::ClampToEdge, @@ -141,6 +217,7 @@ impl Texture2D { } impl Texture2D { + #[cfg_attr(feature = "profiling", profiling::function)] pub fn bind_to_context( self, wgpu_context: &WgpuContext, @@ -205,3 +282,36 @@ impl RoundRobinTextureBuffer wgpu_hal::TextureUses { + let mut u = wgpu_hal::TextureUses::empty(); + u.set( + wgpu_hal::TextureUses::COPY_SRC, + usage.contains(wgpu::TextureUsages::COPY_SRC), + ); + u.set( + wgpu_hal::TextureUses::COPY_DST, + usage.contains(wgpu::TextureUsages::COPY_DST), + ); + u.set( + wgpu_hal::TextureUses::RESOURCE, + usage.contains(wgpu::TextureUsages::TEXTURE_BINDING), + ); + u.set( + wgpu_hal::TextureUses::STORAGE_READ | wgpu_hal::TextureUses::STORAGE_READ_WRITE, + usage.contains(wgpu::TextureUsages::STORAGE_BINDING), + ); + let is_color = aspect.contains(wgpu_hal::FormatAspects::COLOR); + u.set( + wgpu_hal::TextureUses::COLOR_TARGET, + usage.contains(wgpu::TextureUsages::RENDER_ATTACHMENT) && is_color, + ); + u.set( + wgpu_hal::TextureUses::DEPTH_STENCIL_READ | wgpu_hal::TextureUses::DEPTH_STENCIL_WRITE, + usage.contains(wgpu::TextureUsages::RENDER_ATTACHMENT) && !is_color, + ); + u +} diff --git a/src/engine/vr.rs b/src/engine/vr.rs index fc595a3..571aaf9 100644 --- a/src/engine/vr.rs +++ b/src/engine/vr.rs @@ -1,15 +1,18 @@ +use std::ffi::c_char; + use anyhow::{bail, Context}; use ash::vk::{self, Handle, QueueGlobalPriorityKHR}; -use hal::MemoryFlags; + use openxr as xr; -use wgpu::{Device, Extent3d}; +use wgpu::Device; use wgpu_hal as hal; +use xr::SystemId; -use crate::conversions::vulkan_image_to_texture; +use crate::engine::swapchain::SwapchainCreationInfo; use super::{ - texture::{Texture2D, Unbound}, - WgpuLoader, WgpuRunner, TARGET_VULKAN_VERSION, + formats::InternalColorFormat, swapchain::Swapchain, WgpuContext, WgpuLoader, WgpuRunner, + TARGET_VULKAN_VERSION, }; pub struct OpenXRContext { @@ -22,19 +25,19 @@ pub struct OpenXRContext { pub const VIEW_TYPE: openxr::ViewConfigurationType = openxr::ViewConfigurationType::PRIMARY_STEREO; pub const VIEW_COUNT: u32 = 2; -pub const SWAPCHAIN_COLOR_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Bgra8Unorm; -pub const VK_SWAPCHAIN_COLOR_FORMAT: vk::Format = vk::Format::B8G8R8A8_SRGB; +pub const SWAPCHAIN_COLOR_FORMAT: InternalColorFormat = InternalColorFormat::Bgra8UnormSrgb; -#[cfg(debug_assertions)] +#[cfg(not(feature = "dist"))] pub fn openxr_layers() -> [&'static str; 0] { [] //TODO: ["VK_LAYER_KHRONOS_validation"] } -#[cfg(not(debug_assertions))] +#[cfg(feature = "dist")] pub fn openxr_layers() -> [&'static str; 0] { [] } +#[cfg_attr(feature = "profiling", profiling::function)] pub fn enable_xr_runtime() -> anyhow::Result { #[cfg(not(target_os = "android"))] let entry = openxr::Entry::linked(); @@ -53,10 +56,22 @@ pub fn enable_xr_runtime() -> anyhow::Result { #[cfg(target_os = "android")] { + assert!(available_extensions.khr_android_create_instance); enabled_extensions.khr_android_create_instance = true; } log::info!("Enabled extensions: {:?}", enabled_extensions); + #[cfg(not(feature = "dist"))] + { + for layer in entry.enumerate_layers()? { + log::info!( + "[OPENXR] Found layer: {} {:?}", + layer.layer_name, + layer.spec_version + ); + } + } + log::info!("Loading OpenXR Runtime..."); let instance = entry.create_instance( &openxr::ApplicationInfo { @@ -77,7 +92,18 @@ pub fn enable_xr_runtime() -> anyhow::Result { ); // Request a form factor from the device (HMD, Handheld, etc.) - let system = instance.system(openxr::FormFactor::HEAD_MOUNTED_DISPLAY)?; + let system = loop { + match instance.system(openxr::FormFactor::HEAD_MOUNTED_DISPLAY) { + Ok(system) => break system, + Err(err) => { + if err != openxr::sys::Result::ERROR_FORM_FACTOR_UNAVAILABLE { + return Err(err.into()); + } + } + } + log::warn!("No HMD detected, trying again in 1 second"); + std::thread::sleep(std::time::Duration::from_secs(1)); + }; // Check what blend mode is valid for this device (opaque vs transparent displays). We'll just // take the first one available! @@ -98,14 +124,88 @@ pub fn enable_xr_runtime() -> anyhow::Result { }) } -#[cfg(not(debug_assertions))] +#[cfg(feature = "dist")] fn instance_flags() -> hal::InstanceFlags { hal::InstanceFlags::empty() } -#[cfg(debug_assertions)] +#[cfg(not(feature = "dist"))] fn instance_flags() -> hal::InstanceFlags { - hal::InstanceFlags::empty() | hal::InstanceFlags::VALIDATION | hal::InstanceFlags::DEBUG + hal::InstanceFlags::VALIDATION | hal::InstanceFlags::DEBUG +} + +#[cfg(not(feature = "dist"))] +fn vulkan_layers() -> Vec<*const c_char> { + use std::ffi::CStr; + + let layer_names = [CStr::from_bytes_with_nul(b"VK_LAYER_KHRONOS_validation\0").unwrap()]; + layer_names + .iter() + .map(|raw_name| raw_name.as_ptr()) + .collect() +} + +#[cfg(not(feature = "dist"))] +fn populate_debug_messenger_create_info() -> Option { + use std::ptr; + + use crate::utils::validation; + + Some(vk::DebugUtilsMessengerCreateInfoEXT { + s_type: vk::StructureType::DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, + p_next: ptr::null(), + flags: vk::DebugUtilsMessengerCreateFlagsEXT::empty(), + message_severity: vk::DebugUtilsMessageSeverityFlagsEXT::WARNING | + // vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE | + // vk::DebugUtilsMessageSeverityFlagsEXT::INFO | + vk::DebugUtilsMessageSeverityFlagsEXT::ERROR, + message_type: vk::DebugUtilsMessageTypeFlagsEXT::GENERAL + | vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE + | vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION, + pfn_user_callback: Some(validation::debug_callback), + p_user_data: ptr::null_mut(), + }) +} + +#[cfg(not(feature = "dist"))] +fn setup_debug_utils( + entry: &ash::Entry, + instance: &ash::Instance, +) -> ( + Option, + Option, +) { + let debug_utils_loader = ash::extensions::ext::DebugUtils::new(entry, instance); + let messenger_ci = populate_debug_messenger_create_info().unwrap(); + + let utils_messenger = unsafe { + debug_utils_loader + .create_debug_utils_messenger(&messenger_ci, None) + .expect("Debug Utils Callback") + }; + + (Some(debug_utils_loader), Some(utils_messenger)) +} + +#[cfg(feature = "dist")] +fn vulkan_layers() -> Vec<*const c_char> { + vec![] +} + +#[cfg(feature = "dist")] +fn populate_debug_messenger_create_info() -> Option { + None +} + +#[cfg(feature = "dist")] +fn setup_debug_utils( + _entry: &ash::Entry, + _instance: &ash::Instance, +) -> ( + Option, + Option, +) { + (None, None) } impl WgpuLoader for OpenXRContext { @@ -113,7 +213,7 @@ impl WgpuLoader for OpenXRContext { // OpenXR wants to ensure apps are using the correct graphics card and Vulkan features and // extensions, so the instance and device MUST be set up before Instance::create_session. - let wgpu_limits = wgpu::Limits::downlevel_webgl2_defaults(); + let wgpu_limits = wgpu::Limits::default(); let wgpu_features = wgpu::Features::MULTIVIEW; let vk_target_version = TARGET_VULKAN_VERSION; // Vulkan 1.1 guarantees multiview support @@ -143,7 +243,7 @@ impl WgpuLoader for OpenXRContext { let flags = instance_flags(); - let instance_extensions = ::Instance::required_extensions( + let instance_extensions = ::Instance::desired_extensions( &vk_entry, vk_target_version, flags, @@ -153,9 +253,32 @@ impl WgpuLoader for OpenXRContext { let instance_extensions_ptrs: Vec<_> = instance_extensions.iter().map(|x| x.as_ptr()).collect(); - let create_info = vk::InstanceCreateInfo::builder() + #[cfg(not(feature = "dist"))] + { + for layer in vk_entry.enumerate_instance_layer_properties()? { + log::info!( + "[VULKAN] Found layer: {} {:?}", + String::from_utf8_lossy(unsafe { + &*(layer.layer_name.as_ref() as *const _ as *const [u8]) + }), + layer.spec_version + ); + } + } + + let instance_layers = vulkan_layers(); + + // This create info used to debug issues in vk::createInstance and vk::destroyInstance. + let mut debug_info = populate_debug_messenger_create_info(); + + let mut create_info = vk::InstanceCreateInfo::builder() .application_info(&vk_app_info) - .enabled_extension_names(&instance_extensions_ptrs); + .enabled_extension_names(&instance_extensions_ptrs) + .enabled_layer_names(&instance_layers); + + if let Some(debug_info) = &mut debug_info { + create_info = create_info.push_next(debug_info); + } let vk_instance = unsafe { let vk_instance = self @@ -176,6 +299,8 @@ impl WgpuLoader for OpenXRContext { log::info!("Successfully created Vulkan instance"); + let (debug_utils, debug_messenger) = setup_debug_utils(&vk_entry, &vk_instance); + let vk_physical_device = vk::PhysicalDevice::from_raw(unsafe { self.instance .vulkan_graphics_device(self.system, vk_instance.handle().as_raw() as _)? @@ -217,6 +342,7 @@ impl WgpuLoader for OpenXRContext { vk_instance.clone(), vk_target_version, 0, + None, instance_extensions, flags, false, @@ -229,64 +355,29 @@ impl WgpuLoader for OpenXRContext { log::info!("Created WGPU-HAL instance and adapter"); - //TODO actually check if the extensions are available and avoid using them in the loaders - let mut device_extensions = hal_exposed_adapter - .adapter - .required_device_extensions(wgpu_features); + let device_create_info = VkDeviceCreateInfo { + xr_instance: &self.instance.clone(), + system_id: self.system, + hal_exposed_adapter: &hal_exposed_adapter, + wgpu_features, + queue_family_index, + vk_entry: &vk_entry, + vk_physical_device, + vk_instance: &vk_instance, + }; - #[cfg(target_os = "windows")] - device_extensions.push(ash::extensions::khr::ExternalMemoryWin32::name()); + let mut global_queue_priority = vk::DeviceQueueGlobalPriorityCreateInfoKHR::builder() + .global_priority(QueueGlobalPriorityKHR::HIGH); - log::info!("Requested device extensions: {:?}", device_extensions); + let mut device_creation_result = + create_vk_device(device_create_info, Some(&mut global_queue_priority)); - let family_info = vk::DeviceQueueCreateInfo::builder() - .queue_family_index(queue_family_index) - .queue_priorities(&[1.0]) - .push_next( - &mut vk::DeviceQueueGlobalPriorityCreateInfoKHR::builder() - .global_priority(QueueGlobalPriorityKHR::REALTIME_EXT), - ) - .build(); - - let device_extensions_ptrs = device_extensions - .iter() - .map(|x| x.as_ptr()) - .collect::>(); - - let mut enabled_features = hal_exposed_adapter - .adapter - .physical_device_features(&device_extensions, wgpu_features); - - let device_create_info = enabled_features - .add_to_device_create_builder( - vk::DeviceCreateInfo::builder() - .enabled_extension_names(&device_extensions_ptrs) - .queue_create_infos(&[family_info]) - .push_next(&mut vk::PhysicalDeviceMultiviewFeatures { - multiview: vk::TRUE, - ..Default::default() - }), - ) - .build(); + if device_creation_result.is_err() { + log::warn!("Failed to create Vulkan device with realtime priority, trying without"); + device_creation_result = create_vk_device(device_create_info, None); + } - let vk_device = { - unsafe { - let vk_device = self - .instance - .create_vulkan_device( - self.system, - std::mem::transmute(vk_entry.static_fn().get_instance_proc_addr), - vk_physical_device.as_raw() as _, - &device_create_info as *const _ as *const _, - ) - .context("XR error creating Vulkan device")? - .map_err(vk::Result::from_raw) - .context("Vulkan error creating Vulkan device")?; - - log::info!("Creating ash vulkan device device from native"); - ash::Device::load(vk_instance.fp_v1_0(), vk::Device::from_raw(vk_device as _)) - } - }; + let (device_extensions, family_info, vk_device) = device_creation_result?; let vk_device_ptr = vk_device.handle().as_raw(); log::info!("Successfully created Vulkan device"); @@ -331,15 +422,29 @@ impl WgpuLoader for OpenXRContext { device: wgpu_device, physical_device: wgpu_adapter, queue: wgpu_queue, - queue_index: family_info.queue_family_index, + family_queue_index: family_info.queue_family_index, vk_entry, vk_device_ptr, vk_instance_ptr: vk_instance.handle().as_raw(), vk_phys_device_ptr: vk_physical_device.as_raw(), + debug_messenger, + debug_utils, }) } } +impl Drop for WgpuContext { + fn drop(&mut self) { + if let (Some(debug_messenger), Some(debug_utils_loader)) = + (self.debug_messenger, self.debug_utils.take()) + { + unsafe { + debug_utils_loader.destroy_debug_utils_messenger(debug_messenger, None); + } + } + } +} + impl WgpuRunner for OpenXRContext { fn run(&mut self, _wgpu_context: &super::WgpuContext) { todo!() @@ -347,15 +452,12 @@ impl WgpuRunner for OpenXRContext { } impl OpenXRContext { + #[cfg_attr(feature = "profiling", profiling::function)] pub fn create_swapchain( &self, xr_session: &openxr::Session, device: &Device, - ) -> anyhow::Result<( - openxr::Swapchain, - vk::Extent2D, - Vec>, - )> { + ) -> anyhow::Result<(Swapchain, vk::Extent2D)> { log::info!("Creating OpenXR swapchain"); // Fetch the views we need to render to (the eye screens on the HMD) @@ -370,66 +472,109 @@ impl OpenXRContext { width: views[0].recommended_image_rect_width, height: views[0].recommended_image_rect_height, }; - let xr_swapchain = xr_session.create_swapchain(&openxr::SwapchainCreateInfo { - create_flags: openxr::SwapchainCreateFlags::EMPTY, - usage_flags: openxr::SwapchainUsageFlags::COLOR_ATTACHMENT - | openxr::SwapchainUsageFlags::SAMPLED, - format: VK_SWAPCHAIN_COLOR_FORMAT.as_raw() as _, - sample_count: 1, - width: resolution.width, - height: resolution.height, - face_count: 1, - array_size: VIEW_COUNT, - mip_count: 1, - })?; - - // Create image views for the swapchain - let swapcain_textures: Vec<_> = xr_swapchain - .enumerate_images()? - .into_iter() - .map(|image| { - let wgpu_tex_desc = wgpu::TextureDescriptor { - label: Some("Swapchain Target"), - size: Extent3d { - width: resolution.width, - height: resolution.height, - depth_or_array_layers: VIEW_COUNT, - }, - mip_level_count: 1, - sample_count: 1, - dimension: wgpu::TextureDimension::D2, - format: SWAPCHAIN_COLOR_FORMAT, - view_formats: &[], - usage: wgpu::TextureUsages::RENDER_ATTACHMENT - | wgpu::TextureUsages::TEXTURE_BINDING - | wgpu::TextureUsages::COPY_DST, - }; - - let wgpu_hal_tex_desc = wgpu_hal::TextureDescriptor { - label: wgpu_tex_desc.label, - size: wgpu_tex_desc.size, - mip_level_count: wgpu_tex_desc.mip_level_count, - sample_count: wgpu_tex_desc.sample_count, - dimension: wgpu_tex_desc.dimension, - format: wgpu_tex_desc.format, - view_formats: vec![], - usage: wgpu_hal::TextureUses::COLOR_TARGET | wgpu_hal::TextureUses::COPY_DST, - memory_flags: MemoryFlags::empty(), - }; - - // Create a WGPU image view for this image - // TODO: Move this to Texture2D::from_vk_image - let wgpu_texture = vulkan_image_to_texture( - device, - vk::Image::from_raw(image), - wgpu_tex_desc, - wgpu_hal_tex_desc, - ); - Texture2D::::from_wgpu(device, wgpu_texture) - }) - .collect(); + //TODO: Enumerate swapchain formats and pick the best one, remember that WGPU gamma corrects everything + let color_swapchain = Swapchain::new( + "OpenXR Swapchain Image", + xr_session, + device, + SwapchainCreationInfo { + resolution, + format: SWAPCHAIN_COLOR_FORMAT, + view_format: Some(SWAPCHAIN_COLOR_FORMAT.to_norm()), + usage_flags: openxr::SwapchainUsageFlags::COLOR_ATTACHMENT, + view_count: VIEW_COUNT, + }, + )?; + + if color_swapchain.is_empty() { + return Err(anyhow::anyhow!("No swapchain images")); + } + + Ok((color_swapchain, resolution)) + } +} + +#[derive(Clone, Copy)] +struct VkDeviceCreateInfo<'a> { + xr_instance: &'a openxr::Instance, + system_id: SystemId, + hal_exposed_adapter: &'a hal::ExposedAdapter, + wgpu_features: wgpu::Features, + queue_family_index: u32, + vk_entry: &'a ash::Entry, + vk_physical_device: vk::PhysicalDevice, + vk_instance: &'a ash::Instance, +} - Ok((xr_swapchain, resolution, swapcain_textures)) +fn create_vk_device<'a>( + create_info: VkDeviceCreateInfo<'_>, + global_queue_priority: Option<&'a mut vk::DeviceQueueGlobalPriorityCreateInfoKHR>, +) -> Result< + ( + Vec<&'static std::ffi::CStr>, + vk::DeviceQueueCreateInfoBuilder<'a>, + ash::Device, + ), + anyhow::Error, +> { + let VkDeviceCreateInfo { + xr_instance, + system_id, + hal_exposed_adapter, + wgpu_features, + queue_family_index, + vk_entry, + vk_physical_device, + vk_instance, + } = create_info; + + let mut device_extensions = hal_exposed_adapter + .adapter + .required_device_extensions(wgpu_features); + #[cfg(target_os = "windows")] + device_extensions.push(ash::extensions::khr::ExternalMemoryWin32::name()); + log::info!("Requested device extensions: {:?}", device_extensions); + let mut family_info = vk::DeviceQueueCreateInfo::builder() + .queue_family_index(queue_family_index) + .queue_priorities(&[1.0]); + + if let Some(global_queue_priority) = global_queue_priority { + family_info = family_info.push_next(global_queue_priority); } + + let device_extensions_ptrs = device_extensions + .iter() + .map(|x| x.as_ptr()) + .collect::>(); + let mut enabled_features = hal_exposed_adapter + .adapter + .physical_device_features(&device_extensions, wgpu_features); + let mut multiview_params = vk::PhysicalDeviceMultiviewFeatures { + multiview: vk::TRUE, + ..Default::default() + }; + let device_create_info = enabled_features + .add_to_device_create_builder(vk::DeviceCreateInfo::builder()) + .queue_create_infos(std::slice::from_ref(&family_info)) + .enabled_extension_names(&device_extensions_ptrs) + .push_next(&mut multiview_params); + let vk_device = { + unsafe { + let vk_device = xr_instance + .create_vulkan_device( + system_id, + std::mem::transmute(vk_entry.static_fn().get_instance_proc_addr), + vk_physical_device.as_raw() as _, + &device_create_info as *const _ as *const _, + ) + .context("XR error creating Vulkan device")? + .map_err(vk::Result::from_raw) + .context("Vulkan error creating Vulkan device")?; + + log::info!("Creating ash vulkan device device from native"); + ash::Device::load(vk_instance.fp_v1_0(), vk::Device::from_raw(vk_device as _)) + } + }; + Ok((device_extensions, family_info, vk_device)) } diff --git a/src/lib.rs b/src/lib.rs index 0c7a9de..753abce 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,18 @@ #[cfg(target_os = "windows")] -use ::windows::Win32::System::Threading::{ - GetCurrentProcess, SetPriorityClass, HIGH_PRIORITY_CLASS, +use ::windows::Win32::{ + Foundation::GetLastError, + Security::{ + AdjustTokenPrivileges, LookupPrivilegeValueW, LUID_AND_ATTRIBUTES, + SE_INC_BASE_PRIORITY_NAME, SE_PRIVILEGE_ENABLED, TOKEN_ADJUST_PRIVILEGES, TOKEN_PRIVILEGES, + TOKEN_QUERY, + }, + System::Threading::{GetCurrentProcess, SetPriorityClass, HIGH_PRIORITY_CLASS}, + System::Threading::{ + GetCurrentThread, OpenProcessToken, SetThreadPriority, THREAD_PRIORITY_HIGHEST, + }, }; use anyhow::Context; -use cgmath::Rotation3; + use clap::Parser; use config::{AppConfig, TemporalBlurParams}; use engine::{ @@ -11,60 +20,37 @@ use engine::{ geometry::{ModelVertex, Vertex}, input::InputContext, screen::Screen, + space::AppSpace, + swapchain::Swapchain, texture::{Bound, RoundRobinTextureBuffer, Texture2D, Unbound}, vr::{enable_xr_runtime, OpenXRContext, SWAPCHAIN_COLOR_FORMAT, VIEW_COUNT, VIEW_TYPE}, WgpuContext, WgpuLoader, }; -use loaders::{katanga_loader::KatangaLoaderContext, Loader, StereoMode}; -use log::LevelFilter; -use log4rs::{ - append::file::FileAppender, - config::{Appender, Root}, - encode::pattern::PatternEncoder, - Config, -}; -use openxr::ReferenceSpaceType; +use loaders::{blank_loader::BlankLoader, Loader, StereoMode}; +use log::error; +use utils::commands::AppState; + use std::{ iter, num::NonZeroU32, sync::{Arc, Mutex}, }; use thread_priority::*; -#[cfg(not(target_os = "android"))] -use tray_item::TrayItem; use wgpu::{util::DeviceExt, BindGroupLayout}; -use crate::config::ConfigContext; +use crate::{ + config::ConfigContext, + utils::commands::{AppCommands, AppContext, RecenterRequest, ToggleSetting}, +}; mod config; mod conversions; mod engine; mod loaders; +mod utils; -#[derive(Clone)] -enum TrayMessages { - Quit, - Reload, - Recenter(bool), - ToggleSettings(ToggleSetting), -} - -#[derive(Clone)] -enum ToggleSetting { - FlipX, - FlipY, - SwapEyes, - AmbientLight, -} - -struct TrayState { - pub message: Option<&'static TrayMessages>, -} - -struct RecenterRequest { - pub delay: i64, - pub horizon_locked: bool, -} +#[macro_use] +mod macros; const AMBIENT_BLUR_BASE_RES: u32 = 16; const AMBIENT_BLUR_TEMPORAL_SAMPLES: u32 = 16; @@ -72,7 +58,14 @@ const AMBIENT_BLUR_TEMPORAL_SAMPLES: u32 = 16; #[global_allocator] static ALLOC: dhat::Alloc = dhat::Alloc; -pub fn launch() -> anyhow::Result<()> { +pub fn launch() { + #[cfg(not(target_os = "android"))] + if let Err(err) = utils::logging::setup_logging() { + log::error!("Failed to setup logging: {}", err); + } + + try_elevate_priority(); + #[cfg(feature = "dhat-heap")] let _profiler = dhat::Profiler::new_heap(); @@ -84,117 +77,53 @@ pub fn launch() -> anyhow::Result<()> { #[cfg(feature = "renderdoc")] let _rd: renderdoc::RenderDoc = - renderdoc::RenderDoc::new().context("Unable to connect to renderdoc")?; - - #[cfg(not(target_os = "android"))] - { - let logfile = FileAppender::builder() - .encoder(Box::new(PatternEncoder::new("{l} - {m}\n"))) - .build("output.log")?; - - let config = Config::builder() - .appender(Appender::builder().build("logfile", Box::new(logfile))) - .build(Root::builder().appender("logfile").build(LevelFilter::Info))?; - - log4rs::init_config(config)?; - log_panics::init(); - } + match renderdoc::RenderDoc::new().context("Unable to connect to renderdoc") { + Ok(rd) => rd, + Err(err) => { + log::error!("Failed to connect to renderdoc: {}", err); + return; + } + }; - try_elevate_priority(); + let app = match AppContext::new() { + Ok(app) => app, + Err(err) => { + log::error!("Failed to create app context: {}", err); + return; + } + }; - let mut xr_context = enable_xr_runtime()?; - let wgpu_context = xr_context.load_wgpu()?; + let mut xr_context = match enable_xr_runtime() { + Ok(xr_context) => xr_context, + Err(err) => { + log::error!("Failed to enable OpenXR runtime: {}", err); + return; + } + }; - #[cfg(not(target_os = "android"))] - let (_tray, tray_state) = build_tray()?; - #[cfg(target_os = "android")] - let tray_state = Arc::new(Mutex::new(TrayState { message: None })); + let wgpu_context = match xr_context.load_wgpu() { + Ok(wgpu_context) => wgpu_context, + Err(err) => { + log::error!("Failed to load WGPU: {}", err); + return; + } + }; let mut config_context = config::ConfigContext::try_setup().unwrap_or(None); log::info!("Finished initial setup, running main loop"); - run( + + if let Err(err) = run( &mut xr_context, &wgpu_context, - &tray_state, + &app.state, &mut config_context, - )?; - - Ok(()) -} - -#[cfg(not(target_os = "android"))] -fn add_tray_message_sender( - tray_state: &Arc>, - tray: &mut TrayItem, - entry_name: &'static str, - message: &'static TrayMessages, -) -> anyhow::Result<()> { - let cloned_state = tray_state.clone(); - Ok(tray.add_menu_item(entry_name, move || { - if let Ok(mut locked_state) = cloned_state.lock() { - locked_state.message = Some(message); - } - })?) -} - -#[cfg(not(target_os = "android"))] -fn add_all_tray_message_senders( - tray_state: &Arc>, - tray: &mut TrayItem, - entries: Vec<(&'static str, &'static TrayMessages)>, -) -> anyhow::Result<()> { - for (entry_name, message) in entries { - add_tray_message_sender(tray_state, tray, entry_name, message)?; + ) { + log::error!("VRScreenCap closed unexpectedly with an error: {}", err); } - Ok(()) -} - -#[cfg(not(target_os = "android"))] -fn build_tray() -> anyhow::Result<(TrayItem, Arc>)> { - log::info!("Building system tray"); - let mut tray = TrayItem::new("VR Screen Cap", "tray-icon")?; - let tray_state = Arc::new(Mutex::new(TrayState { message: None })); - - tray.add_label("Settings")?; - add_all_tray_message_senders( - &tray_state, - &mut tray, - vec![ - ( - "Swap Eyes", - &TrayMessages::ToggleSettings(ToggleSetting::SwapEyes), - ), - ( - "Flip X", - &TrayMessages::ToggleSettings(ToggleSetting::FlipX), - ), - ( - "Flip Y", - &TrayMessages::ToggleSettings(ToggleSetting::FlipY), - ), - ( - "Toggle Ambient Light", - &TrayMessages::ToggleSettings(ToggleSetting::AmbientLight), - ), - ], - )?; - - tray.add_label("Actions")?; - add_all_tray_message_senders( - &tray_state, - &mut tray, - vec![ - ("Reload Screen", &TrayMessages::Reload), - ("Recenter", &TrayMessages::Recenter(true)), - ("Recenter w/ Pitch", &TrayMessages::Recenter(false)), - ("Quit", &TrayMessages::Quit), - ], - )?; - - Ok((tray, tray_state)) } +#[cfg_attr(feature = "profiling", profiling::function)] fn try_elevate_priority() { log::info!("Trying to elevate process priority"); if set_current_thread_priority(ThreadPriority::Max).is_err() { @@ -203,16 +132,83 @@ fn try_elevate_priority() { #[cfg(target_os = "windows")] { - if !unsafe { SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS) }.as_bool() { + try_elevate_privileges(); + + if unsafe { SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS) }.is_err() { log::warn!("Failed to set process priority to max!"); } + + if let Err(err) = unsafe { SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST) } + { + log::warn!("Failed to set thread priority to max! {}", err); + } } } +// Tries to enable SE_INC_BASE_PRIORITY_NAME privilege, allows to set vulkan global queue priority +#[cfg(target_os = "windows")] +fn try_elevate_privileges() { + use std::mem::size_of; + + let mut h_token = Default::default(); + if unsafe { + OpenProcessToken( + GetCurrentProcess(), + TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, + &mut h_token, + ) + } + .is_ok() + { + let privs = LUID_AND_ATTRIBUTES { + Luid: Default::default(), + Attributes: SE_PRIVILEGE_ENABLED, + }; + let mut tp = TOKEN_PRIVILEGES { + PrivilegeCount: 1, + Privileges: [privs; 1], + }; + + if unsafe { + LookupPrivilegeValueW(None, SE_INC_BASE_PRIORITY_NAME, &mut tp.Privileges[0].Luid) + } + .is_err() + { + log::warn!("Failed to lookup SE_INC_BASE_PRIORITY_NAME privilege"); + return; + } + + if unsafe { + AdjustTokenPrivileges( + h_token, + false, + Some(&tp), + size_of::() as _, + None, + None, + ) + } + .is_err() + { + log::warn!("Failed to adjust SE_INC_BASE_PRIORITY privilege"); + return; + } + + if unsafe { GetLastError() }.is_err() { + log::warn!("Failed to request SE_INC_BASE_PRIORITY privilege, if you want VRScreenCap to run at max priority, please run it as administrator"); + } else { + log::info!("Running in high priority mode"); + } + } else { + log::warn!("Failed to request SE_INC_BASE_PRIORITY privilege, if you want VRScreenCap to run at max priority, please run it as administrator"); + } +} + +#[cfg_attr(feature = "profiling", profiling::function)] fn run( xr_context: &mut OpenXRContext, wgpu_context: &WgpuContext, - tray_state: &Arc>, + app_state: &Arc>, config: &mut Option, ) -> anyhow::Result<()> { // Load the shaders from disk @@ -226,23 +222,27 @@ fn run( // We don't need to configure the texture view much, so let's // let wgpu define it. - let mut aspect_ratio = 1.0; let mut stereo_mode = StereoMode::Mono; + let mut default_stereo_mode = StereoMode::Mono; // Not configurable for now let mut current_loader = None; - //Load blank texture - let blank_texture = Texture2D::::from_bytes( - &wgpu_context.device, - &wgpu_context.queue, - include_bytes!("../assets/blank_grey.png"), - "Blank", - )?; - let mut loaders: Vec> = vec![ #[cfg(target_os = "windows")] { + use loaders::katanga_loader::KatangaLoaderContext; Box::::default() }, + #[cfg(target_os = "windows")] + { + use loaders::desktop_duplication_loader::DesktopDuplicationLoader; + Box::new(DesktopDuplicationLoader::new(0)?) + }, + #[cfg(any(target_os = "unix"))] + { + use loaders::captrs_loader::CaptrLoader; + Box::new(CaptrLoader::new(0)?) + }, + Box::::default(), ]; let texture_bind_group_layout = @@ -272,8 +272,17 @@ fn run( label: Some("texture_bind_group_layout"), }); - let mut screen_texture = - blank_texture.bind_to_context(wgpu_context, &texture_bind_group_layout); + let mut screen_texture = loaders + .last_mut() + .unwrap() + .load( + &wgpu_context.instance, + &wgpu_context.device, + &wgpu_context.queue, + )? + .texture + .bind_to_context(wgpu_context, &texture_bind_group_layout); + let mut ambient_texture = get_ambient_texture( &screen_texture, 1.0, @@ -282,20 +291,6 @@ fn run( &texture_bind_group_layout, )?; - if let Some((texture, aspect, mode, loader)) = try_to_load_texture(&mut loaders, wgpu_context) { - screen_texture = texture.bind_to_context(wgpu_context, &texture_bind_group_layout); - ambient_texture = get_ambient_texture( - &screen_texture, - aspect, - &mode, - wgpu_context, - &texture_bind_group_layout, - )?; - aspect_ratio = aspect; - stereo_mode = mode; - current_loader = Some(loader); - } - let fullscreen_triangle_index_buffer = wgpu_context .device @@ -305,7 +300,7 @@ fn run( usage: wgpu::BufferUsages::INDEX, }); - let mut screen_params = match config { + let mut app_config = match config { Some(ConfigContext { last_config: Some(config), .. @@ -325,10 +320,10 @@ fn run( let mut screen = Screen::new( &wgpu_context.device, - -screen_params.distance, - screen_params.scale, - aspect_ratio, - screen_params.ambient, + -app_config.distance, + app_config.scale, + 1.0, + app_config.ambient, ); let screen_params_buffer = @@ -336,7 +331,7 @@ fn run( .device .create_buffer_init(&wgpu::util::BufferInitDescriptor { label: Some("Screen Params Buffer"), - contents: bytemuck::cast_slice(&[screen_params.uniform(1.0, 1, 1)]), + contents: bytemuck::cast_slice(&[app_config.uniform(1.0, 1, 1, &stereo_mode)]), usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, }); @@ -499,7 +494,7 @@ fn run( module: &screen_shader, entry_point: "fs_main", targets: &[Some(wgpu::ColorTargetState { - format: SWAPCHAIN_COLOR_FORMAT, + format: SWAPCHAIN_COLOR_FORMAT.to_norm().try_into()?, blend: Some(wgpu::BlendState::REPLACE), write_mask: wgpu::ColorWrites::ALL, })], @@ -525,7 +520,7 @@ fn run( module: &screen_shader, entry_point: "vignette_fs_main", targets: &[Some(wgpu::ColorTargetState { - format: SWAPCHAIN_COLOR_FORMAT, + format: SWAPCHAIN_COLOR_FORMAT.to_norm().try_into()?, blend: Some(wgpu::BlendState::REPLACE), write_mask: wgpu::ColorWrites::ALL, })], @@ -552,12 +547,12 @@ fn run( entry_point: "temporal_fs_main", targets: &[ Some(wgpu::ColorTargetState { - format: SWAPCHAIN_COLOR_FORMAT, + format: SWAPCHAIN_COLOR_FORMAT.to_norm().try_into()?, blend: Some(wgpu::BlendState::REPLACE), write_mask: wgpu::ColorWrites::ALL, }), Some(wgpu::ColorTargetState { - format: SWAPCHAIN_COLOR_FORMAT, + format: SWAPCHAIN_COLOR_FORMAT.to_norm().try_into()?, blend: Some(wgpu::BlendState::REPLACE), write_mask: wgpu::ColorWrites::ALL, }), @@ -577,56 +572,108 @@ fn run( instance: wgpu_context.vk_instance_ptr as _, physical_device: wgpu_context.vk_phys_device_ptr as _, device: wgpu_context.vk_device_ptr as _, - queue_family_index: wgpu_context.queue_index, + queue_family_index: wgpu_context.family_queue_index, queue_index: 0, }, )? }; // Create a room-scale reference space - let xr_reference_space = xr_session - .create_reference_space(openxr::ReferenceSpaceType::LOCAL, openxr::Posef::IDENTITY)?; - let xr_view_space = xr_session - .create_reference_space(openxr::ReferenceSpaceType::VIEW, openxr::Posef::IDENTITY)?; - let mut xr_space = xr_session - .create_reference_space(openxr::ReferenceSpaceType::LOCAL, openxr::Posef::IDENTITY)?; - + let mut app_space = AppSpace::new(&xr_session)?; let mut event_storage = openxr::EventDataBuffer::new(); let mut session_running = false; let mut swapchain = None; let mut screen_invalidated = false; let mut recenter_request = None; let mut last_invalidation_check = std::time::Instant::now(); - let mut input_context = InputContext::init(&xr_context.instance) - .map(Some) - .unwrap_or(None); + let mut last_upgrade_check = std::time::Instant::now(); + let mut input_context = match app_config.no_input { + false => InputContext::init(&xr_context.instance) + .map(Some) + .unwrap_or(None), + true => None, + }; if input_context.is_some() { let mut attach_context = input_context .take() .context("Cannot attach input context to session")?; - if attach_context.attach_to_session(&xr_session).is_ok() { + if let Err(attach_context_err) = attach_context.attach_to_session(&xr_session) { + log::error!( + "Cannot attach input context to session: {}", + attach_context_err + ); + } else { input_context = Some(attach_context); } + } else { + log::debug!("No input context available"); } let mut jitter_frame: u32 = 0; // Handle OpenXR events - loop { + 'render_loop: loop { #[cfg(feature = "profiling")] profiling::scope!("main loop"); let time = std::time::Instant::now(); + // Try to upgrade the loader to one that has higher priority + if current_loader.is_none() || time.duration_since(last_upgrade_check).as_secs() > 10 { + #[cfg(feature = "profiling")] + profiling::scope!("Loader Upgrade"); + + if let Some((texture, aspect, mode, loader)) = + try_to_load_texture(&mut loaders, wgpu_context, current_loader) + { + let mode = mode.unwrap_or(default_stereo_mode.clone()); + screen_texture = texture.bind_to_context(wgpu_context, &texture_bind_group_layout); + ambient_texture = get_ambient_texture( + &screen_texture, + aspect, + &mode, + wgpu_context, + &texture_bind_group_layout, + )?; + screen.change_aspect_ratio(aspect); + stereo_mode = mode; + screen_invalidated = current_loader != Some(loader); + current_loader = Some(loader); + } + + last_upgrade_check = time; + } + + // Check if the loader needs to be invalidated if current_loader.is_some() || time.duration_since(last_invalidation_check).as_secs() > 10 { + #[cfg(feature = "profiling")] + profiling::scope!("Loader Invalidation Check"); + check_loader_invalidation(current_loader, &loaders, &mut screen_invalidated)?; last_invalidation_check = time; } + // Check if the loader has been invalidated if screen_invalidated { - if let Some((texture, aspect, mode, loader)) = - try_to_load_texture(&mut loaders, wgpu_context) - { + #[cfg(feature = "profiling")] + profiling::scope!("Loader Invalidation"); + + // Try to load a new texture from the same loader, or from any loader if the current one fails + let new_loader = current_loader + .map(|loader_idx| (loaders.get_mut(loader_idx), loader_idx)) + .filter(|(loader, _)| loader.is_some()) + .map(|(loader, loader_idx)| try_loader(loader.unwrap(), wgpu_context, loader_idx)) + .map(|loader| { + if loader.is_some() { + loader + } else { + try_to_load_texture(&mut loaders, wgpu_context, None) + } + }) + .unwrap_or_default(); + + if let Some((texture, aspect, mode, loader)) = new_loader { + let mode = mode.unwrap_or(default_stereo_mode.clone()); screen_texture = texture.bind_to_context(wgpu_context, &texture_bind_group_layout); ambient_texture = get_ambient_texture( &screen_texture, @@ -635,10 +682,9 @@ fn run( wgpu_context, &texture_bind_group_layout, )?; - aspect_ratio = aspect; - stereo_mode = mode; + screen.change_aspect_ratio(aspect); current_loader = Some(loader); - screen.change_aspect_ratio(aspect_ratio); + stereo_mode = mode; wgpu_context.queue.write_buffer( &screen_model_matrix_buffer, @@ -654,423 +700,425 @@ fn run( wgpu_context.queue.write_buffer( &screen_params_buffer, 0, - bytemuck::cast_slice(&[screen_params.uniform( + bytemuck::cast_slice(&[app_config.uniform( aspect, screen_texture.texture.width() * width_multiplier, ambient_texture.current().texture.width() * width_multiplier, + &stereo_mode, )]), ); } screen_invalidated = false; } - let event = xr_context.instance.poll_event(&mut event_storage)?; - match event { - Some(openxr::Event::SessionStateChanged(e)) => { - // Session state change is where we can begin and end sessions, as well as - // find quit messages! - log::info!("Entered state {:?}", e.state()); - match e.state() { - openxr::SessionState::READY => { - xr_session.begin(VIEW_TYPE)?; - session_running = true; - } - openxr::SessionState::STOPPING => { - xr_session.end()?; - session_running = false; - } - openxr::SessionState::EXITING => { - break; + // Run loader update logic + if let Some(current_loader) = current_loader { + #[cfg(feature = "profiling")] + profiling::scope!("Loader Update"); + + if let Err(error) = loaders + .get_mut(current_loader) + .map(|loader| { + loader.update( + &wgpu_context.instance, + &wgpu_context.device, + &wgpu_context.queue, + &screen_texture, + ) + }) + .unwrap_or(Err(anyhow::anyhow!("Loader not found"))) + { + screen_invalidated = true; + error!("Loader update failed: {}", error); + } + } + + while let Some(event) = xr_context.instance.poll_event(&mut event_storage)? { + match event { + openxr::Event::SessionStateChanged(e) => { + // Session state change is where we can begin and end sessions, as well as + // find quit messages! + log::info!("Entered state {:?}", e.state()); + match e.state() { + openxr::SessionState::READY => { + xr_session.begin(VIEW_TYPE)?; + session_running = true; + } + openxr::SessionState::STOPPING => { + xr_session.end()?; + session_running = false; + } + openxr::SessionState::EXITING => { + break 'render_loop; + } + _ => {} } - _ => {} } + openxr::Event::InstanceLossPending(_) => {} + openxr::Event::EventsLost(e) => { + log::error!("Lost {} OpenXR events", e.lost_event_count()); + } + openxr::Event::ReferenceSpaceChangePending(_) => { + log::info!("Reference space change pending, recentering XR space"); + //Reset XR space to follow runtime + reset_app_space(&mut app_space, &xr_session, input_context.as_mut())?; + } + _ => {} } - Some(openxr::Event::InstanceLossPending(_)) => {} - Some(openxr::Event::EventsLost(e)) => { - log::error!("Lost {} OpenXR events", e.lost_event_count()); + } + + // Render to HMD only if we have an active session + if !session_running { + #[cfg(feature = "profiling")] + profiling::scope!("Session Sleep"); + + // avoid looping too fast + std::thread::sleep(std::time::Duration::from_millis(11)); + } else { + // Block until the previous frame is finished displaying, and is ready for + // another one. Also returns a prediction of when the next frame will be + // displayed, for use with predicting locations of controllers, viewpoints, etc. + let xr_frame_state = { + #[cfg(feature = "profiling")] + profiling::scope!("Wait for frame"); + + frame_wait.wait()? + }; + + // If we do not have a swapchain yet, create it + let (color_swapchain, resolution) = { + #[cfg(feature = "profiling")] + profiling::scope!("Swapchain Setup"); + + match swapchain { + Some(ref mut swapchain) => swapchain, + None => { + let new_swapchain = + xr_context.create_swapchain(&xr_session, &wgpu_context.device)?; + swapchain.get_or_insert(new_swapchain) + } + } + }; + + // Check which image we need to render to and wait until the compositor is + // done with this image + let swapchain_color_view = color_swapchain.wait_next_image()?; + + // Must be called before any rendering is done! + { + #[cfg(feature = "profiling")] + profiling::scope!("Begin FrameStream"); + frame_stream.begin()?; } - Some(openxr::Event::ReferenceSpaceChangePending(_)) => { - //Reset XR space to follow runtime - xr_space = xr_session.create_reference_space( - openxr::ReferenceSpaceType::LOCAL, - openxr::Posef::IDENTITY, - )?; + + #[cfg(feature = "profiling")] + profiling::scope!("FrameStream Recording"); + + // Only render if we should + if !xr_frame_state.should_render { + #[cfg(feature = "profiling")] + { + let predicted_display_time_nanos = + xr_frame_state.predicted_display_time.as_nanos(); + profiling::scope!( + "Show Time Calculation", + format!("{predicted_display_time_nanos}").as_str() + ); + } + + color_swapchain.release_image()?; + + // Early bail + if let Err(err) = frame_stream.end( + xr_frame_state.predicted_display_time, + xr_context.blend_mode, + &[], + ) { + log::error!( + "Failed to end frame stream when should_render is FALSE : {:?}", + err + ); + }; + continue; } - _ => { - // Render to HMD only if we have an active session - if session_running { - // Block until the previous frame is finished displaying, and is ready for - // another one. Also returns a prediction of when the next frame will be - // displayed, for use with predicting locations of controllers, viewpoints, etc. - #[cfg(feature = "profiling")] - profiling::scope!("Wait for frame"); - let xr_frame_state = frame_wait.wait()?; - - // Must be called before any rendering is done! - frame_stream.begin()?; - - #[cfg(feature = "profiling")] - profiling::scope!("FrameStream Recording"); - - // Only render if we should - if !xr_frame_state.should_render { - #[cfg(feature = "profiling")] - { - let predicted_display_time_nanos = - xr_frame_state.predicted_display_time.as_nanos(); - profiling::scope!( - "Show Time Calculation", - format!("{predicted_display_time_nanos}").as_str() - ); - } - // Early bail - if let Err(err) = frame_stream.end( - xr_frame_state.predicted_display_time, - xr_context.blend_mode, - &[], - ) { - log::error!( - "Failed to end frame stream when should_render is FALSE : {:?}", - err - ); - }; - continue; - } + #[cfg(feature = "profiling")] + profiling::scope!("Encode Render Passes"); - #[cfg(feature = "profiling")] - profiling::scope!("Swapchain Setup"); + // Render! + let mut encoder = + wgpu_context + .device + .create_command_encoder(&wgpu::CommandEncoderDescriptor { + label: Some("Render Encorder"), + }); - // If we do not have a swapchain yet, create it - let (xr_swapchain, resolution, swapchain_textures) = match swapchain { - Some(ref mut swapchain) => swapchain, - None => { - let new_swapchain = - xr_context.create_swapchain(&xr_session, &wgpu_context.device)?; - swapchain.get_or_insert(new_swapchain) - } - }; - // Check which image we need to render to and wait until the compositor is - // done with this image - let image_index = xr_swapchain.acquire_image()?; - xr_swapchain.wait_image(openxr::Duration::INFINITE)?; - - let swapchain_view = &swapchain_textures[image_index as usize].view; - - log::trace!("Encode render pass"); - #[cfg(feature = "profiling")] - profiling::scope!("Encode Render Pass"); - // Render! - let mut encoder = wgpu_context.device.create_command_encoder( - &wgpu::CommandEncoderDescriptor { - label: Some("Render Encorder"), + if let Some(loader) = current_loader.and_then(|index| loaders.get(index)) { + loader.encode_pre_pass(&mut encoder, &screen_texture)?; + } + + if screen.ambient_enabled { + #[cfg(feature = "profiling")] + profiling::scope!("Encode Ambient Pass"); + + ambient_texture.next(); + let mut blit_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("Blit Pass"), + color_attachments: &[ + Some(wgpu::RenderPassColorAttachment { + view: &ambient_texture.current().view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(wgpu::Color::BLACK), + store: wgpu::StoreOp::Store, + }, + }), + Some(wgpu::RenderPassColorAttachment { + view: &ambient_texture.previous(1).view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(wgpu::Color::BLACK), + store: wgpu::StoreOp::Store, + }, + }), + ], + depth_stencil_attachment: None, + ..Default::default() + }); + + blit_pass.set_pipeline(&temporal_blur_pipeline); + blit_pass.set_bind_group(0, screen_texture.bind_group(), &[]); + blit_pass.set_bind_group(1, ambient_texture.previous(2).bind_group(), &[]); + blit_pass.set_bind_group(2, &global_temporal_blur_uniform_bind_group, &[]); + blit_pass.set_index_buffer( + fullscreen_triangle_index_buffer.slice(..), + wgpu::IndexFormat::Uint32, + ); + blit_pass.draw_indexed(0..3, 0, 0..1); + } + { + #[cfg(feature = "profiling")] + profiling::scope!("Encode Render Pass"); + let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("Render Pass"), + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: swapchain_color_view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(wgpu::Color::BLACK), + store: wgpu::StoreOp::Store, }, + })], + depth_stencil_attachment: None, + ..Default::default() + }); + + // Render the ambient dome + if screen.ambient_enabled { + let ambient_mesh = &screen.ambient_mesh; + rpass.set_pipeline(&ambient_dome_pipeline); + rpass.set_bind_group(0, ambient_texture.current().bind_group(), &[]); + rpass.set_bind_group(1, &global_uniform_bind_group, &[]); + rpass.set_vertex_buffer(0, ambient_mesh.vertex_buffer().slice(..)); + rpass.set_index_buffer( + ambient_mesh.index_buffer().slice(..), + wgpu::IndexFormat::Uint32, ); - if screen.ambient_enabled { - ambient_texture.next(); - let mut blit_pass = - encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - label: Some("Blit Pass"), - color_attachments: &[ - Some(wgpu::RenderPassColorAttachment { - view: &ambient_texture.current().view, - resolve_target: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Clear(wgpu::Color::BLACK), - store: true, - }, - }), - Some(wgpu::RenderPassColorAttachment { - view: &ambient_texture.previous(1).view, - resolve_target: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Clear(wgpu::Color::BLACK), - store: true, - }, - }), - ], - depth_stencil_attachment: None, - }); - - blit_pass.set_pipeline(&temporal_blur_pipeline); - blit_pass.set_bind_group(0, screen_texture.bind_group(), &[]); - blit_pass.set_bind_group(1, ambient_texture.previous(2).bind_group(), &[]); - blit_pass.set_bind_group(2, &global_temporal_blur_uniform_bind_group, &[]); - blit_pass.set_index_buffer( - fullscreen_triangle_index_buffer.slice(..), - wgpu::IndexFormat::Uint32, - ); - blit_pass.draw_indexed(0..3, 0, 0..1); - } - { - let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - label: Some("Render Pass"), - color_attachments: &[Some(wgpu::RenderPassColorAttachment { - view: swapchain_view, - resolve_target: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Clear(wgpu::Color::BLACK), - store: true, - }, - })], - depth_stencil_attachment: None, - }); - - // Render the ambient dome - if screen.ambient_enabled { - let ambient_mesh = &screen.ambient_mesh; - rpass.set_pipeline(&ambient_dome_pipeline); - rpass.set_bind_group(0, ambient_texture.current().bind_group(), &[]); - rpass.set_bind_group(1, &global_uniform_bind_group, &[]); - rpass.set_vertex_buffer(0, ambient_mesh.vertex_buffer().slice(..)); - rpass.set_index_buffer( - ambient_mesh.index_buffer().slice(..), - wgpu::IndexFormat::Uint32, - ); - rpass.draw_indexed(0..ambient_mesh.indices(), 0, 0..1); - } + rpass.draw_indexed(0..ambient_mesh.indices(), 0, 0..1); + } - // Render the screen - rpass.set_pipeline(&screen_render_pipeline); - rpass.set_bind_group(0, screen_texture.bind_group(), &[]); - rpass.set_bind_group(1, &global_uniform_bind_group, &[]); - rpass.set_vertex_buffer(0, screen.mesh.vertex_buffer().slice(..)); - rpass.set_index_buffer( - screen.mesh.index_buffer().slice(..), - wgpu::IndexFormat::Uint32, - ); - rpass.draw_indexed(0..screen.mesh.indices(), 0, 0..1); - } + // Render the screen + rpass.set_pipeline(&screen_render_pipeline); + rpass.set_bind_group(0, screen_texture.bind_group(), &[]); + rpass.set_bind_group(1, &global_uniform_bind_group, &[]); + rpass.set_vertex_buffer(0, screen.mesh.vertex_buffer().slice(..)); + rpass.set_index_buffer( + screen.mesh.index_buffer().slice(..), + wgpu::IndexFormat::Uint32, + ); + rpass.draw_indexed(0..screen.mesh.indices(), 0, 0..1); + } - #[cfg(feature = "profiling")] - profiling::scope!("Locate Views"); - log::trace!("Locate views"); - // Fetch the view transforms. To minimize latency, we intentionally do this - // *after* recording commands to render the scene, i.e. at the last possible - // moment before rendering begins in earnest on the GPU. Uniforms dependent on - // this data can be sent to the GPU just-in-time by writing them to per-frame - // host-visible memory which the GPU will only read once the command buffer is - // submitted. - let (_, views) = xr_session.locate_views( - VIEW_TYPE, - xr_frame_state.predicted_display_time, - &xr_space, - )?; - - for (view_idx, view) in views.iter().enumerate() { - let mut eye = cameras - .get_mut(view_idx) - .context("Cannot borrow camera as mutable")?; - eye.entity.position.x = view.pose.position.x; - eye.entity.position.y = view.pose.position.y; - eye.entity.position.z = view.pose.position.z; - eye.entity.rotation.v.x = view.pose.orientation.x; - eye.entity.rotation.v.y = view.pose.orientation.y; - eye.entity.rotation.v.z = view.pose.orientation.z; - eye.entity.rotation.s = view.pose.orientation.w; - eye.entity.update_matrices(&[]); - eye.update_projection_from_tangents(view.fov); - let camera_uniform = camera_uniform - .get_mut(view_idx) - .context("Cannot borrow camera uniform buffer as mutable")?; - camera_uniform.update_view_proj(eye)?; - } + if screen.ambient_enabled { + upload_blur_uniforms( + &ambient_texture, + &mut jitter_frame, + &mut temporal_blur_params, + wgpu_context, + &temporal_blur_params_buffer, + ); + } - log::trace!("Write views"); - wgpu_context.queue.write_buffer( - &camera_buffer, - 0, - bytemuck::cast_slice(camera_uniform.as_slice()), - ); + // Fetch the view transforms. To minimize latency, we intentionally do this + // *after* recording commands to render the scene, i.e. at the last possible + // moment before rendering begins in earnest on the GPU. Uniforms dependent on + // this data can be sent to the GPU just-in-time by writing them to per-frame + // host-visible memory which the GPU will only read once the command buffer is + // submitted. + log::trace!("Locate views"); + let (_, views) = { + #[cfg(feature = "profiling")] + profiling::scope!("Locate Views"); + xr_session.locate_views( + VIEW_TYPE, + xr_frame_state.predicted_display_time, + app_space.space(), + )? + }; + + upload_camera_uniforms( + &views, + &mut cameras, + &mut camera_uniform, + wgpu_context, + &camera_buffer, + )?; + + log::trace!("Submit command buffer"); + { + #[cfg(feature = "profiling")] + profiling::scope!("Encoder Submit"); + wgpu_context.queue.submit(iter::once(encoder.finish())); + } - if screen.ambient_enabled { - log::trace!("Writing temporal blur uniforms"); - let ambient_texture = &ambient_texture.current().texture; - let resolution = [ - ambient_texture.width() as f32, - ambient_texture.height() as f32, - ]; - jitter_frame = (jitter_frame + 1) % AMBIENT_BLUR_TEMPORAL_SAMPLES; - temporal_blur_params.jitter = - engine::jitter::get_jitter(jitter_frame, &resolution); - temporal_blur_params.resolution = resolution; - wgpu_context.queue.write_buffer( - &temporal_blur_params_buffer, - 0, - bytemuck::cast_slice(&[temporal_blur_params.uniform()]), - ); - } + log::trace!("Release swapchain image"); + { + #[cfg(feature = "profiling")] + profiling::scope!("Release Swapchain"); - #[cfg(feature = "profiling")] - profiling::scope!("Encode Submit"); + color_swapchain.release_image()?; + } - log::trace!("Submit command buffer"); - wgpu_context.queue.submit(iter::once(encoder.finish())); + end_framestream( + #[cfg(feature = "profiling")] + &time, + FrameStreamEndInfo { + xr_frame_state: &xr_frame_state, + resolution, + frame_stream: &mut frame_stream, + xr_context, + xr_space: app_space.space(), + views: &views, + color_swapchain, + }, + ); - #[cfg(feature = "profiling")] - profiling::scope!("Release Swapchain"); - log::trace!("Release swapchain image"); - xr_swapchain.release_image()?; + //XR Input processing + if input_context.is_some() { + #[cfg(feature = "profiling")] + profiling::scope!("Process Inputs"); - // End rendering and submit the images - let rect = openxr::Rect2Di { - offset: openxr::Offset2Di { x: 0, y: 0 }, - extent: openxr::Extent2Di { - width: resolution.width as _, - height: resolution.height as _, - }, - }; - - log::trace!("End frame stream"); - - #[cfg(feature = "profiling")] - { - let predicted_display_time_nanos = - xr_frame_state.predicted_display_time.as_nanos(); - profiling::scope!( - "Show Time Calculation", - format!("{predicted_display_time_nanos}").as_str() - ); - } - if let Err(err) = frame_stream.end( - xr_frame_state.predicted_display_time, - xr_context.blend_mode, - &[&openxr::CompositionLayerProjection::new() - .space(&xr_space) - .views(&[ - openxr::CompositionLayerProjectionView::new() - .pose(views[0].pose) - .fov(views[0].fov) - .sub_image( - openxr::SwapchainSubImage::new() - .swapchain(xr_swapchain) - .image_array_index(0) - .image_rect(rect), - ), - openxr::CompositionLayerProjectionView::new() - .pose(views[1].pose) - .fov(views[1].fov) - .sub_image( - openxr::SwapchainSubImage::new() - .swapchain(xr_swapchain) - .image_array_index(1) - .image_rect(rect), - ), - ])], - ) { - log::error!("Failed to end frame stream: {}", err); - }; - - //XR Input processing - if input_context.is_some() { - #[cfg(feature = "profiling")] - profiling::scope!("Process Inputs"); - - let input_context = input_context - .as_mut() - .context("Cannot borrow input context as mutable")?; - - if input_context - .process_inputs( - &xr_session, - &xr_frame_state, - &xr_reference_space, - &xr_view_space, - ) - .is_ok() - { - if let Some(new_state) = &input_context.input_state { - if new_state.hands_near_head > 0 - && new_state.near_start.elapsed().as_secs() > 3 - { - let should_unlock_horizon = new_state.hands_near_head > 1 - || (new_state.hands_near_head == 1 - && new_state.count_change.elapsed().as_secs() < 1); - - if recenter_request.is_none() { - recenter_request = Some(RecenterRequest { - horizon_locked: !should_unlock_horizon, - delay: 0, - }); - } + let input_context = input_context + .as_mut() + .context("Cannot borrow input context as mutable")?; + + match input_context.process_inputs( + &xr_session, + &xr_frame_state, + app_space.reference_space(), + app_space.view_space(), + ) { + Ok(()) => { + if let Some(new_state) = &input_context.input_state { + if new_state.hands_near_head > 0 + && new_state.near_start.elapsed().as_secs() > 3 + { + let should_unlock_horizon = new_state.hands_near_head > 1 + || (new_state.hands_near_head == 1 + && new_state.count_change.elapsed().as_secs() < 1); + + if recenter_request.is_none() { + recenter_request = Some(RecenterRequest { + horizon_locked: !should_unlock_horizon, + delay: 0, + }); } } } } - - if let Some(recenter_request) = recenter_request.take() { - if let Err(err) = recenter_scene( - &xr_session, - &xr_reference_space, - &xr_view_space, - xr_frame_state.predicted_display_time, - recenter_request.horizon_locked, - recenter_request.delay, - &mut xr_space, - ) { - log::error!("Failed to recenter scene: {}", err); - } + Err(err) => { + log::error!("Failed to process inputs: {}", err); + reset_app_space(&mut app_space, &xr_session, Some(input_context))?; } } + } + if let Some(recenter_request) = recenter_request.take() { #[cfg(feature = "profiling")] - profiling::finish_frame!(); + profiling::scope!("Recenter Scene"); + + if let Err(err) = app_space.recenter( + &xr_session, + xr_frame_state.predicted_display_time, + recenter_request.horizon_locked, + recenter_request.delay, + ) { + log::error!("Failed to recenter scene: {}", err); + } } } // Non-XR Input processing - match tray_state - .lock() - .ok() - .context("Cannot get lock on icon tray state")? - .message - .take() { - Some(TrayMessages::Quit) => { - log::info!("Qutting app manually..."); - break; - } - Some(TrayMessages::Reload) => { - check_loader_invalidation(current_loader, &loaders, &mut screen_invalidated)?; - } - Some(TrayMessages::Recenter(horizon_locked)) => { - recenter_request = Some(RecenterRequest { - horizon_locked: *horizon_locked, - delay: 0, - }); - } - Some(TrayMessages::ToggleSettings(setting)) => match setting { - ToggleSetting::SwapEyes => { - screen_params.swap_eyes = !screen_params.swap_eyes; - screen_invalidated = true; + #[cfg(feature = "profiling")] + profiling::scope!("Interface input update logic"); + match app_state + .lock() + .ok() + .context("Cannot get lock on app state")? + .message + .take() + { + Some(AppCommands::Quit) => { + log::info!("Qutting app manually..."); + break 'render_loop; + } + Some(AppCommands::Reload) => { + current_loader = None; } - ToggleSetting::FlipX => { - screen_params.flip_x = !screen_params.flip_x; - match stereo_mode { - StereoMode::Sbs | StereoMode::FullSbs => { - screen_params.swap_eyes = !screen_params.swap_eyes; + Some(AppCommands::Recenter(horizon_locked)) => { + recenter_request = Some(RecenterRequest { + horizon_locked: *horizon_locked, + delay: 0, + }); + } + Some(AppCommands::ToggleSettings(setting)) => match setting { + ToggleSetting::SwapEyes => { + app_config.swap_eyes = !app_config.swap_eyes; + screen_invalidated = true; + } + ToggleSetting::FlipX => { + app_config.flip_x = !app_config.flip_x; + match stereo_mode { + StereoMode::Sbs | StereoMode::FullSbs => { + app_config.swap_eyes = !app_config.swap_eyes; + } + _ => {} } - _ => {} + screen_invalidated = true; } - screen_invalidated = true; - } - ToggleSetting::FlipY => { - screen_params.flip_y = !screen_params.flip_y; - match stereo_mode { - StereoMode::Tab | StereoMode::FullTab => { - screen_params.swap_eyes = !screen_params.swap_eyes; + ToggleSetting::FlipY => { + app_config.flip_y = !app_config.flip_y; + match stereo_mode { + StereoMode::Tab | StereoMode::FullTab => { + app_config.swap_eyes = !app_config.swap_eyes; + } + _ => {} } - _ => {} + screen_invalidated = true; } + ToggleSetting::AmbientLight => { + app_config.ambient = !app_config.ambient; + screen.change_ambient_mode(app_config.ambient); + screen_invalidated = true; + } + }, + Some(AppCommands::SetStereoMode(stereo_mode)) => { + default_stereo_mode = stereo_mode.clone(); screen_invalidated = true; } - ToggleSetting::AmbientLight => { - screen_params.ambient = !screen_params.ambient; - screen.change_ambient_mode(screen_params.ambient); - screen_invalidated = true; - } - }, - _ => {} + _ => {} + } } if let Some(ConfigContext { @@ -1078,6 +1126,9 @@ fn run( .. }) = config { + #[cfg(feature = "profiling")] + profiling::scope!("File Config Watcher"); + if config_receiver.try_recv().is_ok() { let config = config .as_mut() @@ -1086,20 +1137,180 @@ fn run( if config_changed { if let Some(new_params) = config.last_config.clone() { - screen_params = new_params; - screen.change_scale(screen_params.scale); - screen.change_distance(-screen_params.distance); - screen.change_ambient_mode(screen_params.ambient); + app_config = new_params; + screen.change_scale(app_config.scale); + screen.change_distance(-app_config.distance); + screen.change_ambient_mode(app_config.ambient); screen_invalidated = true; } } } } + + #[cfg(feature = "profiling")] + profiling::finish_frame!(); + } + + Ok(()) +} + +fn reset_app_space( + app_space: &mut AppSpace, + xr_session: &openxr::Session, + input_context: Option<&mut InputContext>, +) -> Result<(), anyhow::Error> { + *app_space = AppSpace::new(xr_session)?; + if let Some(input_context) = input_context { + input_context.reset_space(); + }; + Ok(()) +} + +struct FrameStreamEndInfo<'a> { + xr_frame_state: &'a openxr::FrameState, + resolution: &'a ash::vk::Extent2D, + frame_stream: &'a mut openxr::FrameStream, + xr_context: &'a OpenXRContext, + xr_space: &'a openxr::Space, + views: &'a [openxr::View], + color_swapchain: &'a Swapchain, +} +fn end_framestream( + #[cfg(feature = "profiling")] frame_begin_instant: &std::time::Instant, + frame_stream_end_info: FrameStreamEndInfo<'_>, +) { + let FrameStreamEndInfo { + xr_frame_state, + resolution, + frame_stream, + xr_context, + xr_space, + views, + color_swapchain, + } = frame_stream_end_info; + + log::trace!("End frame stream"); + + // End rendering and submit the images + let rect = openxr::Rect2Di { + offset: openxr::Offset2Di { x: 0, y: 0 }, + extent: openxr::Extent2Di { + width: resolution.width as _, + height: resolution.height as _, + }, + }; + + let proj_views = [ + get_projection_view(0, views, color_swapchain, rect), + get_projection_view(1, views, color_swapchain, rect), + ]; + + { + #[cfg(feature = "profiling")] + let predicted_display_time_nanos = xr_frame_state.predicted_display_time.as_nanos(); + #[cfg(feature = "profiling")] + let actual_duration = std::time::Instant::now() + .duration_since(*frame_begin_instant) + .as_nanos() as i64; + #[cfg(feature = "profiling")] + let prediction_latentcy = + xr_frame_state.predicted_display_period.as_nanos() - actual_duration; + #[cfg(feature = "profiling")] + profiling::scope!( + "End Frame", + format!("Predicted: {predicted_display_time_nanos}, PredictionLatency: {prediction_latentcy}").as_str() + ); + + if let Err(err) = frame_stream.end( + xr_frame_state.predicted_display_time, + xr_context.blend_mode, + &[&openxr::CompositionLayerProjection::new() + .space(xr_space) + .views(&proj_views)], + ) { + log::error!("Failed to end frame stream: {}", err); + }; } +} + +#[cfg_attr(feature = "profiling", profiling::function)] +fn get_projection_view<'a>( + eye_index: usize, + views: &[openxr::View], + color_swapchain: &'a engine::swapchain::Swapchain, + rect: openxr::Rect2Di, +) -> openxr::CompositionLayerProjectionView<'a, openxr::Vulkan> { + openxr::CompositionLayerProjectionView::new() + .pose(views[eye_index].pose) + .fov(views[eye_index].fov) + .sub_image( + openxr::SwapchainSubImage::new() + .swapchain(color_swapchain.internal()) + .image_array_index(eye_index as u32) + .image_rect(rect), + ) +} + +#[cfg_attr(feature = "profiling", profiling::function)] +fn upload_blur_uniforms( + ambient_texture: &RoundRobinTextureBuffer, 3>, + jitter_frame: &mut u32, + temporal_blur_params: &mut TemporalBlurParams, + wgpu_context: &WgpuContext, + temporal_blur_params_buffer: &wgpu::Buffer, +) { + log::trace!("Writing temporal blur uniforms"); + let ambient_texture = &ambient_texture.current().texture; + let resolution = [ + ambient_texture.width() as f32, + ambient_texture.height() as f32, + ]; + *jitter_frame = (*jitter_frame + 1) % AMBIENT_BLUR_TEMPORAL_SAMPLES; + temporal_blur_params.jitter = engine::jitter::get_jitter(*jitter_frame, &resolution); + temporal_blur_params.resolution = resolution; + wgpu_context.queue.write_buffer( + temporal_blur_params_buffer, + 0, + bytemuck::cast_slice(&[temporal_blur_params.uniform()]), + ); +} +#[cfg_attr(feature = "profiling", profiling::function)] +fn upload_camera_uniforms( + views: &[openxr::View], + cameras: &mut [Camera], + camera_uniform: &mut Vec, + wgpu_context: &WgpuContext, + camera_buffer: &wgpu::Buffer, +) -> Result<(), anyhow::Error> { + for (view_idx, view) in views.iter().enumerate() { + let eye = cameras + .get_mut(view_idx) + .context("Cannot borrow camera as mutable")?; + eye.entity.position.x = view.pose.position.x; + eye.entity.position.y = view.pose.position.y; + eye.entity.position.z = view.pose.position.z; + eye.entity.rotation.v.x = view.pose.orientation.x; + eye.entity.rotation.v.y = view.pose.orientation.y; + eye.entity.rotation.v.z = view.pose.orientation.z; + eye.entity.rotation.s = view.pose.orientation.w; + eye.entity.update_matrices(&[]); + eye.update_projection_from_tangents(view.fov); + let camera_uniform = camera_uniform + .get_mut(view_idx) + .context("Cannot borrow camera uniform buffer as mutable")?; + camera_uniform.update_view_proj(eye)?; + } + log::trace!("Write views"); + wgpu_context.queue.write_buffer( + camera_buffer, + 0, + bytemuck::cast_slice(camera_uniform.as_slice()), + ); Ok(()) } +#[cfg_attr(feature = "profiling", profiling::function)] fn get_ambient_texture( screen_texture: &Texture2D, aspect: f32, @@ -1116,10 +1327,9 @@ fn get_ambient_texture( StereoMode::FullSbs => 2, _ => 1, }; - let buffer = RoundRobinTextureBuffer::new( (0..3) - .map(|idx| { + .flat_map(|idx| { screen_texture .as_render_target_with_extent( format!("Ambient Texture {idx}").as_str(), @@ -1129,10 +1339,11 @@ fn get_ambient_texture( * height_multiplier, depth_or_array_layers: screen_texture.texture.depth_or_array_layers(), }, - SWAPCHAIN_COLOR_FORMAT, + SWAPCHAIN_COLOR_FORMAT.to_norm(), + None, &wgpu_context.device, ) - .bind_to_context(wgpu_context, bind_group_layout) + .map(|texture| texture.bind_to_context(wgpu_context, bind_group_layout)) }) .collect::>() .try_into() @@ -1143,44 +1354,7 @@ fn get_ambient_texture( Ok(buffer) } -fn recenter_scene( - xr_session: &openxr::Session, - xr_reference_space: &openxr::Space, - xr_view_space: &openxr::Space, - last_predicted_frame_time: openxr::Time, - horizon_locked: bool, - delay: i64, - xr_space: &mut openxr::Space, -) -> anyhow::Result<()> { - let mut view_location_pose = xr_view_space - .locate( - xr_reference_space, - openxr::Time::from_nanos(last_predicted_frame_time.as_nanos() - delay), - )? - .pose; - let quaternion = - cgmath::Quaternion::from(mint::Quaternion::from(view_location_pose.orientation)); - let forward = cgmath::Vector3::new(0.0, 0.0, 1.0); - let look_dir = quaternion * forward; - let yaw = cgmath::Rad(look_dir.x.atan2(look_dir.z)); - let clean_orientation = if horizon_locked { - cgmath::Quaternion::from_angle_y(yaw) - } else { - let padj = (look_dir.x * look_dir.x + look_dir.z * look_dir.z).sqrt(); - let pitch = -cgmath::Rad(look_dir.y.atan2(padj)); - cgmath::Quaternion::from_angle_y(yaw) * cgmath::Quaternion::from_angle_x(pitch) - }; - view_location_pose.orientation = openxr::Quaternionf { - x: clean_orientation.v.x, - y: clean_orientation.v.y, - z: clean_orientation.v.z, - w: clean_orientation.s, - }; - *xr_space = xr_session.create_reference_space(ReferenceSpaceType::LOCAL, view_location_pose)?; - - Ok(()) -} - +#[cfg_attr(feature = "profiling", profiling::function)] fn check_loader_invalidation( current_loader: Option, loaders: &[Box], @@ -1202,26 +1376,52 @@ fn check_loader_invalidation( Ok(()) } +#[cfg_attr(feature = "profiling", profiling::function)] fn try_to_load_texture( loaders: &mut [Box], wgpu_context: &WgpuContext, -) -> Option<(Texture2D, f32, StereoMode, usize)> { + current_loader: Option, +) -> Option<(Texture2D, f32, Option, usize)> { for (loader_idx, loader) in loaders.iter_mut().enumerate() { - if let Ok(tex_source) = loader.load(&wgpu_context.instance, &wgpu_context.device) { - return Some(( - tex_source.texture, - (tex_source.width as f32 / 2.0) / tex_source.height as f32, - tex_source.stereo_mode, - loader_idx, - )); + if current_loader == Some(loader_idx) { + break; + } + + let loaded_texture = try_loader(loader, wgpu_context, loader_idx); + if loaded_texture.is_some() { + return loaded_texture; } } None } +#[cfg_attr(feature = "profiling", profiling::function)] +fn try_loader( + loader: &mut Box, + wgpu_context: &WgpuContext, + loader_idx: usize, +) -> Option<(Texture2D, f32, Option, usize)> { + if let Ok(tex_source) = loader.load( + &wgpu_context.instance, + &wgpu_context.device, + &wgpu_context.queue, + ) { + let aspect_ratio_multiplier = tex_source + .stereo_mode + .as_ref() + .map(|stereo_mode| stereo_mode.aspect_ratio_multiplier()) + .unwrap_or(1.0); + return Some(( + tex_source.texture, + (tex_source.width as f32 * aspect_ratio_multiplier) / tex_source.height as f32, + tex_source.stereo_mode, + loader_idx, + )); + } + None +} + #[cfg_attr(target_os = "android", ndk_glue::main(backtrace = "full"))] pub fn main() { - if let Err(err) = launch() { - log::error!("VRScreenCap closed unexpectedly with an error: {}", err); - } + launch(); } diff --git a/src/loaders.rs b/src/loaders.rs index 75e35d6..acf775c 100644 --- a/src/loaders.rs +++ b/src/loaders.rs @@ -1,18 +1,27 @@ -use wgpu::{Device, Instance}; +use wgpu::{CommandEncoder, Device, Instance, Queue}; -use crate::engine::texture::{Texture2D, Unbound}; +use crate::engine::texture::{Bound, Texture2D, Unbound}; + +pub mod blank_loader; #[cfg(target_os = "windows")] pub mod katanga_loader; +#[cfg(target_os = "windows")] +pub mod desktop_duplication_loader; + +#[cfg(target_os = "unix")] +pub mod captrs_loader; + pub struct TextureSource { pub texture: Texture2D, pub width: u32, pub height: u32, - pub stereo_mode: StereoMode, + pub stereo_mode: Option, } #[allow(unused)] +#[derive(Clone)] pub enum StereoMode { Mono, Sbs, @@ -21,8 +30,36 @@ pub enum StereoMode { FullTab, } -pub trait Loader { - fn load(&mut self, instance: &Instance, device: &Device) -> anyhow::Result; +impl StereoMode { + pub fn aspect_ratio_multiplier(&self) -> f32 { + match self { + StereoMode::Mono => 1.0, + StereoMode::Sbs => 1.0, + StereoMode::Tab => 1.0, + StereoMode::FullSbs => 0.5, + StereoMode::FullTab => 2.0, + } + } +} +pub trait Loader { + fn load( + &mut self, + instance: &Instance, + device: &Device, + queue: &Queue, + ) -> anyhow::Result; + fn update( + &mut self, + instance: &Instance, + device: &Device, + queue: &Queue, + texture: &Texture2D, + ) -> anyhow::Result<()>; + fn encode_pre_pass( + &self, + encoder: &mut CommandEncoder, + texture: &Texture2D, + ) -> anyhow::Result<()>; fn is_invalid(&self) -> bool; } diff --git a/src/loaders/blank_loader.rs b/src/loaders/blank_loader.rs new file mode 100644 index 0000000..257cf0c --- /dev/null +++ b/src/loaders/blank_loader.rs @@ -0,0 +1,57 @@ +use crate::engine::texture::{Bound, Texture2D, Unbound}; + +use super::Loader; + +#[derive(Default)] +pub struct BlankLoader; + +impl Loader for BlankLoader { + #[cfg_attr(feature = "profiling", profiling::function)] + fn load( + &mut self, + _instance: &wgpu::Instance, + device: &wgpu::Device, + queue: &wgpu::Queue, + ) -> anyhow::Result { + //Load blank texture + let blank_texture = Texture2D::::from_bytes( + device, + queue, + include_bytes!("../../assets/blank_grey.png"), + "Blank", + None, + )?; + + Ok(super::TextureSource { + texture: blank_texture, + width: 1, + height: 1, + stereo_mode: None, + }) + } + + #[cfg_attr(feature = "profiling", profiling::function)] + fn update( + &mut self, + _instance: &wgpu::Instance, + _device: &wgpu::Device, + _queue: &wgpu::Queue, + _texture: &Texture2D, + ) -> anyhow::Result<()> { + Ok(()) + } + + #[cfg_attr(feature = "profiling", profiling::function)] + fn is_invalid(&self) -> bool { + false + } + + #[cfg_attr(feature = "profiling", profiling::function)] + fn encode_pre_pass( + &self, + _encoder: &mut wgpu::CommandEncoder, + _texture: &Texture2D, + ) -> anyhow::Result<()> { + Ok(()) + } +} diff --git a/src/loaders/captrs_loader.rs b/src/loaders/captrs_loader.rs new file mode 100644 index 0000000..4a6ae6c --- /dev/null +++ b/src/loaders/captrs_loader.rs @@ -0,0 +1,123 @@ +use std::time::Duration; + +use anyhow::anyhow; +use wgpu::Queue; + +use crate::engine::texture::{Bound, Texture2D, Unbound}; + +use super::Loader; + +// This is a loader to capture the desktop using the captrs crate. +// It is currently not really performance friendly since the texture gets copied to system memory and then back to the GPU. +pub struct CaptrLoader { + capturer: captrs::Capturer, + screen_index: usize, + geometry: (u32, u32), +} + +impl Loader for CaptrLoader { + #[cfg_attr(feature = "profiling", profiling::function)] + fn load( + &mut self, + _instance: &wgpu::Instance, + device: &wgpu::Device, + _queue: &Queue, + ) -> anyhow::Result { + self.geometry = self.capturer.geometry(); + let width = self.geometry.0; + let height = self.geometry.1; + let texture = device.create_texture(&wgpu::TextureDescriptor { + label: Some(format!("CRS Screen Capture Texture #{}", self.screen_index).as_str()), + size: wgpu::Extent3d { + width, + height, + depth_or_array_layers: 1, + }, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Bgra8Unorm, + view_formats: &[], + usage: wgpu::TextureUsages::TEXTURE_BINDING + | wgpu::TextureUsages::COPY_SRC + | wgpu::TextureUsages::COPY_DST, + }); + let texture = Texture2D::::from_wgpu(device, texture); + + Ok(super::TextureSource { + texture, + width, + height, + stereo_mode: None, + }) + } + + #[cfg_attr(feature = "profiling", profiling::function)] + fn update( + &mut self, + _instance: &wgpu::Instance, + _device: &wgpu::Device, + queue: &Queue, + texture: &Texture2D, + ) -> anyhow::Result<()> { + let capture_result = self.capturer.capture_store_frame(); + + if let Err(err) = capture_result { + match err { + captrs::CaptureError::Timeout => { + return Ok(()); + } + _ => { + return Err(anyhow!("Failed to capture frame with error {:?}", err)); + } + } + } + + if let Some(frame) = self.capturer.get_stored_frame() { + // FIXME: captrs returns a BGRA8 struct, if this has alignement bytes the following code will collect garbage data + let data = + unsafe { std::slice::from_raw_parts(frame.as_ptr() as *const u8, frame.len() * 4) }; + queue.write_texture( + texture.texture.as_image_copy(), + data, + wgpu::ImageDataLayout { + offset: 0, + bytes_per_row: Some(4 * self.geometry.0), + rows_per_image: Some(self.geometry.1), + }, + texture.texture.size(), + ); + Ok(()) + } else { + Err(anyhow!("Failed to get stored frame")) + } + } + + #[cfg_attr(feature = "profiling", profiling::function)] + fn is_invalid(&self) -> bool { + let geometry = self.capturer.geometry(); + geometry.0 != self.geometry.0 || geometry.1 != self.geometry.1 + } + + #[cfg_attr(feature = "profiling", profiling::function)] + fn encode_pre_pass( + &self, + _encoder: &mut wgpu::CommandEncoder, + _texture: &Texture2D, + ) -> anyhow::Result<()> { + Ok(()) + } +} + +impl CaptrLoader { + #[cfg_attr(feature = "profiling", profiling::function)] + pub fn new(screen_index: usize) -> anyhow::Result { + let capturer = captrs::Capturer::new_with_timeout(screen_index, Duration::from_nanos(0)) + .map_err(|err| anyhow!(err))?; + Ok(Self { + screen_index, + capturer, + geometry: (0, 0), + }) + } +} diff --git a/src/loaders/desktop_duplication_loader.rs b/src/loaders/desktop_duplication_loader.rs new file mode 100644 index 0000000..20f38d9 --- /dev/null +++ b/src/loaders/desktop_duplication_loader.rs @@ -0,0 +1,189 @@ +use windows::Win32::Foundation::HANDLE; + +use anyhow::{anyhow, Context}; +use wgpu::Queue; +use win_desktop_duplication::{ + devices::AdapterFactory, outputs::Display, texture::ColorFormat, DesktopDuplicationApi, +}; +use windows::core::ComInterface; +use windows::Win32::Graphics::Dxgi::IDXGIResource; + +use crate::{ + engine::{ + formats::InternalColorFormat, + texture::{Bound, Texture2D}, + }, + macros::auto_map, + utils::external_texture::{ExternalApi, ExternalTextureInfo}, +}; + +use super::Loader; + +pub struct DesktopDuplicationLoader { + screen_index: usize, + output: Display, + capturer: DesktopDuplicationApi, + current_handle: Option, + resolution: Option<(u32, u32)>, + invalid: bool, +} + +impl Loader for DesktopDuplicationLoader { + #[cfg_attr(feature = "profiling", profiling::function)] + fn load( + &mut self, + _instance: &wgpu::Instance, + device: &wgpu::Device, + _queue: &Queue, + ) -> anyhow::Result { + let display_mode = self.output.get_current_display_mode().map_err(|err| { + anyhow!( + "Failed to get current display mode for screen {}: {:?}", + self.screen_index, + err + ) + })?; + + let resolution = (display_mode.width, display_mode.height); + let width = resolution.0; + let height = resolution.1; + + let d3d_texture = self + .capturer + .acquire_next_frame_now() + .map_err(|err| anyhow!("Error acquiring desktop duplication frame {:?}", err))?; + + let texture_desc = d3d_texture.desc(); + let resource: IDXGIResource = d3d_texture.as_raw_ref().cast()?; + let handle = unsafe { resource.GetSharedHandle() }?; + + self.current_handle = Some(handle); + + let external_texture_info = ExternalTextureInfo { + external_api: ExternalApi::D3D11, + width: texture_desc.width, + height: texture_desc.height, + array_size: 1u32, + sample_count: 1u32, + mip_levels: 1u32, + format: texture_desc.format.try_into()?, + actual_handle: handle.0 as usize, + }; + + let screen_format = external_texture_info.format; + let screen_norm_format = screen_format.to_norm(); + let view_formats = if screen_norm_format != screen_format { + Some(screen_norm_format) + } else { + None + }; + + let texture = external_texture_info + .map_as_wgpu_texture( + format!("DD Screen Capture Texture #{}", self.screen_index).as_str(), + device, + view_formats, + ) + .context("Cannot map desktop duplication output to WGPU texture")?; + + self.resolution = Some(resolution); + Ok(super::TextureSource { + texture, + width, + height, + stereo_mode: None, + }) + } + + #[cfg_attr(feature = "profiling", profiling::function)] + fn update( + &mut self, + _instance: &wgpu::Instance, + _device: &wgpu::Device, + _queue: &Queue, + _texture: &Texture2D, + ) -> anyhow::Result<()> { + let d3d_texture = self + .capturer + .acquire_next_frame_now() + .map_err(|err| anyhow!("Error acquiring desktop duplication frame {:?}", err))?; + let resource: IDXGIResource = d3d_texture.as_raw_ref().cast()?; + let handle = unsafe { resource.GetSharedHandle() }?; + + if let Some(current_handle) = self.current_handle { + if current_handle == handle { + return Ok(()); + } + } + + self.invalid = true; + Ok(()) + } + + #[cfg_attr(feature = "profiling", profiling::function)] + fn is_invalid(&self) -> bool { + let display_mode = self.output.get_current_display_mode(); + + if self.resolution.is_none() { + return true; + } + + let (width, height) = self.resolution.unwrap(); + if let Ok(display_mode) = display_mode { + return display_mode.width != width || display_mode.height != height || self.invalid; + } + + true + } + + #[cfg_attr(feature = "profiling", profiling::function)] + fn encode_pre_pass( + &self, + _encoder: &mut wgpu::CommandEncoder, + _texture: &Texture2D, + ) -> anyhow::Result<()> { + Ok(()) + } +} + +impl DesktopDuplicationLoader { + #[cfg_attr(feature = "profiling", profiling::function)] + pub fn new(screen_index: usize) -> anyhow::Result { + win_desktop_duplication::set_process_dpi_awareness(); + win_desktop_duplication::co_init(); + + let adapter = AdapterFactory::new() + .get_adapter_by_idx(0) + .context("Failed to get adapter")?; + let output = adapter + .get_display_by_idx(screen_index as u32) + .context("Failed to get display")?; + Ok(Self { + screen_index, + output: output.clone(), + current_handle: None, + capturer: DesktopDuplicationApi::new(adapter, output).map_err(|err| { + anyhow!( + "Failed to access desktop duplication api with error {:?}", + err + ) + })?, + resolution: None, + invalid: false, + }) + } +} + +#[cfg(target_os = "windows")] +auto_map!(InternalColorFormat ColorFormat { + (InternalColorFormat::Rgba8Unorm, ColorFormat::ARGB8UNorm), + (InternalColorFormat::Bgra8Unorm, ColorFormat::BGRA8UNorm), //typo in the library + (InternalColorFormat::Ayuv, ColorFormat::AYUV), + (InternalColorFormat::R8Unorm, ColorFormat::YUV444), + (InternalColorFormat::R16Unorm, ColorFormat::YUV444_10bit), + (InternalColorFormat::Nv12, ColorFormat::NV12), + (InternalColorFormat::Rgba16Float, ColorFormat::ARGB16Float), + (InternalColorFormat::Rgb10a2Unorm, ColorFormat::ARGB10UNorm), + (InternalColorFormat::Y410, ColorFormat::Y410), + (InternalColorFormat::P010, ColorFormat::YUV420_10bit) +}); diff --git a/src/loaders/katanga_loader.rs b/src/loaders/katanga_loader.rs index 64255cc..205d035 100644 --- a/src/loaders/katanga_loader.rs +++ b/src/loaders/katanga_loader.rs @@ -1,300 +1,315 @@ use anyhow::{bail, Context}; -use ash::vk::{self, ImageCreateInfo}; -use wgpu::{Device, Instance, TextureFormat}; -use wgpu_hal::{api::Vulkan, MemoryFlags, TextureDescriptor, TextureUses}; +use ash::vk; +use wgpu::{Device, Instance, Queue}; use windows::{ - core::s, - core::w, + core::{s, w, PCWSTR}, Win32::{ Foundation::{CloseHandle, HANDLE}, Graphics::{ Direct3D::D3D_DRIVER_TYPE_HARDWARE, Direct3D11::{ - D3D11CreateDevice, ID3D11Texture2D, D3D11_CREATE_DEVICE_FLAG, D3D11_SDK_VERSION, - D3D11_TEXTURE2D_DESC, + D3D11CreateDevice, ID3D11Device, ID3D11DeviceContext, ID3D11Texture2D, + D3D11_CREATE_DEVICE_FLAG, D3D11_SDK_VERSION, D3D11_TEXTURE2D_DESC, }, Direct3D12::{D3D12CreateDevice, ID3D12Device, ID3D12Resource}, }, System::Memory::{ - MapViewOfFile, OpenFileMappingA, UnmapViewOfFile, FILE_MAP_ALL_ACCESS, - MEMORYMAPPEDVIEW_HANDLE, + MapViewOfFile, OpenFileMappingA, UnmapViewOfFile, FILE_MAP_READ, + MEMORY_MAPPED_VIEW_ADDRESS, }, }, }; use crate::{ - conversions::{map_texture_format, unmap_texture_format, vulkan_image_to_texture}, - engine::texture::{Texture2D, Unbound}, + engine::{ + formats::InternalColorFormat, + texture::{Bound, Texture2D}, + }, + loaders::StereoMode, + utils::external_texture::{ExternalApi, ExternalTextureInfo}, }; use super::{Loader, TextureSource}; -#[derive(Default)] pub struct KatangaLoaderContext { - katanga_file_handle: HANDLE, - katanga_file_mapping: MEMORYMAPPEDVIEW_HANDLE, + katanga_file_handle: Option, + katanga_file_mapping: Option, current_address: usize, + d3d11: Option, + d3d12: Option, } -impl Loader for KatangaLoaderContext { - fn load(&mut self, _instance: &Instance, device: &Device) -> anyhow::Result { - self.katanga_file_handle = unsafe { - OpenFileMappingA(FILE_MAP_ALL_ACCESS.0, false, s!("Local\\KatangaMappedFile"))? +impl KatangaLoaderContext { + fn unmap(&mut self) { + if let Some(file_mapping) = self.katanga_file_mapping.take() { + if let Err(err) = unsafe { UnmapViewOfFile(file_mapping) } { + log::error!("Failed to unmap file view: {:?}", err); + } + } + + if let Some(katanga_handle) = self.katanga_file_handle.take() { + if !katanga_handle.is_invalid() { + if let Err(err) = unsafe { CloseHandle(katanga_handle) } { + log::error!("Failed to close file mapping: {:?}", err); + } + } + } + } + + fn map_katanga_file(&mut self) -> anyhow::Result<()> { + if self.katanga_file_handle.is_some() + && !self.katanga_file_handle.as_ref().unwrap().is_invalid() + && self.katanga_file_mapping.is_some() + { + return Ok(()); + } + + self.unmap(); + + self.katanga_file_handle = match unsafe { + OpenFileMappingA(FILE_MAP_READ.0, false, s!("Local\\KatangaMappedFile")) + } { + Ok(handle) => Some(handle), + Err(_) => { + self.unmap(); + bail!("Cannot open file mapping!") + } }; - log::info!("Handle: {:?}", self.katanga_file_handle); + log::trace!("Handle: {:?}", self.katanga_file_handle); - self.katanga_file_mapping = unsafe { + self.katanga_file_mapping = Some(unsafe { MapViewOfFile( - self.katanga_file_handle, - FILE_MAP_ALL_ACCESS, + self.katanga_file_handle.unwrap(), + FILE_MAP_READ, 0, 0, std::mem::size_of::(), + ) + }); + + if self.katanga_file_mapping.unwrap().Value.is_null() { + self.unmap(); + bail!("Cannot map file view!"); + } + + Ok(()) + } +} + +impl Default for KatangaLoaderContext { + fn default() -> Self { + Self { + d3d11: D3D11Context::new().ok(), + d3d12: D3D12Context::new().ok(), + katanga_file_handle: None, + katanga_file_mapping: None, + current_address: 0, + } + } +} + +struct D3D11Context { + device: ID3D11Device, + _device_context: ID3D11DeviceContext, +} + +impl D3D11Context { + #[cfg_attr(feature = "profiling", profiling::function)] + pub fn new() -> anyhow::Result { + let mut device = None; + let mut device_context = None; + unsafe { + D3D11CreateDevice( + None, + D3D_DRIVER_TYPE_HARDWARE, + None, + D3D11_CREATE_DEVICE_FLAG(0), + None, + D3D11_SDK_VERSION, + Some(&mut device), + None, + Some(&mut device_context), )? }; - if self.katanga_file_mapping.is_invalid() { - bail!("Cannot map file!"); - } + Ok(Self { + device: device.context("Failed to create D3D11 device")?, + _device_context: device_context.context("Failed to create D3D11 device context")?, + }) + } + + #[cfg_attr(feature = "profiling", profiling::function)] + fn get_d3d11_texture_info(&self, handle: HANDLE) -> anyhow::Result { + let mut d3d11_texture: Option = None; + unsafe { self.device.OpenSharedResource(handle, &mut d3d11_texture) }?; + let d3d11_texture = d3d11_texture.context("Failed to open shared DX11 texture")?; + let mut texture_desc = D3D11_TEXTURE2D_DESC::default(); + unsafe { d3d11_texture.GetDesc(&mut texture_desc) }; + + let format: InternalColorFormat = texture_desc.Format.try_into()?; + log::info!("Got texture from DX11 with format {:?}", format); + + Ok(ExternalTextureInfo { + external_api: ExternalApi::D3D11, + width: texture_desc.Width, + height: texture_desc.Height, + array_size: texture_desc.ArraySize, + sample_count: texture_desc.SampleDesc.Count, + mip_levels: texture_desc.MipLevels, + format, + actual_handle: handle.0 as usize, + }) + } +} + +struct D3D12Context { + device: ID3D12Device, +} - let address = unsafe { *(self.katanga_file_mapping.0 as *mut usize) }; +impl D3D12Context { + pub fn new() -> anyhow::Result { + let mut d3d12_device: Option = None; + unsafe { + D3D12CreateDevice( + None, + windows::Win32::Graphics::Direct3D::D3D_FEATURE_LEVEL_12_0, + &mut d3d12_device, + ) + }?; + + let d3d12_device = d3d12_device.context("DX12 device not initialized")?; + + Ok(Self { + device: d3d12_device, + }) + } + + #[cfg_attr(feature = "profiling", profiling::function)] + fn get_d3d12_named_texture_info( + &self, + texture_name: PCWSTR, + ) -> anyhow::Result { + let named_handle = unsafe { + self.device.OpenSharedHandleByName(texture_name, 0x10000000) //GENERIC_ALL + }?; + + let mut d3d12_texture: Option = None; + unsafe { + self.device + .OpenSharedHandle(named_handle, &mut d3d12_texture) + }?; + let d3d12_texture = d3d12_texture.context("Failed to open shared DX12 texture")?; + + let tex_info = unsafe { d3d12_texture.GetDesc() }; + + let format: InternalColorFormat = tex_info.Format.try_into()?; + log::info!("Got texture from DX12 with format {:?}", format); + + Ok(ExternalTextureInfo { + external_api: ExternalApi::D3D12, + width: tex_info.Width as u32, + height: tex_info.Height, + array_size: tex_info.DepthOrArraySize as u32, + sample_count: tex_info.SampleDesc.Count, + mip_levels: tex_info.MipLevels as u32, + format, + actual_handle: named_handle.0 as usize, + }) + } +} + +impl Loader for KatangaLoaderContext { + #[cfg_attr(feature = "profiling", profiling::function)] + fn load( + &mut self, + _instance: &Instance, + device: &Device, + _queue: &Queue, + ) -> anyhow::Result { + self.map_katanga_file()?; + + let address = unsafe { *(self.katanga_file_mapping.as_ref().unwrap().Value as *mut usize) }; self.current_address = address; let tex_handle = self.current_address as vk::HANDLE; log::info!("{:#01x}", tex_handle as usize); - let tex_info = get_d3d11_texture_info(HANDLE(tex_handle as isize)).or_else(|err| { - log::warn!("Not a D3D11Texture {}", err); - get_d3d12_texture_info().map_err(|err| { - log::warn!("Not a D3D12Texture {}", err); - err - }) - })?; + let tex_info = self + .d3d11 + .as_ref() + .map(|d3d11| d3d11.get_d3d11_texture_info(HANDLE(tex_handle as isize))) + .unwrap_or(Err(anyhow::anyhow!("No D3D11 device found"))) + .or_else(|_| { + self.d3d12 + .as_ref() + .map(|d3d12| d3d12.get_d3d12_named_texture_info(w!("DX12VRStream"))) + .unwrap_or(Err(anyhow::anyhow!("No D3D11 device found"))) + })?; - let tex_handle = tex_info.actual_handle as vk::HANDLE; if tex_info.actual_handle != self.current_address { log::info!("Actual Handle: {:?}", self.katanga_file_handle); } - let vk_format = map_texture_format(tex_info.format); - - log::info!("Mapped DXGI format to {:?}", tex_info.format); - log::info!("Mapped WGPU format to Vulkan {:?}", vk_format); - - let raw_image: Option> = unsafe { - device.as_hal::(|device| { - device.map(|device| { - let raw_device = device.raw_device(); - //let raw_phys_device = device.raw_physical_device(); - let handle_type = match tex_info.external_api { - ExternalApi::D3D11 => { - vk::ExternalMemoryHandleTypeFlags::D3D11_TEXTURE_KMT_KHR - } - ExternalApi::D3D12 => vk::ExternalMemoryHandleTypeFlags::D3D12_RESOURCE_KHR, - }; - - let mut import_memory_info = vk::ImportMemoryWin32HandleInfoKHR::builder() - .handle_type(handle_type) - .handle(tex_handle); - - let allocate_info = vk::MemoryAllocateInfo::builder() - .push_next(&mut import_memory_info) - .memory_type_index(0); - - let allocated_memory = raw_device.allocate_memory(&allocate_info, None)?; - - let mut ext_create_info = - vk::ExternalMemoryImageCreateInfo::builder().handle_types(handle_type); - - let image_create_info = ImageCreateInfo::builder() - .push_next(&mut ext_create_info) - //.push_next(&mut dedicated_creation_info) - .image_type(vk::ImageType::TYPE_2D) - .format(vk_format) - .extent(vk::Extent3D { - width: tex_info.width, - height: tex_info.height, - depth: tex_info.array_size, - }) - .mip_levels(tex_info.mip_levels) - .array_layers(tex_info.array_size) - .samples(vk::SampleCountFlags::TYPE_1) - .tiling(vk::ImageTiling::OPTIMAL) - .usage(vk::ImageUsageFlags::TRANSFER_SRC | vk::ImageUsageFlags::SAMPLED) - .sharing_mode(vk::SharingMode::CONCURRENT); - - let raw_image = raw_device.create_image(&image_create_info, None)?; - - raw_device.bind_image_memory(raw_image, allocated_memory, 0)?; - - Ok(raw_image) - }) - }) + let screen_format = tex_info.format; + let screen_norm_format = screen_format.to_norm(); + let view_formats = if screen_norm_format != screen_format { + Some(screen_norm_format) + } else { + None }; - if let Some(Ok(raw_image)) = raw_image { - let texture = vulkan_image_to_texture( - device, - raw_image, - wgpu::TextureDescriptor { - label: "KatangaStream".into(), - size: wgpu::Extent3d { - width: tex_info.width, - height: tex_info.height, - depth_or_array_layers: tex_info.array_size, - }, - mip_level_count: tex_info.mip_levels, - sample_count: tex_info.sample_count, - dimension: wgpu::TextureDimension::D2, - format: tex_info.format, - view_formats: &[], - usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_SRC, - }, - TextureDescriptor { - label: "KatangaStream".into(), - size: wgpu::Extent3d { - width: tex_info.width, - height: tex_info.height, - depth_or_array_layers: tex_info.array_size, - }, - mip_level_count: tex_info.mip_levels, - sample_count: tex_info.sample_count, - dimension: wgpu::TextureDimension::D2, - format: tex_info.format, - view_formats: vec![], - usage: TextureUses::RESOURCE | TextureUses::COPY_SRC, - memory_flags: MemoryFlags::empty(), - }, - ); - - return Ok(TextureSource { - texture: Texture2D::::from_wgpu(device, texture), - width: tex_info.width, - height: tex_info.height, - stereo_mode: crate::loaders::StereoMode::FullSbs, - }); - } + let internal_texture = + tex_info.map_as_wgpu_texture("KatangaStream", device, view_formats)?; - bail!("Cannot open shared texture!") + Ok(TextureSource { + texture: internal_texture, + width: tex_info.width, + height: tex_info.height, + stereo_mode: Some(StereoMode::FullSbs), + }) } + #[cfg_attr(feature = "profiling", profiling::function)] fn is_invalid(&self) -> bool { - let address = unsafe { *(self.katanga_file_mapping.0 as *mut usize) }; - self.current_address != address - } -} - -impl Drop for KatangaLoaderContext { - fn drop(&mut self) { - log::info!("Dropping KatangaLoaderContext"); - - if !self.katanga_file_mapping.is_invalid() - && unsafe { bool::from(UnmapViewOfFile(self.katanga_file_mapping)) } + if self.katanga_file_mapping.is_none() + || self.katanga_file_handle.is_none() + || self.katanga_file_handle.as_ref().unwrap().is_invalid() + || self.katanga_file_mapping.as_ref().unwrap().Value.is_null() { - log::info!("Unmapped file!"); + return true; } - if !self.katanga_file_handle.is_invalid() - && unsafe { bool::from(CloseHandle(self.katanga_file_handle)) } - { - log::info!("Closed handle!"); - } + let address = unsafe { *(self.katanga_file_mapping.as_ref().unwrap().Value as *mut usize) }; + self.current_address != address } -} - -struct ExternalTextureInfo { - external_api: ExternalApi, - width: u32, - height: u32, - array_size: u32, - sample_count: u32, - mip_levels: u32, - format: TextureFormat, - actual_handle: usize, -} -enum ExternalApi { - D3D11, - D3D12, -} + // No update needed for Katanga + #[cfg_attr(feature = "profiling", profiling::function)] + fn update( + &mut self, + _instance: &Instance, + _device: &Device, + _queue: &Queue, + _texture: &Texture2D, + ) -> anyhow::Result<()> { + self.unmap(); + self.map_katanga_file()?; + Ok(()) + } -fn get_d3d11_texture_info(handle: HANDLE) -> anyhow::Result { - let mut d3d11_device = None; - let mut d3d11_device_context = None; - unsafe { - D3D11CreateDevice( - None, - D3D_DRIVER_TYPE_HARDWARE, - None, - D3D11_CREATE_DEVICE_FLAG(0), - None, - D3D11_SDK_VERSION, - Some(&mut d3d11_device), - None, - Some(&mut d3d11_device_context), - )? - }; - let mut d3d11_texture: Option = None; - unsafe { - d3d11_device - .as_ref() - .context("DX11 device not initialized")? - .OpenSharedResource(handle, &mut d3d11_texture) - }?; - let d3d11_texture = d3d11_texture.context("Failed to open shared DX11 texture")?; - let mut texture_desc = D3D11_TEXTURE2D_DESC::default(); - unsafe { d3d11_texture.GetDesc(&mut texture_desc) }; - - log::info!( - "Got texture from DX11 with format {:?}", - texture_desc.Format - ); - - Ok(ExternalTextureInfo { - external_api: ExternalApi::D3D11, - width: texture_desc.Width, - height: texture_desc.Height, - array_size: texture_desc.ArraySize, - sample_count: texture_desc.SampleDesc.Count, - mip_levels: texture_desc.MipLevels, - format: unmap_texture_format(texture_desc.Format), - actual_handle: handle.0 as usize, - }) + #[cfg_attr(feature = "profiling", profiling::function)] + fn encode_pre_pass( + &self, + _encoder: &mut wgpu::CommandEncoder, + _texture: &Texture2D, + ) -> anyhow::Result<()> { + Ok(()) + } } -fn get_d3d12_texture_info() -> anyhow::Result { - let mut d3d12_device: Option = None; - unsafe { - D3D12CreateDevice( - None, - windows::Win32::Graphics::Direct3D::D3D_FEATURE_LEVEL_12_0, - &mut d3d12_device, - ) - }?; - - let d3d12_device = d3d12_device - .as_ref() - .context("DX12 device not initialized")?; - - let named_handle = unsafe { - d3d12_device.OpenSharedHandleByName(w!("DX12VRStream"), 0x10000000) //GENERIC_ALL - }?; - - let mut d3d12_texture: Option = None; - unsafe { d3d12_device.OpenSharedHandle(named_handle, &mut d3d12_texture) }?; - let d3d12_texture = d3d12_texture.context("Failed to open shared DX12 texture")?; - - let tex_info = unsafe { d3d12_texture.GetDesc() }; - - log::info!("Got texture from DX12 with format {:?}", tex_info.Format); - - Ok(ExternalTextureInfo { - external_api: ExternalApi::D3D12, - width: tex_info.Width as u32, - height: tex_info.Height, - array_size: tex_info.DepthOrArraySize as u32, - sample_count: tex_info.SampleDesc.Count, - mip_levels: tex_info.MipLevels as u32, - format: unmap_texture_format(tex_info.Format), - actual_handle: named_handle.0 as usize, - }) +impl Drop for KatangaLoaderContext { + #[cfg_attr(feature = "profiling", profiling::function)] + fn drop(&mut self) { + log::info!("Dropping KatangaLoaderContext"); + self.unmap(); + } } diff --git a/src/macros.rs b/src/macros.rs new file mode 100644 index 0000000..4d52cf0 --- /dev/null +++ b/src/macros.rs @@ -0,0 +1,36 @@ +macro_rules! auto_map { + ($t1:ident $t2:ident {$(($value1:path,$value2:path)), +}) => { + impl TryFrom<$t1> for $t2 { + type Error = anyhow::Error; + #[cfg_attr(feature = "profiling", profiling::function)] + fn try_from(f: $t1) -> Result<$t2, anyhow::Error> { + #[allow(unreachable_patterns)] + match f { + $( $value1 => { + Ok($value2) + } )* + _ => { + anyhow::bail!("Failed to map {:?} to {:?}", f, stringify!($t1)) + } + } + } + } + + impl TryFrom<$t2> for $t1 { + type Error = anyhow::Error; + #[cfg_attr(feature = "profiling", profiling::function)] + fn try_from(f: $t2) -> Result<$t1, anyhow::Error> { + #[allow(unreachable_patterns)] + match f { + $( $value2 => { + Ok($value1) + } )* + _ => { + anyhow::bail!("Failed to map {:?} to {:?}", f, stringify!($t2)) + } + } + } + } + }; +} +pub(crate) use auto_map; diff --git a/src/main.rs b/src/main.rs index beea26c..9850027 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,5 @@ #![windows_subsystem = "windows"] -use vr_screen_cap_core::launch; pub fn main() { - if let Err(err) = launch() { - log::error!("VRScreenCap closed unexpectedly with an error: {}", err); - } + vr_screen_cap_core::launch(); } diff --git a/src/shader.wgsl b/src/shader.wgsl index 7e5c233..1a78b24 100644 --- a/src/shader.wgsl +++ b/src/shader.wgsl @@ -16,6 +16,8 @@ struct ScreenParams { aspect_ratio: f32, screen_width: u32, ambient_width: u32, + stereo_x: f32, // 0.0 = disabled, 1.0 = enabled + stereo_y: f32, // 0.0 = disabled, 1.0 = enabled }; @group(1) @binding(0) @@ -57,8 +59,11 @@ var t_diffuse: texture_2d; var s_diffuse: sampler; fn uv_to_stereo_uv(view_index: i32, uv: vec2) -> vec2 { - let x_offset = abs(f32(view_index) - screen_params.eye_offset) / 2.0; - return vec2(abs(uv.x - screen_params.x_offset) / 2.0 + x_offset, abs(uv.y - screen_params.y_offset)); + let x_divider = 2.0 - (1.0 - screen_params.stereo_x); + let y_divider = 2.0 - (1.0 - screen_params.stereo_y); + let x_offset = (abs(f32(view_index) - screen_params.eye_offset) / 2.0) * screen_params.stereo_x; + let y_offset = (abs(f32(view_index) - screen_params.eye_offset) / 2.0) * screen_params.stereo_y; + return vec2((abs(uv.x - screen_params.x_offset) / x_divider) + x_offset, (abs(uv.y - screen_params.y_offset) / y_divider) + y_offset); } @fragment @@ -103,18 +108,19 @@ fn weighted9_sample(vstep: f32, hstep: f32, } @fragment -fn vignette_fs_main(in: VertexOutput, @builtin(view_index) view_index: i32) -> @location(0) vec4 { +fn vignette_fs_main(in: VertexOutput) -> @location(0) vec4 { let clamped_text_coords = clamp(in.tex_coords, vec2(0.0), vec2(1.0)) - vec2(0.5); let dist = length(clamped_text_coords); let vig = 1.0 - smoothstep(0.35, 0.5, dist); let hstep = 1.0 / f32(screen_params.ambient_width); let vstep = 1.0 / (f32(screen_params.ambient_width) * screen_params.aspect_ratio); return vec4(weighted9_sample(hstep, vstep, - //0.0625, 0.125, 0.0625, - //0.125, 0.25, 0.125, - //0.0625, 0.125, 0.0625, - 0.1111111111111111, 0.1111111111111111, 0.1111111111111111, - 0.1111111111111111, 0.1111111111111111, 0.1111111111111111, - 0.1111111111111111, 0.1111111111111111, 0.1111111111111111, - t_diffuse, s_diffuse, uv_to_stereo_uv(view_index, in.tex_coords)).rgb * vig, 1.0); + 0.0625, 0.125, 0.0625, + 0.125, 0.25, 0.125, + 0.0625, 0.125, 0.0625, + //0.1111111111111111, 0.1111111111111111, 0.1111111111111111, + //0.1111111111111111, 0.1111111111111111, 0.1111111111111111, + //0.1111111111111111, 0.1111111111111111, 0.1111111111111111, + t_diffuse, s_diffuse, uv_to_stereo_uv(0, in.tex_coords)).rgb * vig, 1.0); + // ^ forced mono to left eye } \ No newline at end of file diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..5bb4bad --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,9 @@ +pub mod commands; +pub mod external_texture; +#[cfg(not(target_os = "android"))] +pub mod logging; +#[cfg(not(any(target_os = "android", target_os = "linux")))] +pub mod tray; + +#[cfg(not(feature = "dist"))] +pub mod validation; diff --git a/src/utils/commands.rs b/src/utils/commands.rs new file mode 100644 index 0000000..faf7a24 --- /dev/null +++ b/src/utils/commands.rs @@ -0,0 +1,54 @@ +use std::sync::{Arc, Mutex}; + +use tray_item::TrayItem; + +use crate::loaders::StereoMode; + +use super::tray; + +#[derive(Clone)] +pub(crate) enum AppCommands { + Quit, + Reload, + Recenter(bool), + ToggleSettings(ToggleSetting), + SetStereoMode(StereoMode), +} + +#[derive(Clone)] +pub(crate) enum ToggleSetting { + FlipX, + FlipY, + SwapEyes, + AmbientLight, +} + +pub(crate) struct AppContext { + pub state: Arc>, + #[cfg(not(target_os = "android"))] + _tray: TrayItem, +} + +pub(crate) struct AppState { + pub message: Option<&'static AppCommands>, +} + +pub(crate) struct RecenterRequest { + pub delay: i64, + pub horizon_locked: bool, +} + +impl AppContext { + pub fn new() -> anyhow::Result { + let state = Arc::new(Mutex::new(AppState { message: None })); + + #[cfg(not(target_os = "android"))] + let tray = tray::build_tray(&state)?; + + Ok(Self { + state, + #[cfg(not(target_os = "android"))] + _tray: tray, + }) + } +} diff --git a/src/utils/external_texture.rs b/src/utils/external_texture.rs new file mode 100644 index 0000000..013e3f8 --- /dev/null +++ b/src/utils/external_texture.rs @@ -0,0 +1,138 @@ +use anyhow::Context; +use ash::vk::{self, ImageCreateInfo}; +use wgpu::{Device, TextureFormat}; +use wgpu_hal::{api::Vulkan, MemoryFlags, TextureDescriptor, TextureUses}; + +use crate::{ + conversions::{build_view_formats, vulkan_image_to_texture}, + engine::{ + formats::InternalColorFormat, + texture::{Texture2D, Unbound}, + }, +}; + +pub(crate) struct ExternalTextureInfo { + pub(crate) external_api: ExternalApi, + pub(crate) width: u32, + pub(crate) height: u32, + pub(crate) array_size: u32, + pub(crate) sample_count: u32, + pub(crate) mip_levels: u32, + pub(crate) format: InternalColorFormat, + pub(crate) actual_handle: usize, +} + +pub(crate) enum ExternalApi { + D3D11, + D3D12, +} + +impl ExternalTextureInfo { + #[cfg_attr(feature = "profiling", profiling::function)] + pub(crate) fn map_as_wgpu_texture( + &self, + label: &str, + device: &Device, + view_format: Option, + ) -> anyhow::Result> { + let tex_handle = self.actual_handle as vk::HANDLE; + let vk_format = self.format.try_into()?; + let raw_image: Option> = unsafe { + device.as_hal::(|device| { + device.map(|device| { + let raw_device = device.raw_device(); + //let raw_phys_device = device.raw_physical_device(); + let handle_type = match self.external_api { + ExternalApi::D3D11 => { + vk::ExternalMemoryHandleTypeFlags::D3D11_TEXTURE_KMT_KHR + } + ExternalApi::D3D12 => vk::ExternalMemoryHandleTypeFlags::D3D12_RESOURCE_KHR, + }; + + let mut ext_create_info = + vk::ExternalMemoryImageCreateInfo::builder().handle_types(handle_type); + + let image_create_info = ImageCreateInfo::builder() + .push_next(&mut ext_create_info) + //.push_next(&mut dedicated_creation_info) + .image_type(vk::ImageType::TYPE_2D) + .format(vk_format) + .extent(vk::Extent3D { + width: self.width, + height: self.height, + depth: self.array_size, + }) + .mip_levels(self.mip_levels) + .array_layers(self.array_size) + .samples(vk::SampleCountFlags::TYPE_1) + .tiling(vk::ImageTiling::OPTIMAL) + .usage(vk::ImageUsageFlags::TRANSFER_SRC | vk::ImageUsageFlags::SAMPLED) + .sharing_mode(vk::SharingMode::EXCLUSIVE); + + let raw_image = raw_device.create_image(&image_create_info, None)?; + let img_requirements = raw_device.get_image_memory_requirements(raw_image); + + let mut import_memory_info = vk::ImportMemoryWin32HandleInfoKHR::builder() + .handle_type(handle_type) + .handle(tex_handle); + + let allocate_info = vk::MemoryAllocateInfo::builder() + .push_next(&mut import_memory_info) + .allocation_size(img_requirements.size) + .memory_type_index(0); + + let allocated_memory = raw_device.allocate_memory(&allocate_info, None)?; + raw_device.bind_image_memory(raw_image, allocated_memory, 0)?; + + Ok(raw_image) + }) + }) + }; + + let view_formats = build_view_formats(view_format)?; + let raw_image = raw_image + .context("Failed to get hal device")? + .context("Failed to map external texture")?; + + let wgpu_texture_format: TextureFormat = self.format.try_into()?; + let texture = vulkan_image_to_texture( + device, + raw_image, + wgpu::TextureDescriptor { + label: Some(label), + size: wgpu::Extent3d { + width: self.width, + height: self.height, + depth_or_array_layers: self.array_size, + }, + mip_level_count: self.mip_levels, + sample_count: self.sample_count, + dimension: wgpu::TextureDimension::D2, + format: wgpu_texture_format, + view_formats: &view_formats, + usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_SRC, + }, + TextureDescriptor { + label: Some(label), + size: wgpu::Extent3d { + width: self.width, + height: self.height, + depth_or_array_layers: self.array_size, + }, + mip_level_count: self.mip_levels, + sample_count: self.sample_count, + dimension: wgpu::TextureDimension::D2, + format: wgpu_texture_format, + view_formats: view_formats.clone(), + usage: TextureUses::RESOURCE | TextureUses::COPY_SRC, + memory_flags: MemoryFlags::empty(), + }, + ); + + Ok(Texture2D::::from_wgpu( + device, + texture, + view_format, + )) + } +} diff --git a/src/utils/logging.rs b/src/utils/logging.rs new file mode 100644 index 0000000..66f3e0b --- /dev/null +++ b/src/utils/logging.rs @@ -0,0 +1,67 @@ +use log::LevelFilter; +use log4rs::{ + append::{ + console::ConsoleAppender, + rolling_file::{ + policy::compound::{ + roll::fixed_window::FixedWindowRoller, trigger::size::SizeTrigger, CompoundPolicy, + }, + RollingFileAppender, + }, + }, + config::{Appender, Logger, Root}, + encode::pattern::PatternEncoder, + Config, +}; + +pub fn setup_logging() -> anyhow::Result<()> { + let trigger_size = 30_000_000_u64; + let trigger = Box::new(SizeTrigger::new(trigger_size)); + + let roller_pattern = "logs/output_{}.log"; + let roller_count = 5; + let roller_base = 1; + let roller = Box::new( + FixedWindowRoller::builder() + .base(roller_base) + .build(roller_pattern, roller_count) + .unwrap(), + ); + + let compound_policy = Box::new(CompoundPolicy::new(trigger, roller)); + + let logfile = RollingFileAppender::builder() + .encoder(Box::new(PatternEncoder::new( + "{d(%Y-%m-%d %H:%M:%S)} | {({l}):5.5} | {f}:{L} — {m}{n}", + ))) + .build("logs/output.log", compound_policy)?; + + let stdout = ConsoleAppender::builder().build(); + + let config = Config::builder() + .appender(Appender::builder().build("logfile", Box::new(logfile))) + .appender(Appender::builder().build("stdout", Box::new(stdout))) + .loggers([ + Logger::builder() + .appender("logfile") + .build("panic", LevelFilter::Info), + Logger::builder() + .appender("logfile") + .build("vr-screen-cap", LevelFilter::Info), + Logger::builder() + .appender("logfile") + .build("vr_screen_cap_core", LevelFilter::Info), + Logger::builder() + .appender("logfile") + .build("wgpu", LevelFilter::Warn), + Logger::builder() + .appender("logfile") + .build("wgpu-hal", LevelFilter::Warn), + ]) + .build(Root::builder().appender("stdout").build(LevelFilter::Info))?; + + log4rs::init_config(config)?; + log_panics::init(); + + Ok(()) +} diff --git a/src/utils/tray.rs b/src/utils/tray.rs new file mode 100644 index 0000000..ef33f0f --- /dev/null +++ b/src/utils/tray.rs @@ -0,0 +1,85 @@ +use std::sync::{Arc, Mutex}; + +use tray_item::{IconSource, TrayItem}; + +use crate::{loaders::StereoMode, utils::commands::ToggleSetting}; + +use super::commands::{AppCommands, AppState}; + +#[cfg_attr(feature = "profiling", profiling::function)] +fn add_tray_message_sender( + tray_state: &Arc>, + tray: &mut TrayItem, + entry_name: &'static str, + message: &'static AppCommands, +) -> anyhow::Result<()> { + let cloned_state = tray_state.clone(); + Ok(tray.add_menu_item(entry_name, move || { + if let Ok(mut locked_state) = cloned_state.lock() { + locked_state.message = Some(message); + } + })?) +} + +#[cfg_attr(feature = "profiling", profiling::function)] +fn add_all_tray_message_senders( + tray_state: &Arc>, + tray: &mut TrayItem, + entries: &[(&'static str, &'static AppCommands)], +) -> anyhow::Result<()> { + for (entry_name, message) in entries { + add_tray_message_sender(tray_state, tray, entry_name, message)?; + } + Ok(()) +} + +#[cfg_attr(feature = "profiling", profiling::function)] +pub(crate) fn build_tray(tray_state: &Arc>) -> anyhow::Result { + log::info!("Building system tray"); + let mut tray = TrayItem::new("VR Screen Cap", IconSource::Resource("tray-icon"))?; + + tray.add_label("Settings")?; + add_all_tray_message_senders( + tray_state, + &mut tray, + &[ + ( + "Swap Eyes", + &AppCommands::ToggleSettings(ToggleSetting::SwapEyes), + ), + ("Flip X", &AppCommands::ToggleSettings(ToggleSetting::FlipX)), + ("Flip Y", &AppCommands::ToggleSettings(ToggleSetting::FlipY)), + ( + "Toggle Ambient Light", + &AppCommands::ToggleSettings(ToggleSetting::AmbientLight), + ), + ], + )?; + + tray.add_label("Desktop Settings")?; + add_all_tray_message_senders( + tray_state, + &mut tray, + &[ + ("Mono", &AppCommands::SetStereoMode(StereoMode::Mono)), + ("Half-SBS", &AppCommands::SetStereoMode(StereoMode::Sbs)), + ("Full-SBS", &AppCommands::SetStereoMode(StereoMode::FullSbs)), + ("Half-TAB", &AppCommands::SetStereoMode(StereoMode::Tab)), + ("Full-TAB", &AppCommands::SetStereoMode(StereoMode::FullTab)), + ], + )?; + + tray.add_label("Actions")?; + add_all_tray_message_senders( + tray_state, + &mut tray, + &[ + ("Reload Screen", &AppCommands::Reload), + ("Recenter", &AppCommands::Recenter(true)), + ("Recenter w/ Pitch", &AppCommands::Recenter(false)), + ("Quit", &AppCommands::Quit), + ], + )?; + + Ok(tray) +} diff --git a/src/utils/validation.rs b/src/utils/validation.rs new file mode 100644 index 0000000..ef4eadf --- /dev/null +++ b/src/utils/validation.rs @@ -0,0 +1,26 @@ +use std::ffi::{c_void, CStr}; + +use ash::vk; +use log::{debug, error, trace, warn}; + +pub extern "system" fn debug_callback( + message_severity: vk::DebugUtilsMessageSeverityFlagsEXT, + message_type: vk::DebugUtilsMessageTypeFlagsEXT, + p_callback_data: *const vk::DebugUtilsMessengerCallbackDataEXT, + _: *mut c_void, +) -> vk::Bool32 { + let _data = unsafe { *p_callback_data }; + let message = unsafe { CStr::from_ptr((*p_callback_data).p_message) }; + + if message_severity >= vk::DebugUtilsMessageSeverityFlagsEXT::ERROR { + error!("[VALIDATION] ({:?}) {:?}", message_type, message); + } else if message_severity >= vk::DebugUtilsMessageSeverityFlagsEXT::WARNING { + warn!("[VALIDATION] ({:?}) {:?}", message_type, message); + } else if message_severity >= vk::DebugUtilsMessageSeverityFlagsEXT::INFO { + debug!("[VALIDATION] ({:?}) {:?}", message_type, message); + } else { + trace!("[VALIDATION] ({:?}) {:?}", message_type, message); + } + + vk::FALSE +}