diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..a6bd770 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + "recommendations": [ + "pinage404.rust-extension-pack", + "vadimcn.vscode-lldb", + "jnoortheen.nix-ide" + ] +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..c0caf03 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,45 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "lldb", + "request": "launch", + "name": "Debug executable 'rust_vulkan_test'", + "cargo": { + "args": [ + "build", + "--bin=rust_vulkan_test", + "--package=rust_vulkan_test" + ], + "filter": { + "name": "rust_vulkan_test", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "Debug unit tests in executable 'rust_vulkan_test'", + "cargo": { + "args": [ + "test", + "--no-run", + "--bin=rust_vulkan_test", + "--package=rust_vulkan_test" + ], + "filter": { + "name": "rust_vulkan_test", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..875f10e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.organizeImports": "always", + }, + "[rust]": { + "editor.defaultFormatter": "rust-lang.rust-analyzer", + }, + "files.insertFinalNewline": true, + "files.trimTrailingWhitespace": true +} diff --git a/Cargo.lock b/Cargo.lock index 85ed865..375be30 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "ab_glyph" @@ -19,13 +19,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" [[package]] -name = "ahash" -version = "0.8.11" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", - "getrandom", + "getrandom 0.3.3", "once_cell", "version_check", "zerocopy", @@ -40,6 +46,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "aligned-vec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1" + [[package]] name = "android-activity" version = "0.6.0" @@ -47,7 +59,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" dependencies = [ "android-properties", - "bitflags 2.6.0", + "bitflags 2.9.1", "cc", "cesu8", "jni", @@ -58,7 +70,7 @@ dependencies = [ "ndk-context", "ndk-sys", "num_enum", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -108,19 +120,57 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "3.0.6" +version = "3.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" dependencies = [ "anstyle", + "once_cell", "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.93" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" + +[[package]] +name = "arbitrary" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" + +[[package]] +name = "arboard" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1df21f715862ede32a0c525ce2ca4d52626bb0007f8c18b87a384503ac33e70" +dependencies = [ + "clipboard-win", + "image", + "log", + "objc2 0.6.1", + "objc2-app-kit 0.3.1", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation 0.3.1", + "parking_lot", + "percent-encoding", + "windows-sys 0.59.0", + "x11rb", +] + +[[package]] +name = "arg_enum_proc_macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "arrayref" @@ -145,16 +195,8 @@ name = "ash" version = "0.38.0+1.3.281" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" - -[[package]] -name = "ash-window" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52bca67b61cb81e5553babde81b8211f713cb6db79766f80168f3e5f40ea6c82" dependencies = [ - "ash", - "raw-window-handle", - "raw-window-metal", + "libloading", ] [[package]] @@ -169,6 +211,35 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +[[package]] +name = "av1-grain" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f3efb2ca85bc610acfa917b5aaa36f3fcbebed5b3182d7f877b02531c4b80c8" +dependencies = [ + "anyhow", + "arrayvec", + "log", + "nom", + "num-rational", + "v_frame", +] + +[[package]] +name = "avif-serialize" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98922d6a4cfbcb08820c69d8eeccc05bb1f29bfa06b4f5b1dbfe9a868bd7608e" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "bit_field" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" + [[package]] name = "bitflags" version = "1.3.2" @@ -177,15 +248,15 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] -name = "block" -version = "0.1.6" +name = "bitstream-io" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" +checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2" [[package]] name = "block2" @@ -193,26 +264,52 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" dependencies = [ - "objc2", + "objc2 0.5.2", ] [[package]] -name = "bumpalo" -version = "3.16.0" +name = "built" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b" + +[[package]] +name = "bumpalo" +version = "3.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "bytemuck" -version = "1.19.0" +version = "1.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" +checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ecc273b49b3205b83d648f0690daa588925572cc5063745bfe547fe7ec8e1a1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.8.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "calloop" @@ -220,12 +317,12 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "log", "polling", "rustix", "slab", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -242,9 +339,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.1" +version = "1.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" +checksum = "5f4ac86a9e5bc1e2b3449ab9d7d3a6a405e3d1bb28d7b9be8614f55846ae3766" dependencies = [ "jobserver", "libc", @@ -257,6 +354,16 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" +[[package]] +name = "cfg-expr" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +dependencies = [ + "smallvec", + "target-lexicon", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -270,35 +377,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] -name = "cocoa" -version = "0.25.0" +name = "clipboard-win" +version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6140449f97a6e97f9511815c5632d84c8aacf8ac271ad77c559218161a1373c" +checksum = "15efe7a882b08f34e38556b14f2fb3daa98769d06c7f0c1b076dfd0d983bc892" dependencies = [ - "bitflags 1.3.2", - "block", - "cocoa-foundation", - "core-foundation", - "core-graphics", - "foreign-types", - "libc", - "objc", + "error-code", ] [[package]] -name = "cocoa-foundation" -version = "0.1.2" +name = "cmake" +version = "0.1.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" +checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" dependencies = [ - "bitflags 1.3.2", - "block", - "core-foundation", - "core-graphics-types", - "libc", - "objc", + "cc", ] +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + [[package]] name = "colorchoice" version = "1.0.3" @@ -334,6 +435,16 @@ dependencies = [ "libc", ] +[[package]] +name = "core-foundation" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -347,7 +458,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" dependencies = [ "bitflags 1.3.2", - "core-foundation", + "core-foundation 0.9.4", "core-graphics-types", "foreign-types", "libc", @@ -360,15 +471,58 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" dependencies = [ "bitflags 1.3.2", - "core-foundation", + "core-foundation 0.9.4", "libc", ] [[package]] -name = "crossbeam-utils" -version = "0.8.20" +name = "crc32fast" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" [[package]] name = "cursor-icon" @@ -382,6 +536,27 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "dispatch2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" +dependencies = [ + "bitflags 2.9.1", + "objc2 0.6.1", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "dlib" version = "0.5.2" @@ -399,15 +574,89 @@ checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" [[package]] name = "dpi" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" +checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" + +[[package]] +name = "ecolor" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc4feb366740ded31a004a0e4452fbf84e80ef432ecf8314c485210229672fd1" +dependencies = [ + "bytemuck", + "emath", +] + +[[package]] +name = "egui" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25dd34cec49ab55d85ebf70139cb1ccd29c977ef6b6ba4fe85489d6877ee9ef3" +dependencies = [ + "ahash", + "bitflags 2.9.1", + "emath", + "epaint", + "log", + "nohash-hasher", + "profiling", +] + +[[package]] +name = "egui-winit" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d9dfbb78fe4eb9c3a39ad528b90ee5915c252e77bbab9d4ebc576541ab67e13" +dependencies = [ + "ahash", + "arboard", + "bytemuck", + "egui", + "log", + "profiling", + "raw-window-handle", + "smithay-clipboard", + "web-time", + "webbrowser", + "winit", +] + +[[package]] +name = "egui_winit_vulkano" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6abd5e69939cd416853fc3ec69c0e08721b175d03b508d5574849885c7e85a6" +dependencies = [ + "ahash", + "egui", + "egui-winit", + "image", + "vulkano", + "vulkano-shaders", + "winit", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "emath" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e4cadcff7a5353ba72b7fea76bf2122b5ebdbc68e8155aa56dfdea90083fe1b" +dependencies = [ + "bytemuck", +] [[package]] name = "env_filter" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" dependencies = [ "log", "regex", @@ -415,33 +664,103 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.5" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" dependencies = [ "anstream", "anstyle", "env_filter", - "humantime", + "jiff", "log", ] [[package]] -name = "equivalent" -version = "1.0.1" +name = "epaint" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "41fcc0f5a7c613afd2dee5e4b30c3e6acafb8ad6f0edb06068811f708a67c562" +dependencies = [ + "ab_glyph", + "ahash", + "bytemuck", + "ecolor", + "emath", + "epaint_default_fonts", + "log", + "nohash-hasher", + "parking_lot", + "profiling", +] + +[[package]] +name = "epaint_default_fonts" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7e7a64c02cf7a5b51e745a9e45f60660a286f151c238b9d397b3e923f5082f" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] +[[package]] +name = "error-code" +version = "3.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59" + +[[package]] +name = "exr" +version = "1.73.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83197f59927b46c04a183a619b7c29df34e63e63c7869320862268c0ef687e0" +dependencies = [ + "bit_field", + "half", + "lebe", + "miniz_oxide", + "rayon-core", + "smallvec", + "zune-inflate", +] + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "flate2" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "foreign-types" version = "0.5.0" @@ -469,6 +788,15 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + [[package]] name = "gethostname" version = "0.4.3" @@ -481,26 +809,71 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", ] [[package]] -name = "glob" -version = "0.3.1" +name = "getrandom" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", +] + +[[package]] +name = "gif" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2" +dependencies = [ + "color_quant", + "weezl", +] + +[[package]] +name = "glam" +version = "0.30.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b46b9ca4690308844c644e7c634d68792467260e051c8543e0c7871662b3ba7" + +[[package]] +name = "half" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" +dependencies = [ + "bytemuck", + "cfg-if", + "crunchy", +] [[package]] name = "hashbrown" -version = "0.15.1" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" @@ -509,27 +882,226 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" [[package]] -name = "humantime" -version = "2.1.0" +name = "home" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "image" +version = "0.25.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a" +dependencies = [ + "bytemuck", + "byteorder-lite", + "color_quant", + "exr", + "gif", + "image-webp", + "num-traits", + "png", + "qoi", + "ravif", + "rayon", + "rgb", + "tiff", + "zune-core", + "zune-jpeg", +] + +[[package]] +name = "image-webp" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b77d01e822461baa8409e156015a1d91735549f0f2c17691bd2d996bef238f7f" +dependencies = [ + "byteorder-lite", + "quick-error", +] + +[[package]] +name = "imgref" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408" [[package]] name = "indexmap" -version = "2.6.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", "hashbrown", ] +[[package]] +name = "interpolate_name" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "jiff" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f02000660d30638906021176af16b17498bd0d12813dbfe7b276d8bc7f3c0806" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde", +] + +[[package]] +name = "jiff-static" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c30758ddd7188629c6713fc45d1188af4f44c90582311d0c8d8c9907f60c48" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "jni" version = "0.21.1" @@ -541,7 +1113,7 @@ dependencies = [ "combine", "jni-sys", "log", - "thiserror", + "thiserror 1.0.69", "walkdir", "windows-sys 0.45.0", ] @@ -554,33 +1126,57 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ + "getrandom 0.3.3", "libc", ] [[package]] -name = "js-sys" -version = "0.3.72" +name = "jpeg-decoder" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ + "once_cell", "wasm-bindgen", ] [[package]] -name = "libc" -version = "0.2.164" +name = "lebe" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" +checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" + +[[package]] +name = "libc" +version = "0.2.172" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" + +[[package]] +name = "libfuzzer-sys" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf78f52d400cf2d84a3a973a78a592b4adc535739e0a5597a0da6f0c357adc75" +dependencies = [ + "arbitrary", + "cc", +] [[package]] name = "libloading" -version = "0.8.5" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +checksum = "6a793df0d7afeac54f95b471d3af7f0d4fb975699f972341a4b76988d49cdf0c" dependencies = [ "cfg-if", "windows-targets 0.52.6", @@ -592,30 +1188,56 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "libc", - "redox_syscall 0.5.7", + "redox_syscall 0.5.12", ] [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] [[package]] name = "log" -version = "0.4.22" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] -name = "malloc_buf" -version = "0.0.6" +name = "loop9" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" dependencies = [ - "libc", + "imgref", +] + +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if", + "rayon", ] [[package]] @@ -633,19 +1255,35 @@ dependencies = [ "libc", ] +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +dependencies = [ + "adler2", + "simd-adler32", +] + [[package]] name = "ndk" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "jni-sys", "log", "ndk-sys", "num_enum", "raw-window-handle", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -663,6 +1301,84 @@ dependencies = [ "jni-sys", ] +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "noop_proc_macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + [[package]] name = "num_enum" version = "0.7.3" @@ -684,15 +1400,6 @@ dependencies = [ "syn", ] -[[package]] -name = "objc" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" -dependencies = [ - "malloc_buf", -] - [[package]] name = "objc-sys" version = "0.3.5" @@ -709,20 +1416,41 @@ dependencies = [ "objc2-encode", ] +[[package]] +name = "objc2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88c6597e14493ab2e44ce58f2fdecf095a51f12ca57bec060a11c57332520551" +dependencies = [ + "objc2-encode", +] + [[package]] name = "objc2-app-kit" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "block2", "libc", - "objc2", + "objc2 0.5.2", "objc2-core-data", "objc2-core-image", - "objc2-foundation", - "objc2-quartz-core", + "objc2-foundation 0.2.2", + "objc2-quartz-core 0.2.2", +] + +[[package]] +name = "objc2-app-kit" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6f29f568bec459b0ddff777cec4fe3fd8666d82d5a40ebd0ff7e66134f89bcc" +dependencies = [ + "bitflags 2.9.1", + "objc2 0.6.1", + "objc2-core-graphics", + "objc2-foundation 0.3.1", ] [[package]] @@ -731,11 +1459,11 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "block2", - "objc2", + "objc2 0.5.2", "objc2-core-location", - "objc2-foundation", + "objc2-foundation 0.2.2", ] [[package]] @@ -745,8 +1473,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" dependencies = [ "block2", - "objc2", - "objc2-foundation", + "objc2 0.5.2", + "objc2-foundation 0.2.2", ] [[package]] @@ -755,10 +1483,34 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "block2", - "objc2", - "objc2-foundation", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" +dependencies = [ + "bitflags 2.9.1", + "dispatch2", + "objc2 0.6.1", +] + +[[package]] +name = "objc2-core-graphics" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "989c6c68c13021b5c2d6b71456ebb0f9dc78d752e86a98da7c716f4f9470f5a4" +dependencies = [ + "bitflags 2.9.1", + "dispatch2", + "objc2 0.6.1", + "objc2-core-foundation", + "objc2-io-surface", ] [[package]] @@ -768,9 +1520,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" dependencies = [ "block2", - "objc2", - "objc2-foundation", - "objc2-metal", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "objc2-metal 0.2.2", ] [[package]] @@ -780,16 +1532,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" dependencies = [ "block2", - "objc2", + "objc2 0.5.2", "objc2-contacts", - "objc2-foundation", + "objc2-foundation 0.2.2", ] [[package]] name = "objc2-encode" -version = "4.0.3" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7891e71393cd1f227313c9379a26a584ff3d7e6e7159e988851f0934c993f0f8" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" [[package]] name = "objc2-foundation" @@ -797,11 +1549,33 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "block2", "dispatch", "libc", - "objc2", + "objc2 0.5.2", +] + +[[package]] +name = "objc2-foundation" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" +dependencies = [ + "bitflags 2.9.1", + "objc2 0.6.1", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-io-surface" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7282e9ac92529fa3457ce90ebb15f4ecbc383e8338060960760fa2cf75420c3c" +dependencies = [ + "bitflags 2.9.1", + "objc2 0.6.1", + "objc2-core-foundation", ] [[package]] @@ -811,9 +1585,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" dependencies = [ "block2", - "objc2", - "objc2-app-kit", - "objc2-foundation", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", ] [[package]] @@ -822,10 +1596,21 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "block2", - "objc2", - "objc2-foundation", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-metal" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f246c183239540aab1782457b35ab2040d4259175bd1d0c58e46ada7b47a874" +dependencies = [ + "bitflags 2.9.1", + "objc2 0.6.1", + "objc2-foundation 0.3.1", ] [[package]] @@ -834,11 +1619,24 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "block2", - "objc2", - "objc2-foundation", - "objc2-metal", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "objc2-metal 0.2.2", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ffb6a0cd5f182dc964334388560b12a57f7b74b3e2dec5e2722aa2dfb2ccd5" +dependencies = [ + "bitflags 2.9.1", + "objc2 0.6.1", + "objc2-core-foundation", + "objc2-foundation 0.3.1", + "objc2-metal 0.3.1", ] [[package]] @@ -847,8 +1645,8 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc" dependencies = [ - "objc2", - "objc2-foundation", + "objc2 0.5.2", + "objc2-foundation 0.2.2", ] [[package]] @@ -857,16 +1655,16 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "block2", - "objc2", + "objc2 0.5.2", "objc2-cloud-kit", "objc2-core-data", "objc2-core-image", "objc2-core-location", - "objc2-foundation", + "objc2-foundation 0.2.2", "objc2-link-presentation", - "objc2-quartz-core", + "objc2-quartz-core 0.2.2", "objc2-symbols", "objc2-uniform-type-identifiers", "objc2-user-notifications", @@ -879,8 +1677,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" dependencies = [ "block2", - "objc2", - "objc2-foundation", + "objc2 0.5.2", + "objc2-foundation 0.2.2", ] [[package]] @@ -889,18 +1687,18 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "block2", - "objc2", + "objc2 0.5.2", "objc2-core-location", - "objc2-foundation", + "objc2-foundation 0.2.2", ] [[package]] name = "once_cell" -version = "1.20.2" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "orbclient" @@ -920,6 +1718,35 @@ dependencies = [ "ttf-parser", ] +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.12", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "percent-encoding" version = "2.3.1" @@ -928,18 +1755,18 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project" -version = "1.1.7" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.7" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", @@ -948,15 +1775,28 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pkg-config" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "png" +version = "0.17.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] [[package]] name = "polling" @@ -974,41 +1814,223 @@ dependencies = [ ] [[package]] -name = "proc-macro-crate" -version = "3.2.0" +name = "portable-atomic" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro-crate" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" dependencies = [ "toml_edit", ] [[package]] name = "proc-macro2" -version = "1.0.89" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] [[package]] -name = "quick-xml" -version = "0.36.2" +name = "profiling" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe" +checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + +[[package]] +name = "quick-xml" +version = "0.37.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" dependencies = [ "memchr", ] [[package]] name = "quote" -version = "1.0.37" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.3", +] + +[[package]] +name = "rav1e" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9" +dependencies = [ + "arbitrary", + "arg_enum_proc_macro", + "arrayvec", + "av1-grain", + "bitstream-io", + "built", + "cfg-if", + "interpolate_name", + "itertools", + "libc", + "libfuzzer-sys", + "log", + "maybe-rayon", + "new_debug_unreachable", + "noop_proc_macro", + "num-derive", + "num-traits", + "once_cell", + "paste", + "profiling", + "rand 0.8.5", + "rand_chacha 0.3.1", + "simd_helpers", + "system-deps", + "thiserror 1.0.69", + "v_frame", + "wasm-bindgen", +] + +[[package]] +name = "ravif" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6a5f31fcf7500f9401fea858ea4ab5525c99f2322cfcee732c0e6c74208c0c6" +dependencies = [ + "avif-serialize", + "imgref", + "loop9", + "quick-error", + "rav1e", + "rayon", + "rgb", +] + [[package]] name = "raw-window-handle" version = "0.6.2" @@ -1017,14 +2039,34 @@ checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" [[package]] name = "raw-window-metal" -version = "0.4.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76e8caa82e31bb98fee12fa8f051c94a6aa36b07cddb03f0d4fc558988360ff1" +checksum = "40d213455a5f1dc59214213c7330e074ddf8114c9a42411eb890c767357ce135" dependencies = [ - "cocoa", - "core-graphics", - "objc", - "raw-window-handle", + "objc2 0.6.1", + "objc2-core-foundation", + "objc2-foundation 0.3.1", + "objc2-quartz-core 0.3.1", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", ] [[package]] @@ -1038,11 +2080,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.7" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", ] [[package]] @@ -1074,32 +2116,64 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "rgb" +version = "0.8.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" + +[[package]] +name = "roxmltree" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "921904a62e410e37e215c40381b7117f830d9d89ba60ab5236170541dd25646b" +dependencies = [ + "xmlparser", +] + [[package]] name = "rust_vulkan_test" version = "0.1.0" dependencies = [ "anyhow", - "ash", - "ash-window", + "egui_winit_vulkano", "env_logger", - "glob", + "glam", + "image", "log", + "rand 0.9.1", + "thiserror 2.0.12", + "vulkano", + "vulkano-shaders", + "vulkano-util", "winit", ] [[package]] name = "rustix" -version = "0.38.40" +version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] +[[package]] +name = "rustversion" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + [[package]] name = "same-file" version = "1.0.6" @@ -1115,6 +2189,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "sctk-adwaita" version = "0.10.1" @@ -1130,30 +2210,87 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.215" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.215" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "serde_json" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + +[[package]] +name = "shaderc" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27e07913ada18607bb60d12431cbe3358d3bbebbe95948e1618851dc01e63b7b" +dependencies = [ + "libc", + "shaderc-sys", +] + +[[package]] +name = "shaderc-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73120d240fe22196300f39ca8547ca2d014960f27b19b47b21288b396272f7f7" +dependencies = [ + "cmake", + "libc", + "roxmltree", +] + [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[package]] +name = "simd_helpers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" +dependencies = [ + "quote", +] + [[package]] name = "slab" version = "0.4.9" @@ -1164,10 +2301,16 @@ dependencies = [ ] [[package]] -name = "smallvec" -version = "1.13.2" +name = "slabbin" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "9db491c0d4152a069911a0fbdaca959691bf0b9d7110d98a7ed1c8e59b79ab30" + +[[package]] +name = "smallvec" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" [[package]] name = "smithay-client-toolkit" @@ -1175,7 +2318,7 @@ version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "calloop", "calloop-wayland-source", "cursor-icon", @@ -1183,7 +2326,7 @@ dependencies = [ "log", "memmap2", "rustix", - "thiserror", + "thiserror 1.0.69", "wayland-backend", "wayland-client", "wayland-csd-frame", @@ -1194,6 +2337,17 @@ dependencies = [ "xkeysym", ] +[[package]] +name = "smithay-clipboard" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc8216eec463674a0e90f29e0ae41a4db573ec5b56b1c6c1c71615d249b6d846" +dependencies = [ + "libc", + "smithay-client-toolkit", + "wayland-backend", +] + [[package]] name = "smol_str" version = "0.2.2" @@ -1203,6 +2357,12 @@ dependencies = [ "serde", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "strict-num" version = "0.1.1" @@ -1211,22 +2371,61 @@ checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" [[package]] name = "syn" -version = "2.0.87" +version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "system-deps" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +dependencies = [ + "cfg-expr", + "heck 0.5.0", + "pkg-config", + "toml", + "version-compare", +] + +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + [[package]] name = "thiserror" version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", ] [[package]] @@ -1240,6 +2439,38 @@ dependencies = [ "syn", ] +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "tiff" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" +dependencies = [ + "flate2", + "jpeg-decoder", + "weezl", +] + [[package]] name = "tiny-skia" version = "0.11.4" @@ -1266,27 +2497,54 @@ dependencies = [ ] [[package]] -name = "toml_datetime" -version = "0.6.8" +name = "tinystr" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "toml" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" +dependencies = [ + "serde", +] [[package]] name = "toml_edit" -version = "0.22.22" +version = "0.22.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" dependencies = [ "indexmap", + "serde", + "serde_spanned", "toml_datetime", "winnow", ] [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "pin-project-lite", "tracing-core", @@ -1294,21 +2552,21 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" [[package]] name = "ttf-parser" -version = "0.25.0" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5902c5d130972a0000f60860bfbf46f7ca3db5391eddfedd1b8728bd9dc96c0e" +checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-segmentation" @@ -1316,18 +2574,131 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "v_frame" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f32aaa24bacd11e488aa9ba66369c7cd514885742c9fe08cfe85884db3e92b" +dependencies = [ + "aligned-vec", + "num-traits", + "wasm-bindgen", +] + +[[package]] +name = "version-compare" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" + [[package]] name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "vk-parse" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3859da4d7b98bec73e68fb65815d47a263819c415c90eed42b80440a02cbce8c" +dependencies = [ + "xml-rs", +] + +[[package]] +name = "vulkano" +version = "0.35.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08840c2b51759a6f88f26f5ea378bc8b5c199a5b4760ddda292304be087249c4" +dependencies = [ + "ash", + "bytemuck", + "crossbeam-queue", + "foldhash", + "half", + "heck 0.4.1", + "indexmap", + "libloading", + "nom", + "once_cell", + "parking_lot", + "proc-macro2", + "quote", + "raw-window-handle", + "raw-window-metal", + "serde", + "serde_json", + "slabbin", + "smallvec", + "thread_local", + "vk-parse", + "vulkano-macros", + "x11-dl", + "x11rb", +] + +[[package]] +name = "vulkano-macros" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dc929c42c9336fd082079ac3ea30126e4a0dfe36fd2e2b3581303f7d140d20f" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "vulkano-shaders" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bf501461be7cef2893c0e62c50945add9763cc482051d29053f6157089d5ea9" +dependencies = [ + "foldhash", + "heck 0.4.1", + "proc-macro2", + "quote", + "shaderc", + "syn", + "vulkano", +] + +[[package]] +name = "vulkano-util" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e25dc54fd5e14a0e01c7282f9b5d9c6e133745e1df3228b0352366e34c83bb6b" +dependencies = [ + "foldhash", + "vulkano", + "winit", +] + [[package]] name = "walkdir" version = "2.5.0" @@ -1345,25 +2716,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] -name = "wasm-bindgen" -version = "0.2.95" +name = "wasi" +version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.95" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", "syn", @@ -1372,21 +2752,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.45" +version = "0.4.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.95" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1394,9 +2775,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.95" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", @@ -1407,15 +2788,18 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.95" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] name = "wayland-backend" -version = "0.3.7" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "056535ced7a150d45159d3a8dc30f91a2e2d588ca0b23f70e56033622b8016f6" +checksum = "fe770181423e5fc79d3e2a7f4410b7799d5aab1de4372853de3c6aa13ca24121" dependencies = [ "cc", "downcast-rs", @@ -1427,11 +2811,11 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.31.7" +version = "0.31.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66249d3fc69f76fd74c82cc319300faa554e9d865dab1f7cd66cc20db10b280" +checksum = "978fa7c67b0847dbd6a9f350ca2569174974cd4082737054dbb7fbb79d7d9a61" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "rustix", "wayland-backend", "wayland-scanner", @@ -1443,16 +2827,16 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "cursor-icon", "wayland-backend", ] [[package]] name = "wayland-cursor" -version = "0.31.7" +version = "0.31.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b08bc3aafdb0035e7fe0fdf17ba0c09c268732707dca4ae098f60cb28c9e4c" +checksum = "a65317158dec28d00416cb16705934070aef4f8393353d41126c54264ae0f182" dependencies = [ "rustix", "wayland-client", @@ -1461,11 +2845,11 @@ dependencies = [ [[package]] name = "wayland-protocols" -version = "0.32.5" +version = "0.32.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd0ade57c4e6e9a8952741325c30bf82f4246885dca8bf561898b86d0c1f58e" +checksum = "779075454e1e9a521794fed15886323ea0feda3f8b0fc1390f5398141310422a" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "wayland-backend", "wayland-client", "wayland-scanner", @@ -1473,11 +2857,11 @@ dependencies = [ [[package]] name = "wayland-protocols-plasma" -version = "0.3.5" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b31cab548ee68c7eb155517f2212049dc151f7cd7910c2b66abfd31c3ee12bd" +checksum = "4fd38cdad69b56ace413c6bcc1fbf5acc5e2ef4af9d5f8f1f9570c0c83eae175" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "wayland-backend", "wayland-client", "wayland-protocols", @@ -1486,11 +2870,11 @@ dependencies = [ [[package]] name = "wayland-protocols-wlr" -version = "0.3.5" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "782e12f6cd923c3c316130d56205ebab53f55d6666b7faddfad36cecaeeb4022" +checksum = "1cb6cdc73399c0e06504c437fe3cf886f25568dd5454473d565085b36d6a8bbf" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "wayland-backend", "wayland-client", "wayland-protocols", @@ -1499,9 +2883,9 @@ dependencies = [ [[package]] name = "wayland-scanner" -version = "0.31.5" +version = "0.31.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597f2001b2e5fc1121e3d5b9791d3e78f05ba6bfa4641053846248e3a13661c3" +checksum = "896fdafd5d28145fce7958917d69f2fd44469b1d4e861cb5961bcbeebc6d1484" dependencies = [ "proc-macro2", "quick-xml", @@ -1510,9 +2894,9 @@ dependencies = [ [[package]] name = "wayland-sys" -version = "0.31.5" +version = "0.31.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efa8ac0d8e8ed3e3b5c9fc92c7881406a268e11555abe36493efabe649a29e09" +checksum = "dbcebb399c77d5aa9fa5db874806ee7b4eba4e73650948e8f93963f128896615" dependencies = [ "dlib", "log", @@ -1522,9 +2906,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.72" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" dependencies = [ "js-sys", "wasm-bindgen", @@ -1540,6 +2924,29 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webbrowser" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5df295f8451142f1856b1bd86a606dfe9587d439bc036e319c827700dbd555e" +dependencies = [ + "core-foundation 0.10.0", + "home", + "jni", + "log", + "ndk-context", + "objc2 0.6.1", + "objc2-foundation 0.3.1", + "url", + "web-sys", +] + +[[package]] +name = "weezl" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3" + [[package]] name = "winapi-util" version = "0.1.9" @@ -1756,20 +3163,20 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winit" -version = "0.30.5" +version = "0.30.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0be9e76a1f1077e04a411f0b989cbd3c93339e1771cb41e71ac4aee95bfd2c67" +checksum = "b0d05bd8908e14618c9609471db04007e644fd9cce6529756046cfc577f9155e" dependencies = [ "ahash", "android-activity", "atomic-waker", - "bitflags 2.6.0", + "bitflags 2.9.1", "block2", "bytemuck", "calloop", "cfg_aliases", "concurrent-queue", - "core-foundation", + "core-foundation 0.9.4", "core-graphics", "cursor-icon", "dpi", @@ -1777,9 +3184,9 @@ dependencies = [ "libc", "memmap2", "ndk", - "objc2", - "objc2-app-kit", - "objc2-foundation", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", "objc2-ui-kit", "orbclient", "percent-encoding", @@ -1808,13 +3215,28 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.20" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" dependencies = [ "memchr", ] +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags 2.9.1", +] + +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + [[package]] name = "x11-dl" version = "2.21.0" @@ -1859,7 +3281,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "dlib", "log", "once_cell", @@ -1873,21 +3295,135 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" [[package]] -name = "zerocopy" -version = "0.7.35" +name = "xml-rs" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +checksum = "a62ce76d9b56901b19a74f19431b0d8b3bc7ca4ad685a746dfd78ca8f4fc6bda" + +[[package]] +name = "xmlparser" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.35" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" dependencies = [ "proc-macro2", "quote", "syn", ] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zune-core" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" + +[[package]] +name = "zune-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "zune-jpeg" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99a5bab8d7dedf81405c4bb1f2b83ea057643d9cb28778cea9eecddeedd2e028" +dependencies = [ + "zune-core", +] diff --git a/Cargo.toml b/Cargo.toml index 3865769..feb1bca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,19 +1,28 @@ [package] name = "rust_vulkan_test" version = "0.1.0" -edition = "2021" +edition = "2024" authors = ["Florian RICHER "] publish = false [dependencies] anyhow = "1.0" +thiserror = "2.0" winit = { version = "0.30", features = ["rwh_06"] } -ash = { version = "0.38", default-features = false, features = ["linked", "debug", "std"] } -ash-window = "0.13" + +vulkano = "0.35" +vulkano-shaders = "0.35" +vulkano-util = "0.35" +egui_winit_vulkano = { version = "0.28" } + +image = { version = "0.25", features = ["png", "jpeg"] } + +# Math +glam = { version = "0.30" } # Log and tracing log = "0.4" -env_logger = "0.11.5" +env_logger = "0.11" -[build-dependencies] -glob = "0.3" \ No newline at end of file +# Random +rand = "0.9" diff --git a/README.md b/README.md new file mode 100644 index 0000000..c271fd8 --- /dev/null +++ b/README.md @@ -0,0 +1,17 @@ +# Project + +## Notes + +1. Run renderdoc on wayland: + +```console +WAYLAND_DISPLAY= QT_QPA_PLATFORM=xcb qrenderdoc +``` +> Not supported yet https://github.com/baldurk/renderdoc/issues/853 + +2. [Difference Between OpenGL and Vulkan](./docs/OPENGL_VULKAN_DIFF.md) + +## Usefull links + +- https://vulkan-tutorial.com/fr/Introduction +- https://github.com/bwasty/vulkan-tutorial-rs diff --git a/build.rs b/build.rs deleted file mode 100644 index be949e6..0000000 --- a/build.rs +++ /dev/null @@ -1,24 +0,0 @@ -use std::process::Command; - -fn main() { - for shader in glob::glob("res/shaders/*").unwrap().filter_map(Result::ok) { - if !shader.is_file() { - continue; - } - - let shader_file_name = shader.to_str().unwrap(); - - let mut command = Command::new("glslc"); - command.arg(&shader); - - let out_file = match shader.extension().unwrap().to_str().unwrap() { - "vert" => shader_file_name.replace(".vert", ".vert.spv"), - "frag" => shader_file_name.replace(".frag", ".frag.spv"), - _ => continue, - }; - - command.arg("-o"); - command.arg(out_file); - command.output().unwrap(); - } -} diff --git a/docs/OPENGL_VULKAN_DIFF.md b/docs/OPENGL_VULKAN_DIFF.md new file mode 100644 index 0000000..93d0855 --- /dev/null +++ b/docs/OPENGL_VULKAN_DIFF.md @@ -0,0 +1,11 @@ +# Difference between Vulkan and OpenGL + +Viewport: + +- Y axis is flipped like D3D +- Clipped Z axis is not [-1; 1] but [0; 1] + +![normalized viewport coordinates](./images/normalized_device_coordinates.svg) +![coord_sys](./images/coord_sys.png) + +See: [Vulkan Tutorial (Vertex step)](https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics/Shader_modules) and [VK_KHR_maintenance1 (Allow negative height)](https://registry.khronos.org/vulkan/specs/latest/man/html/VK_KHR_maintenance1.html#_description) diff --git a/docs/images/coord_sys.png b/docs/images/coord_sys.png new file mode 100644 index 0000000..6d195f6 Binary files /dev/null and b/docs/images/coord_sys.png differ diff --git a/docs/images/normalized_device_coordinates.svg b/docs/images/normalized_device_coordinates.svg new file mode 100644 index 0000000..970c9f4 --- /dev/null +++ b/docs/images/normalized_device_coordinates.svg @@ -0,0 +1,219 @@ + + + + + + + + + + image/svg+xml + + + + + + + + Framebuffer coordinates + (0, 0) + (1920, 0) + (0, 1080) + (1920, 1080) + + (960, 540) + + Normalized device coordinates + (-1, -1) + (1, -1) + (-1, 1) + (1, 1) + + (0, 0) + + diff --git a/flake.lock b/flake.lock index 9ff2d00..4f4cf7e 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1726560853, - "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", "owner": "numtide", "repo": "flake-utils", - "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", "type": "github" }, "original": { @@ -28,26 +28,27 @@ ] }, "locked": { - "lastModified": 1713543440, - "narHash": "sha256-lnzZQYG0+EXl/6NkGpyIz+FEOc/DSEG57AP1VsdeNrM=", - "owner": "nix-community", + "lastModified": 1735283791, + "narHash": "sha256-JlT4VFs8aVlW+l151HZIZumfFsccZXcO/k5WpbYF09Y=", + "owner": "phirsch", "repo": "nixGL", - "rev": "310f8e49a149e4c9ea52f1adf70cdc768ec53f8a", + "rev": "ea8baea3b9d854bf9cf5c834a805c50948dd2603", "type": "github" }, "original": { - "owner": "nix-community", + "owner": "phirsch", + "ref": "fix-versionMatch", "repo": "nixGL", "type": "github" } }, "nixpkgs": { "locked": { - "lastModified": 1730831018, - "narHash": "sha256-2S0HwIFRxYp+afuoFORcZA9TjryAf512GmE0MTfEOPU=", + "lastModified": 1747312588, + "narHash": "sha256-MmJvj6mlWzeRwKGLcwmZpKaOPZ5nJb/6al5CXqJsgjo=", "owner": "nixos", "repo": "nixpkgs", - "rev": "8c4dc69b9732f6bbe826b5fbb32184987520ff26", + "rev": "b1bebd0fe266bbd1820019612ead889e96a8fa2d", "type": "github" }, "original": { @@ -72,11 +73,11 @@ ] }, "locked": { - "lastModified": 1730860036, - "narHash": "sha256-u0sfA4B65Q9cRO3xpIkQ4nldB8isfdIb3rWtsnRZ+Iw=", + "lastModified": 1747363019, + "narHash": "sha256-N4dwkRBmpOosa4gfFkFf/LTD8oOcNkAyvZ07JvRDEf0=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "b8eb3aeb21629cbe14968a5e3b1cbaefb0d1b260", + "rev": "0e624f2b1972a34be1a9b35290ed18ea4b419b6f", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 624590d..c5bbd9a 100644 --- a/flake.nix +++ b/flake.nix @@ -9,7 +9,8 @@ inputs.nixpkgs.follows = "nixpkgs"; }; nixgl = { - url = "github:nix-community/nixGL"; + # Revert this to community version when https://github.com/nix-community/nixGL/pull/187 is merged + url = "github:phirsch/nixGL/fix-versionMatch"; inputs.nixpkgs.follows = "nixpkgs"; inputs.flake-utils.follows = "flake-utils"; }; @@ -30,35 +31,58 @@ cargo = rust; }); - libs = with pkgs; [ vulkan-headers vulkan-loader vulkan-validation-layers ] - ++ pkgs.lib.optionals pkgs.stdenv.hostPlatform.isLinux (with pkgs; [ libxkbcommon wayland libGL ]) + buildInputs = with pkgs; [ vulkan-headers vulkan-loader vulkan-validation-layers renderdoc ] + ++ pkgs.lib.optionals pkgs.stdenv.hostPlatform.isLinux (with pkgs; [ + stdenv.cc.cc.lib + + # Wayland + libxkbcommon + wayland + libGL + + # Xorg + xorg.libX11 + xorg.libXcursor + xorg.libXi + xorg.libxcb + xorg.libxshmfence + ]) ++ pkgs.lib.optionals pkgs.stdenv.hostPlatform.isDarwin (with pkgs; [ darwin.apple_sdk.frameworks.SystemConfiguration ]); + + nativeBuildInputs = with pkgs; [ + pkg-config + cmake + python312 + ]; + + mkCustomShell = { packages ? [ ] }: pkgs.mkShell { + nativeBuildInputs = [ + pkgs.renderdoc + (rust.override { extensions = [ "rust-src" "rust-analyzer" ]; }) + ] ++ nativeBuildInputs; + + buildInputs = buildInputs + ++ packages; + + LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath buildInputs; + VK_LAYER_PATH = "${pkgs.vulkan-validation-layers}/share/vulkan/explicit_layer.d"; + RUST_LOG = "debug,rust_vulkan_test=trace"; + }; in { devShells = { - default = pkgs.mkShell { - nativeBuildInputs = with pkgs; [ - (rust.override { extensions = ["rust-src" "rust-analyzer"]; }) - pkg-config - ]; - - buildInputs = libs ++ [ - pkgs.nixgl.auto.nixVulkanNvidia pkgs.nixgl.nixVulkanIntel - ]; - - LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath (with pkgs; [ libxkbcommon wayland libGL ]); - }; + default = mkCustomShell { packages = [ pkgs.nixgl.auto.nixVulkanNvidia pkgs.nixgl.nixVulkanMesa ]; }; + nixos = mkCustomShell { }; }; packages = { default = rustPlatform.buildRustPackage { - pname = "rust_ash_test"; + pname = "vulkan_test"; version = "0.1.0"; src = self; - nativeBuildInputs = with pkgs; [ pkg-config shaderc ]; - buildInputs = libs; + inherit nativeBuildInputs buildInputs; cargoLock = { lockFile = ./Cargo.lock; diff --git a/res/shaders/main.frag b/res/shaders/main.frag deleted file mode 100644 index 33ca4af..0000000 --- a/res/shaders/main.frag +++ /dev/null @@ -1,8 +0,0 @@ -#version 450 - -layout (location = 0) in vec3 fragColor; -layout (location = 0) out vec4 outColor; - -void main() { - outColor = vec4(fragColor, 1.0); -} \ No newline at end of file diff --git a/res/shaders/main.vert b/res/shaders/main.vert deleted file mode 100644 index d141c1d..0000000 --- a/res/shaders/main.vert +++ /dev/null @@ -1 +0,0 @@ -#version 450 out gl_PerVertex { vec4 gl_Position; }; layout (location = 0) out vec3 fragColor; vec2 positions[3] = vec2[]( vec2(0.0, -0.5), vec2(0.5, 0.5), vec2(-0.5, 0.5) ); vec3 colors[3] = vec3[]( vec3(1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, 0.0, 1.0) ); void main() { gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); fragColor = colors[gl_VertexIndex]; } \ No newline at end of file diff --git a/res/shaders/vertex.frag b/res/shaders/vertex.frag index 04f88bd..67831a9 100644 --- a/res/shaders/vertex.frag +++ b/res/shaders/vertex.frag @@ -1,10 +1,12 @@ #version 450 -#extension GL_ARB_separate_shader_objects: enable -layout (location = 0) in vec3 fragColor; +layout (location = 0) in vec2 tex_coords; -layout (location = 0) out vec4 outColor; +layout (location = 0) out vec4 f_color; + +layout(set = 1, binding = 0) uniform sampler mySampler; +layout(set = 1, binding = 1) uniform texture2D myTexture; void main() { - outColor = vec4(fragColor, 1.0); -} \ No newline at end of file + f_color = texture(sampler2D(myTexture, mySampler), tex_coords); +} diff --git a/res/shaders/vertex.vert b/res/shaders/vertex.vert index d7b1aac..8c1df7c 100644 --- a/res/shaders/vertex.vert +++ b/res/shaders/vertex.vert @@ -1 +1,20 @@ -#version 450 #extension GL_ARB_separate_shader_objects: enable // NOTE: names must match the `Vertex` struct in Rust layout (location = 0) in vec2 pos; layout (location = 1) in vec3 color; layout (location = 0) out vec3 fragColor; out gl_PerVertex { vec4 gl_Position; }; void main() { gl_Position = vec4(pos, 0.0, 1.0); fragColor = color; } \ No newline at end of file +#version 450 + +layout (location = 0) in vec3 position; +layout (location = 1) in vec2 uv; +layout (location = 2) in mat4 model; + +layout (location = 0) out vec2 fragUv; + +layout (set = 0, binding = 0) uniform MVP { + mat4 world; + mat4 view; + mat4 projection; +} uniforms; + +void main() { + mat4 worldview = uniforms.view * uniforms.world; + vec4 modelPosition = model * vec4(position, 1.0); + gl_Position = uniforms.projection * worldview * modelPosition; + fragUv = uv; +} diff --git a/res/textures/wooden-crate.jpg b/res/textures/wooden-crate.jpg new file mode 100644 index 0000000..d1c8734 Binary files /dev/null and b/res/textures/wooden-crate.jpg differ diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 2e2b8c8..b8889a3 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "1.82.0" +channel = "1.87.0" diff --git a/src/core/app/context.rs b/src/core/app/context.rs new file mode 100644 index 0000000..f7f8ec4 --- /dev/null +++ b/src/core/app/context.rs @@ -0,0 +1,239 @@ +use std::{ + rc::Rc, + sync::{Arc, RwLock}, +}; + +use egui_winit_vulkano::Gui; +use vulkano::{ + command_buffer::allocator::StandardCommandBufferAllocator, + descriptor_set::allocator::StandardDescriptorSetAllocator, + device::{Device, Queue}, + instance::Instance, + memory::allocator::StandardMemoryAllocator, +}; +use vulkano_util::{renderer::VulkanoWindowRenderer, window::VulkanoWindows}; +use winit::{ + event_loop::EventLoopProxy, + window::{Window, WindowId}, +}; + +use crate::core::{input::InputManager, render::vulkan_context::VulkanContext, timer::Timer}; + +use super::user_event::UserEvent; + +/// Contexte d'application unifié avec Arc> pour la mutabilité partagée +#[derive(Clone)] +pub struct ApplicationContext { + // Données Vulkan (immutables) + pub vulkan_context: Arc, + pub device: Arc, + pub instance: Arc, + pub graphics_queue: Arc, + pub compute_queue: Arc, + pub transfer_queue: Option>, + pub memory_allocator: Arc, + pub command_buffer_allocator: Arc, + pub descriptor_set_allocator: Arc, + pub event_loop_proxy: EventLoopProxy, + pub window_id: WindowId, + + // Données mutables partagées avec Arc> + pub vulkano_windows: Rc>, + pub input_manager: Arc>, + pub timer: Arc>, + pub gui: Rc>, +} + +impl ApplicationContext { + pub fn new( + vulkan_context: Arc, + vulkano_windows: Rc>, + input_manager: Arc>, + timer: Arc>, + gui: Rc>, + event_loop_proxy: EventLoopProxy, + window_id: WindowId, + ) -> Self { + let vulkano_context_inner = vulkan_context.vulkano_context(); + + Self { + // Données Vulkan + vulkan_context: vulkan_context.clone(), + device: vulkano_context_inner.device().clone(), + instance: vulkano_context_inner.instance().clone(), + graphics_queue: vulkano_context_inner.graphics_queue().clone(), + compute_queue: vulkano_context_inner.compute_queue().clone(), + transfer_queue: vulkano_context_inner.transfer_queue().cloned(), + memory_allocator: vulkano_context_inner.memory_allocator().clone(), + command_buffer_allocator: vulkan_context.command_buffer_allocator().clone(), + descriptor_set_allocator: vulkan_context.descriptor_set_allocator().clone(), + event_loop_proxy, + window_id, + + // Données mutables partagées + vulkano_windows, + input_manager, + timer, + gui, + } + } + + /// Récupère les résolutions disponibles du moniteur (méthode utilitaire statique) + fn get_monitor_resolutions(window: &Window) -> Vec<(u32, u32)> { + // Première tentative : moniteur actuel + if let Some(monitor) = window.current_monitor() { + let resolutions = Self::extract_resolutions_from_monitor(&monitor); + if !resolutions.is_empty() { + log::debug!( + "Résolutions trouvées via moniteur actuel: {:?}", + resolutions + ); + return resolutions; + } + } + + // Deuxième tentative : tous les moniteurs disponibles + log::debug!("Tentative de récupération via tous les moniteurs disponibles..."); + let mut all_resolutions = Vec::new(); + + for monitor in window.available_monitors() { + let resolutions = Self::extract_resolutions_from_monitor(&monitor); + all_resolutions.extend(resolutions); + } + + if !all_resolutions.is_empty() { + // Supprime les doublons et trie + all_resolutions.sort_unstable(); + all_resolutions.dedup(); + all_resolutions.sort_by(|a, b| (b.0 * b.1).cmp(&(a.0 * a.1))); + + log::debug!( + "Résolutions trouvées via tous les moniteurs: {:?}", + all_resolutions + ); + return all_resolutions; + } + + // Aucune résolution détectée - retourne un vecteur vide + log::warn!("Aucune résolution détectée pour cette fenêtre"); + Vec::new() + } + + /// Extrait les résolutions d'un moniteur donné + fn extract_resolutions_from_monitor( + monitor: &winit::monitor::MonitorHandle, + ) -> Vec<(u32, u32)> { + let video_modes: Vec<_> = monitor.video_modes().collect(); + + if video_modes.is_empty() { + log::debug!( + "Aucun mode vidéo trouvé pour le moniteur {:?}", + monitor.name() + ); + return Vec::new(); + } + + let resolutions: Vec<(u32, u32)> = video_modes + .into_iter() + .map(|mode| { + let size = mode.size(); + (size.width, size.height) + }) + .collect(); + + log::debug!( + "Modes vidéo trouvés pour {:?}: {:?}", + monitor.name(), + resolutions + ); + resolutions + } + + /// Récupère les résolutions disponibles + pub fn get_available_resolutions(&self) -> Vec<(u32, u32)> { + self.with_renderer(|renderer| Self::get_monitor_resolutions(renderer.window())) + } + + /// Récupère le delta time actuel depuis le timer + pub fn get_delta_time(&self) -> f32 { + self.with_timer(|timer| timer.delta_time()) + } + + /// Récupère la taille de la fenêtre depuis le renderer + pub fn get_window_size(&self) -> [f32; 2] { + self.with_renderer(|renderer| renderer.window_size()) + } + + /// Récupère l'aspect ratio depuis le renderer + pub fn get_aspect_ratio(&self) -> f32 { + self.with_renderer(|renderer| renderer.aspect_ratio()) + } + + pub fn with_renderer(&self, f: F) -> T + where + F: FnOnce(&VulkanoWindowRenderer) -> T, + { + let vulkano_windows = self + .vulkano_windows + .read() + .expect("Failed to lock vulkano_windows"); + let renderer = vulkano_windows + .get_renderer(self.window_id) + .expect("Failed to get renderer"); + f(renderer) + } + + /// Méthode utilitaire pour accéder au renderer de manière thread-safe + pub fn with_renderer_mut(&mut self, f: F) -> T + where + F: FnOnce(&mut VulkanoWindowRenderer) -> T, + { + let mut vulkano_windows = self + .vulkano_windows + .write() + .expect("Failed to lock vulkano_windows"); + let renderer = vulkano_windows + .get_renderer_mut(self.window_id) + .expect("Failed to get renderer"); + f(renderer) + } + + /// Méthode utilitaire pour accéder au gui de manière thread-safe + pub fn with_gui(&self, f: F) -> T + where + F: FnOnce(&Gui) -> T, + { + let gui = self.gui.read().expect("Failed to lock gui"); + f(&gui) + } + + /// Méthode utilitaire pour accéder au gui de manière thread-safe + pub fn with_gui_mut(&mut self, f: F) -> T + where + F: FnOnce(&mut Gui) -> T, + { + let mut gui = self.gui.write().expect("Failed to lock gui"); + f(&mut gui) + } + + /// Méthode utilitaire pour accéder à l'input manager de manière thread-safe + pub fn with_input_manager(&self, f: F) -> T + where + F: FnOnce(&InputManager) -> T, + { + let input_manager = self + .input_manager + .read() + .expect("Failed to lock input_manager"); + f(&input_manager) + } + + /// Méthode utilitaire pour accéder au timer de manière thread-safe + pub fn with_timer(&self, f: F) -> T + where + F: FnOnce(&Timer) -> T, + { + let timer = self.timer.read().expect("Failed to lock timer"); + f(&timer) + } +} diff --git a/src/core/app/mod.rs b/src/core/app/mod.rs new file mode 100644 index 0000000..0a1b3de --- /dev/null +++ b/src/core/app/mod.rs @@ -0,0 +1,243 @@ +use std::collections::HashMap; +use std::rc::Rc; +use std::sync::{Arc, RwLock}; + +use super::render::vulkan_context::VulkanContext; +use crate::core::input::InputManager; +use crate::core::scene::manager::SceneManager; +use crate::core::timer::Timer; +use crate::game::scenes::main_scene::MainScene; +use egui_winit_vulkano::{Gui, GuiConfig}; +use user_event::UserEvent; +use vulkano::format::Format; +use vulkano::image::ImageUsage; +use vulkano::swapchain::PresentMode; +use vulkano_util::context::VulkanoContext; +use vulkano_util::window::{VulkanoWindows, WindowDescriptor}; +use winit::application::ApplicationHandler; +use winit::event::WindowEvent; +use winit::event_loop::{ActiveEventLoop, EventLoopProxy}; +use winit::window::WindowId; + +use self::context::ApplicationContext; + +pub mod context; +pub mod user_event; + +pub const DEPTH_IMAGE_ID: usize = 0; + +pub struct App { + vulkan_context: Arc, + vulkano_windows: Rc>, + gui: HashMap>>, + scene_manager: HashMap, + input_manager: Arc>, + timer: Arc>, + event_loop_proxy: EventLoopProxy, + + // Context d'application partagé par fenêtre - architecture unifiée + app_contexts: HashMap>>, +} + +impl App { + pub fn new( + vulkano_context: VulkanoContext, + input_manager: InputManager, + event_loop_proxy: EventLoopProxy, + ) -> Self { + Self { + vulkan_context: Arc::new(VulkanContext::new(vulkano_context)), + vulkano_windows: Rc::new(RwLock::new(VulkanoWindows::default())), + gui: HashMap::new(), + input_manager: Arc::new(RwLock::new(input_manager)), + scene_manager: HashMap::new(), + timer: Arc::new(RwLock::new(Timer::new())), + event_loop_proxy, + app_contexts: HashMap::new(), + } + } +} + +impl ApplicationHandler for App { + fn resumed(&mut self, event_loop: &ActiveEventLoop) { + let mut vulkano_windows = self + .vulkano_windows + .write() + .expect("Failed to lock vulkano_windows"); + let window_id = vulkano_windows.create_window( + event_loop, + self.vulkan_context.vulkano_context(), + &WindowDescriptor { + title: "Rust ASH Test".to_string(), + width: 800.0, + height: 600.0, + present_mode: PresentMode::Fifo, + cursor_visible: false, + cursor_locked: true, + ..Default::default() + }, + |_| {}, + ); + + let renderer = vulkano_windows.get_renderer_mut(window_id).unwrap(); + renderer.add_additional_image_view( + DEPTH_IMAGE_ID, + Format::D16_UNORM, + ImageUsage::DEPTH_STENCIL_ATTACHMENT, + ); + + let gui = { + Gui::new( + event_loop, + renderer.surface(), + renderer.graphics_queue(), + renderer.swapchain_format(), + GuiConfig { + is_overlay: true, + allow_srgb_render_target: true, + ..Default::default() + }, + ) + }; + self.gui.insert(window_id, Rc::new(RwLock::new(gui))); + + let mut scene_manager = SceneManager::new(); + scene_manager.load_scene(Box::new(MainScene::default())); + + self.scene_manager.insert(window_id, scene_manager); + } + + fn device_event( + &mut self, + _event_loop: &ActiveEventLoop, + _device_id: winit::event::DeviceId, + event: winit::event::DeviceEvent, + ) { + let mut input_manager = self.input_manager.write().unwrap(); + input_manager.process_device_event(&event); + } + + fn window_event(&mut self, event_loop: &ActiveEventLoop, id: WindowId, event: WindowEvent) { + { + let gui = self.gui.get_mut(&id).unwrap(); + let mut gui = gui.write().expect("Failed to lock gui"); + if !gui.update(&event) { + let mut input_manager = self.input_manager.write().unwrap(); + input_manager.process_window_event(&event); + } + } + + match event { + WindowEvent::CloseRequested => { + log::debug!("The close button was pressed; stopping"); + event_loop.exit(); + } + WindowEvent::Resized(_) | WindowEvent::ScaleFactorChanged { .. } => { + let mut vulkano_windows = self.vulkano_windows.write().unwrap(); + vulkano_windows.get_renderer_mut(id).unwrap().resize(); + } + WindowEvent::RedrawRequested => { + { + let mut input_manager = self + .input_manager + .write() + .expect("Failed to lock input manager"); + input_manager.update(); + } + { + let mut timer = self.timer.write().expect("Failed to lock timer"); + timer.update(); + } + + // Créer ou mettre à jour le contexte d'application + let app_context = self + .app_contexts + .entry(id) + .or_insert_with(|| { + Rc::new(RwLock::new(ApplicationContext::new( + self.vulkan_context.clone(), + self.vulkano_windows.clone(), + self.input_manager.clone(), + self.timer.clone(), + self.gui.get(&id).unwrap().clone(), + self.event_loop_proxy.clone(), + id, + ))) + }) + .clone(); + + let scene_manager = self.scene_manager.get_mut(&id).unwrap(); + + // Utiliser le contexte partagé pour les scènes + { + let mut context = app_context.write().unwrap(); + + scene_manager + .load_scene_if_not_loaded(&mut context) + .unwrap(); + + if let Some(scene) = scene_manager.current_scene_mut() { + scene.update(&mut context).unwrap(); + + let acquire_future = context + .with_renderer_mut(|renderer| renderer.acquire(None, |_| {}).unwrap()); + + let acquire_future = scene.render(acquire_future, &mut context).unwrap(); + + context.with_renderer_mut(|renderer| { + renderer.present(acquire_future, true); + }); + } else { + log::warn!("No current scene found for update!"); + } + } + } + _ => {} + } + } + + fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) { + let vulkano_windows = self.vulkano_windows.read().unwrap(); + let window = vulkano_windows.get_primary_window().unwrap(); + window.request_redraw(); + } + + fn user_event(&mut self, event_loop: &ActiveEventLoop, event: UserEvent) { + match event { + UserEvent::CursorGrabMode(window_id, grab) => { + let vulkano_windows = self.vulkano_windows.read().unwrap(); + let window = vulkano_windows.get_window(window_id).unwrap(); + if let Err(e) = window.set_cursor_grab(grab) { + log::error!("Failed to set cursor grab: {}", e); + } + } + UserEvent::CursorVisible(window_id, visible) => { + let vulkano_windows = self.vulkano_windows.read().unwrap(); + let window = vulkano_windows.get_window(window_id).unwrap(); + window.set_cursor_visible(visible); + } + UserEvent::ChangeScene(window_id, scene) => { + if let Some(scene_manager) = self.scene_manager.get_mut(&window_id) { + scene_manager.load_scene(scene); + } + } + UserEvent::ChangeResolution(window_id, width, height) => { + let mut vulkano_windows = self.vulkano_windows.write().unwrap(); + let window = vulkano_windows.get_window(window_id).unwrap(); + let _ = window.request_inner_size(winit::dpi::LogicalSize::new(width, height)); + let renderer = vulkano_windows.get_renderer_mut(window_id).unwrap(); + renderer.resize(); + log::info!( + "Resolution changed to {}x{} for window {:?}", + width, + height, + window_id + ); + } + UserEvent::Exit(window_id) => { + log::info!("Exit requested for window {:?}", window_id); + event_loop.exit(); + } + } + } +} diff --git a/src/core/app/user_event.rs b/src/core/app/user_event.rs new file mode 100644 index 0000000..21b70f1 --- /dev/null +++ b/src/core/app/user_event.rs @@ -0,0 +1,11 @@ +use winit::window::{CursorGrabMode, WindowId}; + +use crate::core::scene::Scene; + +pub enum UserEvent { + CursorGrabMode(WindowId, CursorGrabMode), + CursorVisible(WindowId, bool), + ChangeScene(WindowId, Box), + ChangeResolution(WindowId, f32, f32), + Exit(WindowId), +} diff --git a/src/core/input/cache.rs b/src/core/input/cache.rs new file mode 100644 index 0000000..b9d562c --- /dev/null +++ b/src/core/input/cache.rs @@ -0,0 +1,86 @@ +use std::{ + collections::HashMap, + hash::Hash, + ops::{Add, AddAssign, Sub}, +}; + +use winit::event::ElementState; + +pub struct CachedElementState { + cache: HashMap, +} + +impl Default for CachedElementState { + fn default() -> Self { + Self { + cache: HashMap::new(), + } + } +} + +impl CachedElementState { + pub fn set_key_state(&mut self, key: K, state: ElementState) -> Option { + let key_state = self.cache.get(&key); + let new_key_state = match key_state { + Some(old) => match state { + ElementState::Pressed => match old { + ElementState::Released => Some(ElementState::Pressed), + ElementState::Pressed => None, + }, + ElementState::Released => match old { + ElementState::Released => None, + ElementState::Pressed => Some(ElementState::Released), + }, + }, + None => match state { + ElementState::Pressed => Some(ElementState::Pressed), + ElementState::Released => Some(ElementState::Released), + }, + }; + if let Some(new_key_state) = new_key_state { + self.cache.insert(key, new_key_state); + } + new_key_state + } +} + +#[derive(Default)] +pub struct CachedMovement +where + T: Sub + Add + Default + Copy, +{ + pub old_value: Option, + pub value: T, +} + +impl CachedMovement +where + T: Sub + Add + Default + Copy, +{ + pub fn set_value(&mut self, value: T) { + self.value = value; + } + + pub fn reset(&mut self) -> T { + match self.old_value.as_ref() { + Some(old_value) => { + let diff = self.value - *old_value; + self.old_value = Some(self.value); + diff + } + None => { + self.old_value = Some(self.value); + T::default() + } + } + } +} + +impl AddAssign for CachedMovement +where + T: Add + Sub + Default + Copy, +{ + fn add_assign(&mut self, rhs: T) { + self.value = self.value + rhs; + } +} diff --git a/src/core/input/mod.rs b/src/core/input/mod.rs new file mode 100644 index 0000000..f4a1642 --- /dev/null +++ b/src/core/input/mod.rs @@ -0,0 +1,97 @@ +use std::collections::HashMap; + +use cache::{CachedElementState, CachedMovement}; +use virtual_input::VirtualInput; +use winit::{ + event::{DeviceEvent, MouseButton, MouseScrollDelta, WindowEvent}, + keyboard::PhysicalKey, +}; + +mod cache; +mod virtual_binding; +mod virtual_input; +mod virtual_state; +pub use virtual_binding::{AxisDirection, VirtualBinding}; + +#[derive(Default)] +pub struct InputManager { + keys_state: CachedElementState, + mouse_buttons_state: CachedElementState, + mouse_position_delta: CachedMovement, + mouse_wheel_delta: CachedMovement, + virtual_input: VirtualInput, +} + +impl std::fmt::Debug for InputManager { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("InputManager") + .field("virtual_input", &self.virtual_input) + .finish() + } +} + +impl InputManager { + pub fn new(input_mapping: HashMap>) -> Self { + let mut input_manager = InputManager::default(); + for (value_name, bindings) in input_mapping { + input_manager.add_virtual_bindings(value_name, bindings); + } + input_manager + } + + pub fn process_device_event(&mut self, event: &DeviceEvent) { + if let DeviceEvent::MouseMotion { delta, .. } = event { + self.mouse_position_delta += glam::Vec2::new(delta.0 as f32, delta.1 as f32); + } + } + + pub fn process_window_event(&mut self, event: &WindowEvent) { + match event { + WindowEvent::AxisMotion { axis, value, .. } => { + self.virtual_input.update_axis_binding(*axis, *value as f32); + } + WindowEvent::KeyboardInput { event, .. } => { + let new_key_state = self + .keys_state + .set_key_state(event.physical_key, event.state); + if let Some(new_key_state) = new_key_state { + self.virtual_input + .update_key_binding(event.physical_key, new_key_state); + } + } + WindowEvent::MouseInput { button, state, .. } => { + let new_mouse_button_state = + self.mouse_buttons_state.set_key_state(*button, *state); + if let Some(new_mouse_button_state) = new_mouse_button_state { + self.virtual_input + .update_mouse_button_binding(*button, new_mouse_button_state); + } + } + WindowEvent::MouseWheel { delta, .. } => { + self.mouse_wheel_delta += match delta { + MouseScrollDelta::PixelDelta(position) => { + glam::Vec2::new(position.x as f32, position.y as f32) + } + MouseScrollDelta::LineDelta(x, y) => glam::Vec2::new(*x, *y), + }; + } + _ => {} + } + } + + /// Updates deltas before running update + pub fn update(&mut self) { + self.virtual_input + .update_mouse_move_binding(&self.mouse_position_delta.reset()); + self.virtual_input + .update_mouse_wheel_binding(&self.mouse_wheel_delta.reset()); + } + + pub fn get_virtual_input_state(&self, value_name: &str) -> f32 { + self.virtual_input.get_state(value_name) + } + + fn add_virtual_bindings(&mut self, value_name: String, bindings: Vec) { + self.virtual_input.add_bindings(value_name, bindings); + } +} diff --git a/src/core/input/virtual_binding.rs b/src/core/input/virtual_binding.rs new file mode 100644 index 0000000..c11dd48 --- /dev/null +++ b/src/core/input/virtual_binding.rs @@ -0,0 +1,30 @@ +use winit::{ + event::{AxisId, MouseButton}, + keyboard::PhysicalKey, +}; + +#[derive(Clone)] +pub enum AxisDirection { + Normal, + Invert, +} + +impl From<&AxisDirection> for f32 { + fn from(direction: &AxisDirection) -> Self { + match direction { + AxisDirection::Normal => 1.0, + AxisDirection::Invert => -1.0, + } + } +} + +#[derive(Clone)] +pub enum VirtualBinding { + Keyboard(PhysicalKey, AxisDirection), + Axis(AxisId, AxisDirection, f32), // f32 deadzone + MouseX(AxisDirection), + MouseY(AxisDirection), + MouseWheelX(AxisDirection), + MouseWheelY(AxisDirection), + MouseButton(MouseButton, AxisDirection), +} diff --git a/src/core/input/virtual_input.rs b/src/core/input/virtual_input.rs new file mode 100644 index 0000000..26ac882 --- /dev/null +++ b/src/core/input/virtual_input.rs @@ -0,0 +1,144 @@ +use std::{collections::HashMap, sync::Arc}; + +use egui_winit_vulkano::egui::mutex::Mutex; +use winit::{ + event::{AxisId, ElementState, MouseButton}, + keyboard::PhysicalKey, +}; + +use super::{ + virtual_binding::VirtualBinding, + virtual_state::{VirtualBindingState, VirtualInputState}, +}; + +#[derive(Default)] +pub struct VirtualInput { + // Global states + states: HashMap>>, + + // Per kind of input states to keep complexity low during state updates + states_by_key: HashMap>>>, + mouse_move_states: Vec>>, + mouse_wheel_states: Vec>>, + mouse_button_states: HashMap>>>, + axis_states: HashMap>>>, +} + +impl std::fmt::Debug for VirtualInput { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut debug = f.debug_struct("VirtualInput"); + + for (name, state) in &self.states { + debug.field(name, &state.lock().value); + } + + debug.finish() + } +} + +impl VirtualInput { + pub fn get_state(&self, value_name: &str) -> f32 { + self.states + .get(value_name) + .map(|state| state.lock().value) + .unwrap_or(0.0) + } + + pub fn add_bindings(&mut self, value_name: String, new_bindings: Vec) { + let state = + self.states + .entry(value_name) + .or_insert(Arc::new(Mutex::new(VirtualInputState { + value: 0.0, + bindings: Vec::new(), + }))); + + for binding in &new_bindings { + match binding { + VirtualBinding::Keyboard(key, _) => { + self.states_by_key + .entry(*key) + .or_default() + .push(state.clone()); + } + VirtualBinding::MouseX(_) | VirtualBinding::MouseY(_) => { + self.mouse_move_states.push(state.clone()); + } + VirtualBinding::MouseButton(button, _) => { + self.mouse_button_states + .entry(*button) + .or_default() + .push(state.clone()); + } + VirtualBinding::MouseWheelX(_) | VirtualBinding::MouseWheelY(_) => { + self.mouse_wheel_states.push(state.clone()); + } + VirtualBinding::Axis(axis, _, _) => { + self.axis_states + .entry(*axis) + .or_default() + .push(state.clone()); + } + } + } + + state + .lock() + .bindings + .extend(new_bindings.iter().map(|b| VirtualBindingState { + value: 0.0, + binding: b.clone(), + })); + } + + pub(super) fn update_key_binding(&mut self, key: PhysicalKey, key_state: ElementState) { + let states = self.states_by_key.get_mut(&key); + + if let Some(states) = states { + for state in states { + let mut state = state.lock(); + state.update_from_key(key, key_state); + } + } + } + + pub(super) fn update_mouse_move_binding(&mut self, delta: &glam::Vec2) { + for state in &mut self.mouse_move_states { + let mut state = state.lock(); + state.update_from_mouse(delta); + } + } + + pub(super) fn update_mouse_wheel_binding(&mut self, delta: &glam::Vec2) { + for state in &mut self.mouse_wheel_states { + let mut state = state.lock(); + state.update_from_mouse_wheel(delta); + } + } + + pub(super) fn update_mouse_button_binding( + &mut self, + button: MouseButton, + button_state: ElementState, + ) { + let states = self.mouse_button_states.get_mut(&button); + + if let Some(states) = states { + for state in states { + let mut state = state.lock(); + state.update_from_mouse_button(button, button_state); + } + } + } + + pub(super) fn update_axis_binding(&mut self, axis: AxisId, axis_state: f32) { + let states = self.axis_states.get_mut(&axis); + + if let Some(states) = states { + for state in states { + let mut state = state.lock(); + state.update_from_axis(axis, axis_state); + } + } + } +} diff --git a/src/core/input/virtual_state.rs b/src/core/input/virtual_state.rs new file mode 100644 index 0000000..2cfd098 --- /dev/null +++ b/src/core/input/virtual_state.rs @@ -0,0 +1,105 @@ +use winit::{ + event::{AxisId, ElementState, MouseButton}, + keyboard::PhysicalKey, +}; + +use super::virtual_binding::VirtualBinding; + +pub struct VirtualBindingState { + pub value: f32, + pub binding: VirtualBinding, +} + +pub struct VirtualInputState { + pub value: f32, + pub bindings: Vec, +} + +impl VirtualInputState { + pub fn update_from_key(&mut self, key: PhysicalKey, key_state: ElementState) { + let mut new_value = 0.0; + for binding in &mut self.bindings { + if let VirtualBinding::Keyboard(binding_key, direction) = &binding.binding { + if binding_key == &key { + if key_state == ElementState::Pressed { + binding.value += f32::from(direction); + } else { + binding.value = 0.0; + } + } + } + new_value += binding.value; + } + self.value = new_value; + } + + pub fn update_from_mouse(&mut self, delta: &glam::Vec2) { + let mut new_value = 0.0; + for binding in &mut self.bindings { + match &binding.binding { + VirtualBinding::MouseX(direction) => { + binding.value = f32::from(direction) * delta.x; + } + VirtualBinding::MouseY(direction) => { + binding.value = f32::from(direction) * delta.y; + } + _ => {} + } + new_value += binding.value; + } + self.value = new_value; + } + + pub fn update_from_mouse_wheel(&mut self, delta: &glam::Vec2) { + let mut new_value = 0.0; + for binding in &mut self.bindings { + match &binding.binding { + VirtualBinding::MouseWheelX(direction) => { + binding.value = f32::from(direction) * delta.x; + } + VirtualBinding::MouseWheelY(direction) => { + binding.value = f32::from(direction) * delta.y; + } + _ => {} + } + new_value += binding.value; + } + self.value = new_value; + } + + pub fn update_from_mouse_button(&mut self, button: MouseButton, button_state: ElementState) { + let mut new_value = 0.0; + for binding in &mut self.bindings { + if let VirtualBinding::MouseButton(binding_button, direction) = &binding.binding { + if binding_button == &button { + if button_state == ElementState::Pressed { + binding.value = f32::from(direction); + } else { + binding.value = 0.0; + } + } + } + new_value += binding.value; + } + self.value = new_value; + } + + pub fn update_from_axis(&mut self, axis: AxisId, axis_state: f32) { + let mut new_value = 0.0; + for binding in &mut self.bindings { + if let VirtualBinding::Axis(binding_axis, direction, deadzone) = &binding.binding { + if binding_axis == &axis { + binding.value = + f32::from(direction) * process_axis_deadzone(axis_state, *deadzone); + } + } + new_value += binding.value; + } + self.value = new_value; + } +} + +#[inline] +fn process_axis_deadzone(value: f32, deadzone: f32) -> f32 { + if value.abs() < deadzone { 0.0 } else { value } +} diff --git a/src/core/mod.rs b/src/core/mod.rs new file mode 100644 index 0000000..237496d --- /dev/null +++ b/src/core/mod.rs @@ -0,0 +1,5 @@ +pub mod app; +pub mod input; +pub mod render; +pub mod scene; +pub mod timer; diff --git a/src/core/render/mod.rs b/src/core/render/mod.rs new file mode 100644 index 0000000..f56fdf4 --- /dev/null +++ b/src/core/render/mod.rs @@ -0,0 +1,4 @@ +pub mod primitives; +pub mod render_pass_manager; +pub mod texture; +pub mod vulkan_context; diff --git a/src/core/render/primitives/camera.rs b/src/core/render/primitives/camera.rs new file mode 100644 index 0000000..f27622a --- /dev/null +++ b/src/core/render/primitives/camera.rs @@ -0,0 +1,122 @@ +use std::{f32::consts::FRAC_PI_2, sync::Arc}; + +use glam::{Mat4, Vec3, Vec4}; +use vulkano::{ + Validated, + buffer::{AllocateBufferError, Subbuffer}, + memory::allocator::StandardMemoryAllocator, +}; + +use crate::core::{input::InputManager, timer::Timer}; + +use super::mvp::Mvp; + +// See docs/OPENGL_VULKAN_DIFF.md +const OPENGL_TO_VULKAN_Y_AXIS_FLIP: Mat4 = Mat4 { + x_axis: Vec4::new(1.0, 0.0, 0.0, 0.0), + y_axis: Vec4::new(0.0, -1.0, 0.0, 0.0), + z_axis: Vec4::new(0.0, 0.0, 1.0, 0.0), + w_axis: Vec4::new(0.0, 0.0, 0.0, 1.0), +}; + +#[derive(Default)] +pub struct Camera3D { + projection: Mat4, + + position: Vec3, + rotation: Vec3, + aspect_ratio: f32, + fov: f32, + near: f32, + far: f32, +} + +impl Camera3D { + pub fn new(aspect_ratio: f32, fov: f32, near: f32, far: f32) -> Self { + Self { + projection: Mat4::perspective_rh(fov, aspect_ratio, near, far), + position: Vec3::ZERO, + rotation: Vec3::ZERO, + aspect_ratio, + fov, + near, + far, + } + } + + pub fn update( + &mut self, + input_manager: &InputManager, + timer: &Timer, + movement_speed: f32, + camera_sensitivity: f32, + window_aspect_ratio: f32, + ) { + // Process camera rotation + let camera_delta = camera_sensitivity * timer.delta_time(); + self.rotation += Vec3::new( + (input_manager.get_virtual_input_state("mouse_y") * camera_delta).to_radians(), + (input_manager.get_virtual_input_state("mouse_x") * camera_delta).to_radians(), + 0.0, + ); + + if self.rotation.x > FRAC_PI_2 { + self.rotation = Vec3::new(FRAC_PI_2, self.rotation.y, 0.0); + } + + if self.rotation.x < -FRAC_PI_2 { + self.rotation = Vec3::new(-FRAC_PI_2, self.rotation.y, 0.0); + } + + let movement_delta = movement_speed * timer.delta_time(); + + let (yaw_sin, yaw_cos) = self.rotation.y.sin_cos(); + let forward = Vec3::new(yaw_cos, 0.0, yaw_sin).normalize(); + let right = Vec3::new(-yaw_sin, 0.0, yaw_cos).normalize(); + + let tx = input_manager.get_virtual_input_state("move_right") * movement_delta; + self.position += tx * right; + + let tz = input_manager.get_virtual_input_state("move_forward") * movement_delta; + self.position += tz * forward; + + if self.aspect_ratio != window_aspect_ratio { + self.aspect_ratio = window_aspect_ratio; + self.projection = + Mat4::perspective_rh(self.fov, self.aspect_ratio, self.near, self.far); + } + } + + pub fn set_projection(&mut self, projection: Mat4) { + self.projection = projection; + } + + pub fn get_position(&self) -> Vec3 { + self.position + } + + pub fn get_rotation(&self) -> Vec3 { + self.rotation + } + + pub fn create_buffer( + &self, + memory_allocator: &Arc, + ) -> Result, Validated> { + let (sin_pitch, cos_pitch) = self.rotation.x.sin_cos(); + let (sin_yaw, cos_yaw) = self.rotation.y.sin_cos(); + + let view_matrix = Mat4::look_to_rh( + self.position, + Vec3::new(cos_pitch * cos_yaw, sin_pitch, cos_pitch * sin_yaw).normalize(), + Vec3::Y, + ); + + Mvp { + model: OPENGL_TO_VULKAN_Y_AXIS_FLIP.to_cols_array_2d(), + view: view_matrix.to_cols_array_2d(), + projection: self.projection.to_cols_array_2d(), + } + .into_buffer(memory_allocator) + } +} diff --git a/src/core/render/primitives/mod.rs b/src/core/render/primitives/mod.rs new file mode 100644 index 0000000..606c12d --- /dev/null +++ b/src/core/render/primitives/mod.rs @@ -0,0 +1,4 @@ +pub mod camera; +pub mod mvp; +pub mod transform; +pub mod vertex; diff --git a/src/core/render/primitives/mvp.rs b/src/core/render/primitives/mvp.rs new file mode 100644 index 0000000..192c67b --- /dev/null +++ b/src/core/render/primitives/mvp.rs @@ -0,0 +1,36 @@ +use std::sync::Arc; + +use vulkano::Validated; +use vulkano::buffer::{ + AllocateBufferError, Buffer, BufferContents, BufferCreateInfo, BufferUsage, Subbuffer, +}; +use vulkano::memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator}; + +#[derive(BufferContents, Clone, Copy)] +#[repr(C)] +pub struct Mvp { + pub model: [[f32; 4]; 4], + pub view: [[f32; 4]; 4], + pub projection: [[f32; 4]; 4], +} + +impl Mvp { + pub fn into_buffer( + self, + memory_allocator: &Arc, + ) -> Result, Validated> { + Buffer::from_iter( + memory_allocator.clone(), + BufferCreateInfo { + usage: BufferUsage::UNIFORM_BUFFER, + ..Default::default() + }, + AllocationCreateInfo { + memory_type_filter: MemoryTypeFilter::PREFER_DEVICE + | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, + ..Default::default() + }, + [self], + ) + } +} diff --git a/src/core/render/primitives/transform.rs b/src/core/render/primitives/transform.rs new file mode 100644 index 0000000..4d870b0 --- /dev/null +++ b/src/core/render/primitives/transform.rs @@ -0,0 +1,81 @@ +use std::sync::Arc; + +use glam::{Mat4, Quat, Vec3}; +use vulkano::{ + Validated, + buffer::{ + AllocateBufferError, Buffer, BufferContents, BufferCreateInfo, BufferUsage, Subbuffer, + }, + memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator}, + pipeline::graphics::vertex_input::Vertex, +}; + +pub struct Transform { + pub position: Vec3, + pub rotation: Quat, + pub scale: Vec3, +} + +#[derive(BufferContents, Vertex)] +#[repr(C)] +pub struct TransformRaw { + #[format(R32G32B32A32_SFLOAT)] + pub model: [[f32; 4]; 4], +} + +impl Default for Transform { + fn default() -> Self { + Self { + position: Vec3::default(), + rotation: Quat::default(), + scale: Vec3::ONE, + } + } +} + +impl Transform { + pub fn rotate(&mut self, rotation: Quat) { + self.rotation *= rotation; + } + + pub fn translate(&mut self, translation: Vec3) { + self.position += translation; + } + + pub fn scale(&mut self, scale: Vec3) { + self.scale *= scale; + } + + pub fn to_raw_tranform(&self) -> TransformRaw { + TransformRaw { + model: (Mat4::from_translation(self.position) + * Mat4::from_quat(self.rotation) + * Mat4::from_scale(self.scale)) + .to_cols_array_2d(), + } + } + + pub fn create_buffer( + memory_allocator: &Arc, + transforms: &[Transform], + ) -> Result, Validated> { + let transform_raws: Vec = + transforms.iter().map(|t| t.to_raw_tranform()).collect(); + + let buffer = Buffer::from_iter( + memory_allocator.clone(), + BufferCreateInfo { + usage: BufferUsage::VERTEX_BUFFER, + ..Default::default() + }, + AllocationCreateInfo { + memory_type_filter: MemoryTypeFilter::PREFER_DEVICE + | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, + ..Default::default() + }, + transform_raws, + )?; + + Ok(buffer) + } +} diff --git a/src/core/render/primitives/vertex.rs b/src/core/render/primitives/vertex.rs new file mode 100644 index 0000000..166ac44 --- /dev/null +++ b/src/core/render/primitives/vertex.rs @@ -0,0 +1,22 @@ +use vulkano::buffer::BufferContents; +use vulkano::pipeline::graphics::vertex_input::Vertex; + +#[derive(BufferContents, Vertex)] +#[repr(C)] +pub struct Vertex2D { + #[format(R32G32_SFLOAT)] + pub position: [f32; 2], + + #[format(R32G32_SFLOAT)] + pub uv: [f32; 2], +} + +#[derive(BufferContents, Vertex)] +#[repr(C)] +pub struct Vertex3D { + #[format(R32G32B32_SFLOAT)] + pub position: [f32; 3], + + #[format(R32G32_SFLOAT)] + pub uv: [f32; 2], +} diff --git a/src/core/render/render_pass_manager.rs b/src/core/render/render_pass_manager.rs new file mode 100644 index 0000000..02c3d7a --- /dev/null +++ b/src/core/render/render_pass_manager.rs @@ -0,0 +1,113 @@ +use std::sync::Arc; +use vulkano::{ + command_buffer::{AutoCommandBufferBuilder, RenderingAttachmentInfo, RenderingInfo}, + image::view::ImageView, + pipeline::graphics::viewport::Viewport, + render_pass::{AttachmentLoadOp, AttachmentStoreOp}, +}; + +/// Types de render passes disponibles +#[derive(Debug, Clone)] +pub enum RenderPassType { + Standard, + ShadowMap, + PostProcess, +} + +/// Configuration pour un render pass +#[derive(Debug, Clone)] +pub struct RenderPassConfig { + pub pass_type: RenderPassType, + pub clear_color: Option<[f32; 4]>, + pub clear_depth: Option, + pub load_op: AttachmentLoadOp, + pub store_op: AttachmentStoreOp, +} + +impl Default for RenderPassConfig { + fn default() -> Self { + Self { + pass_type: RenderPassType::Standard, + clear_color: Some([0.0, 0.0, 0.0, 1.0]), + clear_depth: Some(1.0), + load_op: AttachmentLoadOp::Clear, + store_op: AttachmentStoreOp::Store, + } + } +} + +/// Gestionnaire de render passes réutilisable +pub struct RenderPassManager; + +impl RenderPassManager { + /// Commence un render pass standard avec les paramètres donnés + pub fn begin_standard_rendering( + builder: &mut AutoCommandBufferBuilder, + config: &RenderPassConfig, + color_attachment: Arc, + depth_attachment: Option>, + window_size: [f32; 2], + ) -> Result<(), Box> { + let viewport = Viewport { + offset: [0.0, 0.0], + extent: window_size, + depth_range: 0.0..=1.0, + }; + + let mut rendering_info = RenderingInfo { + color_attachments: vec![Some(RenderingAttachmentInfo { + load_op: config.load_op, + store_op: config.store_op, + clear_value: config.clear_color.map(|c| c.into()), + ..RenderingAttachmentInfo::image_view(color_attachment) + })], + depth_attachment: None, + ..Default::default() + }; + + if let Some(depth_view) = depth_attachment { + rendering_info.depth_attachment = Some(RenderingAttachmentInfo { + load_op: AttachmentLoadOp::Clear, + store_op: AttachmentStoreOp::DontCare, + clear_value: config.clear_depth.map(|d| [d].into()), + ..RenderingAttachmentInfo::image_view(depth_view) + }); + } + + builder + .begin_rendering(rendering_info)? + .set_viewport(0, [viewport].into_iter().collect())?; + + Ok(()) + } + + /// Termine le render pass actuel + pub fn end_rendering( + builder: &mut AutoCommandBufferBuilder, + ) -> Result<(), Box> { + builder.end_rendering()?; + Ok(()) + } + + /// Crée une configuration pour un render pass shadow map + pub fn shadow_map_config() -> RenderPassConfig { + RenderPassConfig { + pass_type: RenderPassType::ShadowMap, + clear_color: None, + clear_depth: Some(1.0), + load_op: AttachmentLoadOp::Clear, + store_op: AttachmentStoreOp::Store, + } + } + + /// Crée une configuration pour un render pass de post-processing + pub fn post_process_config() -> RenderPassConfig { + RenderPassConfig { + pass_type: RenderPassType::PostProcess, + clear_color: Some([0.0, 0.0, 0.0, 1.0]), + clear_depth: None, + load_op: AttachmentLoadOp::Load, + store_op: AttachmentStoreOp::Store, + } + } +} diff --git a/src/core/render/texture.rs b/src/core/render/texture.rs new file mode 100644 index 0000000..b8270da --- /dev/null +++ b/src/core/render/texture.rs @@ -0,0 +1,118 @@ +use std::{path::Path, sync::Arc}; + +use anyhow::Error; +use image::{DynamicImage, EncodableLayout}; +use vulkano::{ + buffer::{Buffer, BufferCreateInfo, BufferUsage}, + command_buffer::{AutoCommandBufferBuilder, CopyBufferToImageInfo, PrimaryAutoCommandBuffer}, + device::Device, + format::Format, + image::{ + Image, ImageCreateInfo, ImageType, ImageUsage, + sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo}, + view::ImageView, + }, + memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator}, +}; + +pub struct Texture { + texture: Arc, + sampler: Arc, +} + +impl Texture { + fn new(texture: Arc, sampler: Arc) -> Self { + Self { texture, sampler } + } + + pub fn from_file( + device: &Arc, + memory_allocator: &Arc, + builder: &mut AutoCommandBufferBuilder, + path: &str, + ) -> Result { + let image = image::open(path)?; + Self::from_dynamic_image(device, memory_allocator, builder, image) + } + + pub fn from_bytes( + device: &Arc, + memory_allocator: &Arc, + builder: &mut AutoCommandBufferBuilder, + bytes: &[u8], + ) -> Result { + let image = image::load_from_memory(bytes)?; + Self::from_dynamic_image(device, memory_allocator, builder, image) + } + + pub fn from_dynamic_image( + device: &Arc, + memory_allocator: &Arc, + builder: &mut AutoCommandBufferBuilder, + image: DynamicImage, + ) -> Result { + let image_data = image.to_rgba8(); + let image_dimensions = image_data.dimensions(); + + let upload_buffer = Buffer::new_slice( + memory_allocator.clone(), + BufferCreateInfo { + usage: BufferUsage::TRANSFER_SRC, + ..Default::default() + }, + AllocationCreateInfo { + memory_type_filter: MemoryTypeFilter::PREFER_HOST + | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, + ..Default::default() + }, + image_data.len() as u64, + )?; + + { + let buffer_data = &mut *upload_buffer.write()?; + buffer_data.copy_from_slice(image_data.as_raw()); + } + + let image = Image::new( + memory_allocator.clone(), + ImageCreateInfo { + image_type: ImageType::Dim2d, + format: Format::R8G8B8A8_SRGB, + extent: [image_dimensions.0, image_dimensions.1, 1], + array_layers: 1, + usage: ImageUsage::TRANSFER_DST | ImageUsage::SAMPLED, + ..Default::default() + }, + AllocationCreateInfo::default(), + )?; + + builder.copy_buffer_to_image(CopyBufferToImageInfo::buffer_image( + upload_buffer, + image.clone(), + ))?; + + let sampler = Sampler::new( + device.clone(), + SamplerCreateInfo { + mag_filter: Filter::Linear, + min_filter: Filter::Linear, + address_mode: [SamplerAddressMode::Repeat; 3], + ..Default::default() + }, + )?; + + let image_view = ImageView::new_default(image)?; + + log::trace!("Texture loaded with dimensions {:?}", image_dimensions); + + Ok(Self::new(image_view, sampler)) + } + + pub fn get_texture(&self) -> &Arc { + &self.texture + } + + pub fn get_sampler(&self) -> &Arc { + &self.sampler + } +} diff --git a/src/core/render/vulkan_context.rs b/src/core/render/vulkan_context.rs new file mode 100644 index 0000000..3d91ec3 --- /dev/null +++ b/src/core/render/vulkan_context.rs @@ -0,0 +1,45 @@ +use std::sync::Arc; + +use vulkano::{ + command_buffer::allocator::StandardCommandBufferAllocator, + descriptor_set::allocator::StandardDescriptorSetAllocator, +}; +use vulkano_util::context::VulkanoContext; + +pub struct VulkanContext { + vulkano_context: VulkanoContext, + command_buffer_allocator: Arc, + descriptor_set_allocator: Arc, +} + +impl VulkanContext { + pub fn new(vulkano_context: VulkanoContext) -> Self { + let command_buffer_allocator = Arc::new(StandardCommandBufferAllocator::new( + vulkano_context.device().clone(), + Default::default(), + )); + + let descriptor_set_allocator = Arc::new(StandardDescriptorSetAllocator::new( + vulkano_context.device().clone(), + Default::default(), + )); + + Self { + vulkano_context, + command_buffer_allocator, + descriptor_set_allocator, + } + } + + pub fn vulkano_context(&self) -> &VulkanoContext { + &self.vulkano_context + } + + pub fn command_buffer_allocator(&self) -> &Arc { + &self.command_buffer_allocator + } + + pub fn descriptor_set_allocator(&self) -> &Arc { + &self.descriptor_set_allocator + } +} diff --git a/src/core/scene/manager.rs b/src/core/scene/manager.rs new file mode 100644 index 0000000..a12892e --- /dev/null +++ b/src/core/scene/manager.rs @@ -0,0 +1,65 @@ +use std::error::Error; + +use crate::core::app::context::ApplicationContext; + +use super::Scene; + +pub struct SceneManager { + scenes: Vec>, + current_scene_index: Option, +} + +impl SceneManager { + pub fn new() -> Self { + Self { + scenes: Vec::new(), + current_scene_index: None, + } + } + + pub fn load_scene(&mut self, scene: Box) { + self.scenes.push(scene); + self.current_scene_index = Some(self.scenes.len() - 1); + } + + pub fn replace_current_scene(&mut self, scene: Box) { + if let Some(index) = self.current_scene_index { + if index < self.scenes.len() { + self.scenes[index].unload(); + self.scenes[index] = scene; + } + } else { + self.load_scene(scene); + } + } + + pub fn current_scene(&self) -> Option<&Box> { + if let Some(index) = self.current_scene_index { + self.scenes.get(index) + } else { + None + } + } + + pub fn current_scene_mut(&mut self) -> Option<&mut Box> { + if let Some(index) = self.current_scene_index { + self.scenes.get_mut(index) + } else { + None + } + } + + pub fn load_scene_if_not_loaded( + &mut self, + app_context: &mut ApplicationContext, + ) -> Result<(), Box> { + if let Some(scene) = self.current_scene_mut() { + if !scene.loaded() { + scene.load(app_context)?; + } + } else { + log::warn!("No scene found in SceneManager!"); + } + Ok(()) + } +} diff --git a/src/core/scene/mod.rs b/src/core/scene/mod.rs new file mode 100644 index 0000000..58a75df --- /dev/null +++ b/src/core/scene/mod.rs @@ -0,0 +1,19 @@ +use std::error::Error; + +use vulkano::sync::GpuFuture; + +use crate::core::app::context::ApplicationContext; + +pub mod manager; + +pub trait Scene { + fn loaded(&self) -> bool; + fn load(&mut self, app_context: &mut ApplicationContext) -> Result<(), Box>; + fn update(&mut self, app_context: &mut ApplicationContext) -> Result<(), Box>; + fn render( + &mut self, + acquire_future: Box, + app_context: &mut ApplicationContext, + ) -> Result, Box>; + fn unload(&mut self); +} diff --git a/src/core/timer.rs b/src/core/timer.rs new file mode 100644 index 0000000..3245a4c --- /dev/null +++ b/src/core/timer.rs @@ -0,0 +1,34 @@ +pub struct Timer { + start_time: std::time::Instant, + last_time: std::time::Instant, + current_time: std::time::Instant, + delta_time: f32, +} + +impl Timer { + pub fn new() -> Self { + Self { + start_time: std::time::Instant::now(), + last_time: std::time::Instant::now(), + current_time: std::time::Instant::now(), + delta_time: 0.0, + } + } + + pub fn update(&mut self) { + self.current_time = std::time::Instant::now(); + self.delta_time = self + .current_time + .duration_since(self.last_time) + .as_secs_f32(); + self.last_time = self.current_time; + } + + pub fn delta_time(&self) -> f32 { + self.delta_time + } + + pub fn start_time(&self) -> std::time::Instant { + self.start_time + } +} diff --git a/src/display/app.rs b/src/display/app.rs deleted file mode 100644 index 0d5fb1d..0000000 --- a/src/display/app.rs +++ /dev/null @@ -1,93 +0,0 @@ -use crate::display::window::Window; -use crate::renderer::{vulkan::VkRenderContext, Renderable}; -use winit::application::ApplicationHandler; -use winit::event::WindowEvent; -use winit::event_loop::ActiveEventLoop; -use winit::window::WindowId; -use crate::scene::TriangleScene; - -pub struct App { - window: Window, - render_context: Option, - scene: Option>, -} - -impl App { - pub fn new(window: Window) -> Self { - Self { - window, - render_context: None, - scene: None, - } - } - - pub fn set_scene(&mut self, mut scene: Box) { - let result = self.render_context.as_mut() - .ok_or_else(|| anyhow::anyhow!("No render context")) - .and_then(|render_context| render_context.init_scene(&mut scene)); - - match result { - Ok(_) => self.scene = Some(scene), - Err(err) => log::warn!("{err}"), - } - } -} - -impl ApplicationHandler for App { - fn resumed(&mut self, event_loop: &ActiveEventLoop) { - self.window - .create_window(event_loop) - .map_err(|err| format!("Failed to create window: {}", err)) - .unwrap(); - - self.render_context = VkRenderContext::init(&self.window).ok(); - - let scene = TriangleScene::new(); - self.set_scene(Box::new(scene)); - } - - fn window_event(&mut self, event_loop: &ActiveEventLoop, _id: WindowId, event: WindowEvent) { - match event { - WindowEvent::CloseRequested => { - match self.render_context.as_ref() { - Some(render_context) => render_context.exit(), - None => log::warn!("Window closed but no render context found"), - }; - - log::debug!("The close button was pressed; stopping"); - event_loop.exit(); - } - WindowEvent::Resized(size) => { - match self.render_context.as_mut() { - Some(render_context) => { - if let Err(error) = - render_context.update_resolution(size.width, size.height) - { - log::error!( - "Failed to update resolution of render context : {}", - error - ); - } - } - None => log::warn!("Window resized but no render context found"), - }; - } - WindowEvent::RedrawRequested => { - if !event_loop.exiting() { - match self.render_context.as_mut() { - Some(render_context) => { - if let Err(error) = render_context.render(self.scene.as_ref()) { - log::error!("Failed to render with render context : {}", error); - event_loop.exit(); - } - } - None => log::warn!("Window resized but no render context found"), - }; - } - - self.window.request_redraw(); - } - _ => {} - } - } -} diff --git a/src/display/mod.rs b/src/display/mod.rs deleted file mode 100644 index f7758ab..0000000 --- a/src/display/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod app; -mod window; - -pub use app::App; -pub use window::Window; diff --git a/src/display/window.rs b/src/display/window.rs deleted file mode 100644 index 803fd35..0000000 --- a/src/display/window.rs +++ /dev/null @@ -1,65 +0,0 @@ -use std::ffi::c_char; -use winit::dpi::Pixel; -use winit::event_loop::ActiveEventLoop; -use winit::raw_window_handle::HasDisplayHandle; - -pub struct Window { - handle: Option, - window_attributes: winit::window::WindowAttributes, -} - -impl Window { - pub fn new(window_attributes: winit::window::WindowAttributes) -> Self { - Self { - handle: None, - window_attributes, - } - } - - pub fn create_window(&mut self, event_loop: &ActiveEventLoop) -> anyhow::Result<()> { - let window = event_loop.create_window(self.window_attributes.clone())?; - - self.handle = Some(window); - - Ok(()) - } - - pub fn required_extensions(&self) -> anyhow::Result> { - let display_handle = self - .handle - .as_ref() - .ok_or_else(|| anyhow::anyhow!("Window not found"))? - .display_handle()?; - - #[allow(unused_mut)] - let mut extension_names = - ash_window::enumerate_required_extensions(display_handle.as_raw())?.to_vec(); - - // TODO: Move this because is not related to Window extensions - #[cfg(any(target_os = "macos", target_os = "ios"))] - { - extension_names.push(ash::khr::portability_enumeration::NAME.as_ptr()); - // Enabling this extension is a requirement when using `VK_KHR_portability_subset` - extension_names.push(ash::khr::get_physical_device_properties2::NAME.as_ptr()); - } - - Ok(extension_names) - } - - pub fn handle(&self) -> Option<&winit::window::Window> { - self.handle.as_ref() - } - - pub fn physical_size(&self) -> Option> { - self.window_attributes - .inner_size - .and_then(|size| Some(size.to_physical::

(1.0))) - } - - pub fn request_redraw(&self) { - match self.handle.as_ref() { - Some(window) => window.request_redraw(), - None => log::warn!("Redraw requested but no window found"), - } - } -} diff --git a/src/game/assets/mod.rs b/src/game/assets/mod.rs new file mode 100644 index 0000000..d793a66 --- /dev/null +++ b/src/game/assets/mod.rs @@ -0,0 +1 @@ +pub mod square; diff --git a/src/game/assets/square.rs b/src/game/assets/square.rs new file mode 100644 index 0000000..7219157 --- /dev/null +++ b/src/game/assets/square.rs @@ -0,0 +1,263 @@ +use std::{collections::BTreeMap, error::Error, sync::Arc}; + +use vulkano::{ + buffer::{Buffer, BufferCreateInfo, BufferUsage, Subbuffer}, + command_buffer::{AutoCommandBufferBuilder, PrimaryAutoCommandBuffer}, + descriptor_set::{ + DescriptorSet, WriteDescriptorSet, + allocator::StandardDescriptorSetAllocator, + layout::{DescriptorSetLayoutBinding, DescriptorSetLayoutCreateInfo, DescriptorType}, + }, + device::Device, + format::Format, + memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator}, + pipeline::{ + DynamicState, GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout, + PipelineShaderStageCreateInfo, + graphics::{ + GraphicsPipelineCreateInfo, + color_blend::{ColorBlendAttachmentState, ColorBlendState}, + depth_stencil::{DepthState, DepthStencilState}, + input_assembly::InputAssemblyState, + multisample::MultisampleState, + rasterization::RasterizationState, + subpass::PipelineRenderingCreateInfo, + vertex_input::{Vertex, VertexDefinition}, + viewport::ViewportState, + }, + layout::{PipelineDescriptorSetLayoutCreateInfo, PipelineLayoutCreateFlags}, + }, + shader::ShaderStages, +}; + +use crate::core::render::{ + primitives::{mvp::Mvp, transform::TransformRaw, vertex::Vertex3D}, + texture::Texture, +}; + +const VERTICES: [Vertex3D; 4] = [ + Vertex3D { + position: [-0.5, -0.5, 0.0], + uv: [0.0, 0.0], + }, + Vertex3D { + position: [-0.5, 0.5, 0.0], + uv: [0.0, 1.0], + }, + Vertex3D { + position: [0.5, -0.5, 0.0], + uv: [1.0, 0.0], + }, + Vertex3D { + position: [0.5, 0.5, 0.0], + uv: [1.0, 1.0], + }, +]; + +const INDICES: [u32; 6] = [0, 2, 1, 2, 3, 1]; + +pub mod shaders { + pub mod vs { + vulkano_shaders::shader! { + ty: "vertex", + path: r"res/shaders/vertex.vert", + generate_structs: false, + } + } + + pub mod fs { + vulkano_shaders::shader! { + ty: "fragment", + path: r"res/shaders/vertex.frag", + generate_structs: false, + } + } +} + +pub struct Square { + vertex_buffer: Subbuffer<[Vertex3D]>, + index_buffer: Subbuffer<[u32]>, + pipeline: Arc, +} + +impl Square { + pub fn new( + device: &Arc, + memory_allocator: &Arc, + swapchain_format: Format, + depth_format: Format, + ) -> Result> { + let vertex_buffer = Buffer::from_iter( + memory_allocator.clone(), + BufferCreateInfo { + usage: BufferUsage::VERTEX_BUFFER, + ..Default::default() + }, + AllocationCreateInfo { + memory_type_filter: MemoryTypeFilter::PREFER_DEVICE + | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, + ..Default::default() + }, + Vec::from_iter(VERTICES), + )?; + let index_buffer = Buffer::from_iter( + memory_allocator.clone(), + BufferCreateInfo { + usage: BufferUsage::INDEX_BUFFER, + ..Default::default() + }, + AllocationCreateInfo { + memory_type_filter: MemoryTypeFilter::PREFER_DEVICE + | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, + ..Default::default() + }, + Vec::from_iter(INDICES), + )?; + + let vs = shaders::vs::load(device.clone())? + .entry_point("main") + .ok_or("Failed find main entry point of vertex shader".to_string())?; + + let fs = shaders::fs::load(device.clone())? + .entry_point("main") + .ok_or("Failed find main entry point of fragment shader".to_string())?; + + let vertex_input_state = + [Vertex3D::per_vertex(), TransformRaw::per_instance()].definition(&vs)?; + + let stages = [ + PipelineShaderStageCreateInfo::new(vs), + PipelineShaderStageCreateInfo::new(fs), + ]; + + let vertex_bindings = BTreeMap::::from_iter([( + 0, + DescriptorSetLayoutBinding { + stages: ShaderStages::VERTEX, + ..DescriptorSetLayoutBinding::descriptor_type(DescriptorType::UniformBuffer) + }, + )]); + let fragment_bindings = BTreeMap::::from_iter([ + ( + 0, + DescriptorSetLayoutBinding { + stages: ShaderStages::FRAGMENT, + ..DescriptorSetLayoutBinding::descriptor_type(DescriptorType::Sampler) + }, + ), + ( + 1, + DescriptorSetLayoutBinding { + stages: ShaderStages::FRAGMENT, + ..DescriptorSetLayoutBinding::descriptor_type(DescriptorType::SampledImage) + }, + ), + ]); + + let vertex_descriptor_set_layout = DescriptorSetLayoutCreateInfo { + bindings: vertex_bindings, + ..Default::default() + }; + + let fragment_descriptor_set_layout = DescriptorSetLayoutCreateInfo { + bindings: fragment_bindings, + ..Default::default() + }; + + let create_info = PipelineDescriptorSetLayoutCreateInfo { + set_layouts: vec![vertex_descriptor_set_layout, fragment_descriptor_set_layout], + flags: PipelineLayoutCreateFlags::default(), + push_constant_ranges: vec![], + } + .into_pipeline_layout_create_info(device.clone())?; + + let layout = PipelineLayout::new(device.clone(), create_info)?; + + let subpass = PipelineRenderingCreateInfo { + color_attachment_formats: vec![Some(swapchain_format)], + depth_attachment_format: Some(depth_format), + ..Default::default() + }; + + let pipeline = GraphicsPipeline::new( + device.clone(), + None, + GraphicsPipelineCreateInfo { + stages: stages.into_iter().collect(), + vertex_input_state: Some(vertex_input_state), + input_assembly_state: Some(InputAssemblyState::default()), + viewport_state: Some(ViewportState::default()), + rasterization_state: Some(RasterizationState::default()), + multisample_state: Some(MultisampleState::default()), + color_blend_state: Some(ColorBlendState::with_attachment_states( + subpass.color_attachment_formats.len() as u32, + ColorBlendAttachmentState::default(), + )), + depth_stencil_state: Some(DepthStencilState { + depth: Some(DepthState::simple()), + ..Default::default() + }), + dynamic_state: [DynamicState::Viewport].into_iter().collect(), + subpass: Some(subpass.into()), + ..GraphicsPipelineCreateInfo::layout(layout) + }, + )?; + + Ok(Self { + vertex_buffer, + index_buffer, + pipeline, + }) + } + + pub fn render( + &self, + command_buffer: &mut AutoCommandBufferBuilder, + descriptor_set_allocator: &Arc, + mvp_uniform: &Subbuffer<[Mvp]>, + transform_uniform: &Subbuffer<[TransformRaw]>, + texture: &Texture, + ) -> Result<(), Box> { + let layouts = self.pipeline.layout().set_layouts(); + + let uniform_descriptor_set = DescriptorSet::new( + descriptor_set_allocator.clone(), + layouts[0].clone(), + [WriteDescriptorSet::buffer(0, mvp_uniform.clone())], + [], + )?; + + let texture_descriptor_set = DescriptorSet::new( + descriptor_set_allocator.clone(), + layouts[1].clone(), + [ + WriteDescriptorSet::sampler(0, texture.get_sampler().clone()), + WriteDescriptorSet::image_view(1, texture.get_texture().clone()), + ], + [], + )?; + + command_buffer.bind_pipeline_graphics(self.pipeline.clone())?; + command_buffer.bind_descriptor_sets( + PipelineBindPoint::Graphics, + self.pipeline.layout().clone(), + 0, + vec![uniform_descriptor_set, texture_descriptor_set], + )?; + command_buffer + .bind_vertex_buffers(0, (self.vertex_buffer.clone(), transform_uniform.clone()))?; + command_buffer.bind_index_buffer(self.index_buffer.clone())?; + + unsafe { + command_buffer.draw_indexed( + INDICES.len() as u32, + transform_uniform.len() as u32, + 0, + 0, + 0, + )?; + } + + Ok(()) + } +} diff --git a/src/game/mod.rs b/src/game/mod.rs new file mode 100644 index 0000000..065e8e4 --- /dev/null +++ b/src/game/mod.rs @@ -0,0 +1,2 @@ +pub mod assets; +pub mod scenes; diff --git a/src/game/scenes/main_scene.rs b/src/game/scenes/main_scene.rs new file mode 100644 index 0000000..00232f7 --- /dev/null +++ b/src/game/scenes/main_scene.rs @@ -0,0 +1,288 @@ +use std::error::Error; + +use super::settings_scene::SettingsScene; +use crate::core::app::DEPTH_IMAGE_ID; +use crate::core::app::context::ApplicationContext; +use crate::core::app::user_event::UserEvent; +use crate::core::render::primitives::camera::Camera3D; +use crate::core::render::primitives::transform::Transform; +use crate::core::render::render_pass_manager::{RenderPassConfig, RenderPassManager}; +use crate::core::render::texture::Texture; +use crate::core::scene::Scene; +use crate::game::assets::square::Square; +use egui_winit_vulkano::egui; +use glam::EulerRot; +use glam::Quat; +use glam::Vec3; +use vulkano::{ + command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, PrimaryCommandBufferAbstract}, + sync::GpuFuture, +}; +use winit::window::CursorGrabMode; + +pub struct MainSceneState { + square: Square, + instances: Vec, + camera: Camera3D, + texture: Texture, + speed: f32, +} + +#[derive(Default)] +pub struct MainScene { + state: Option, +} + +impl Scene for MainScene { + fn loaded(&self) -> bool { + self.state.is_some() + } + + fn load( + &mut self, + app_context: &mut ApplicationContext, + ) -> Result<(), Box> { + let depth_image_view = app_context.with_renderer_mut(|renderer| { + renderer.get_additional_image_view(DEPTH_IMAGE_ID).clone() + }); + + let swapchain_image_view = + app_context.with_renderer(|renderer| renderer.swapchain_image_view().clone()); + + let square = Square::new( + &app_context.device, + &app_context.memory_allocator, + swapchain_image_view.format(), + depth_image_view.format(), + )?; + + let num_instances = 100; + let instance_size = 10.0; + let instance_spacing = 10.0; + let num_instances_per_row = (num_instances as f32 / instance_spacing).ceil() as u32; + let instances: Vec = (0..num_instances) + .map(|i| Transform { + position: Vec3::new( + (i % num_instances_per_row) as f32 * (instance_spacing + instance_size), + 0.0, + (i / num_instances_per_row) as f32 * (instance_spacing + instance_size), + ), + rotation: Quat::from_euler( + EulerRot::XYZ, + 0.0, + rand::random_range(0.0..=360.0), + 0.0, + ), + scale: Vec3::new(instance_size, instance_size, instance_size), + }) + .collect(); + + let texture = { + let mut uploads = AutoCommandBufferBuilder::primary( + app_context.command_buffer_allocator.clone(), + app_context.graphics_queue.queue_family_index(), + CommandBufferUsage::OneTimeSubmit, + )?; + + let texture = Texture::from_file( + &app_context.device, + &app_context.memory_allocator, + &mut uploads, + "res/textures/wooden-crate.jpg", + )?; + + let _ = uploads + .build()? + .execute(app_context.graphics_queue.clone())?; + + texture + }; + + let camera = app_context.with_renderer(|renderer| { + Camera3D::new( + renderer.aspect_ratio(), + std::f32::consts::FRAC_PI_2, + 0.01, + 1000.0, + ) + }); + + self.state = Some(MainSceneState { + square, + instances, + camera, + texture, + speed: 50.0, + }); + + Ok(()) + } + + fn update(&mut self, app_context: &mut ApplicationContext) -> Result<(), Box> { + let state = self.state.as_mut().unwrap(); + app_context.with_input_manager(|input_manager| { + app_context.with_timer(|timer| { + state.camera.update( + input_manager, + timer, + state.speed, + 10.0, + app_context.get_aspect_ratio(), + ); + }); + }); + + if app_context + .with_input_manager(|input_manager| input_manager.get_virtual_input_state("mouse_left")) + > 0.0 + { + let _ = app_context + .event_loop_proxy + .send_event(UserEvent::CursorVisible(app_context.window_id, false)); + let _ = app_context + .event_loop_proxy + .send_event(UserEvent::CursorGrabMode( + app_context.window_id, + CursorGrabMode::Locked, + )); + } + + if app_context.with_input_manager(|input_manager| { + input_manager.get_virtual_input_state("mouse_right") + }) > 0.0 + { + let _ = app_context + .event_loop_proxy + .send_event(UserEvent::CursorVisible(app_context.window_id, true)); + let _ = app_context + .event_loop_proxy + .send_event(UserEvent::CursorGrabMode( + app_context.window_id, + CursorGrabMode::None, + )); + } + + Ok(()) + } + + fn render( + &mut self, + before_future: Box, + app_context: &mut ApplicationContext, + ) -> Result, Box> { + let state = self.state.as_ref().ok_or("State not loaded")?; + + let mut builder = AutoCommandBufferBuilder::primary( + app_context.command_buffer_allocator.clone(), + app_context.graphics_queue.queue_family_index(), + CommandBufferUsage::OneTimeSubmit, + )?; + + { + let swapchain_image_view = + app_context.with_renderer(|renderer| renderer.swapchain_image_view().clone()); + let depth_image_view = app_context.with_renderer_mut(|renderer| { + renderer.get_additional_image_view(DEPTH_IMAGE_ID).clone() + }); + let config = RenderPassConfig::default(); + RenderPassManager::begin_standard_rendering( + &mut builder, + &config, + swapchain_image_view, + Some(depth_image_view), + app_context.get_window_size(), + )?; + } + + // Create camera uniform using the actual camera + let camera_uniform = state.camera.create_buffer(&app_context.memory_allocator)?; + + let transform_uniform = + Transform::create_buffer(&app_context.memory_allocator, &state.instances)?; + + state + .square + .render( + &mut builder, + &app_context.descriptor_set_allocator, + &camera_uniform, + &transform_uniform, + &state.texture, + ) + .unwrap(); + + RenderPassManager::end_rendering(&mut builder)?; + + let command_buffer = builder.build()?; + + let render_future = + before_future.then_execute(app_context.graphics_queue.clone(), command_buffer)?; + + let swapchain_image_view = + app_context.with_renderer(|renderer| renderer.swapchain_image_view().clone()); + let input_manager_status = + app_context.with_input_manager(|input_manager| format!("{:#?}", input_manager)); + let event_loop_proxy = app_context.event_loop_proxy.clone(); + let delta_time = app_context.get_delta_time(); + let window_id = app_context.window_id; + let window_size = app_context.get_window_size(); + + let render_future = app_context.with_gui_mut(|gui| { + gui.immediate_ui(|gui| { + let ctx = gui.context(); + egui::TopBottomPanel::top("top_panel").show(&ctx, |ui| { + ui.horizontal(|ui| { + ui.heading("Vulkan Test - Moteur 3D"); + ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| { + if ui.button("Paramètres").clicked() { + let _ = event_loop_proxy.send_event(UserEvent::ChangeScene( + window_id, + Box::new(SettingsScene::default()), + )); + } + if ui.button("Quitter").clicked() { + let _ = event_loop_proxy.send_event(UserEvent::Exit(window_id)); + } + }); + }); + }); + + egui::SidePanel::left("side_panel").show(&ctx, |ui| { + ui.heading("Informations"); + + ui.separator(); + + ui.label(format!("Résolution: {:?}", window_size)); + ui.label(format!("Delta Time: {:.2}ms", delta_time * 1000.0)); + + ui.separator(); + + ui.label("Position caméra:"); + let position = state.camera.get_position(); + ui.label(format!(" X: {:.2}", position[0])); + ui.label(format!(" Y: {:.2}", position[1])); + ui.label(format!(" Z: {:.2}", position[2])); + + ui.separator(); + + ui.label("Rotation caméra:"); + let rotation = state.camera.get_rotation(); + ui.label(format!(" Yaw: {:.2}°", rotation.y.to_degrees())); + ui.label(format!(" Pitch: {:.2}°", rotation.x.to_degrees())); + + ui.separator(); + + ui.label(input_manager_status); + }); + }); + + gui.draw_on_image(render_future, swapchain_image_view.clone()) + }); + + Ok(render_future) + } + + fn unload(&mut self) { + self.state = None; + } +} diff --git a/src/game/scenes/mod.rs b/src/game/scenes/mod.rs new file mode 100644 index 0000000..516fa6f --- /dev/null +++ b/src/game/scenes/mod.rs @@ -0,0 +1,2 @@ +pub mod main_scene; +pub mod settings_scene; diff --git a/src/game/scenes/settings_scene.rs b/src/game/scenes/settings_scene.rs new file mode 100644 index 0000000..4d6fc53 --- /dev/null +++ b/src/game/scenes/settings_scene.rs @@ -0,0 +1,136 @@ +use std::error::Error; + +use crate::core::app::DEPTH_IMAGE_ID; +use crate::core::app::context::ApplicationContext; +use crate::core::app::user_event::UserEvent; +use crate::core::render::render_pass_manager::{RenderPassConfig, RenderPassManager}; +use crate::core::scene::Scene; +use egui_winit_vulkano::egui; +use vulkano::{ + command_buffer::AutoCommandBufferBuilder, command_buffer::CommandBufferUsage, sync::GpuFuture, +}; + +use super::main_scene::MainScene; + +pub struct SettingsSceneState { + current_resolution: [f32; 2], + available_resolutions: Vec<(u32, u32)>, +} + +#[derive(Default)] +pub struct SettingsScene { + state: Option, +} + +impl Scene for SettingsScene { + fn loaded(&self) -> bool { + self.state.is_some() + } + + fn load(&mut self, app_context: &mut ApplicationContext) -> Result<(), Box> { + let current_resolution = app_context.get_window_size(); + let available_resolutions = app_context.get_available_resolutions(); + + self.state = Some(SettingsSceneState { + current_resolution, + available_resolutions, + }); + + Ok(()) + } + + fn update(&mut self, _app_context: &mut ApplicationContext) -> Result<(), Box> { + Ok(()) + } + + fn render( + &mut self, + before_future: Box, + app_context: &mut ApplicationContext, + ) -> Result, Box> { + let state = self.state.as_ref().ok_or("State not found")?; + + let mut builder = AutoCommandBufferBuilder::primary( + app_context.command_buffer_allocator.clone(), + app_context.graphics_queue.queue_family_index(), + CommandBufferUsage::OneTimeSubmit, + )?; + + // Utiliser le RenderPassManager + { + let swapchain_image_view = + app_context.with_renderer(|renderer| renderer.swapchain_image_view().clone()); + let depth_stencil_image_view = app_context.with_renderer_mut(|renderer| { + renderer.get_additional_image_view(DEPTH_IMAGE_ID).clone() + }); + + let config = RenderPassConfig::default(); + RenderPassManager::begin_standard_rendering( + &mut builder, + &config, + swapchain_image_view, + Some(depth_stencil_image_view), + app_context.get_window_size(), + )?; + } + + // Pas de géométrie dans cette scène - juste un écran de paramètres + RenderPassManager::end_rendering(&mut builder)?; + + let command_buffer = builder.build()?; + + let render_future = + before_future.then_execute(app_context.graphics_queue.clone(), command_buffer)?; + + let swapchain_image_view = + app_context.with_renderer(|renderer| renderer.swapchain_image_view().clone()); + + let event_loop_proxy = app_context.event_loop_proxy.clone(); + let window_id = app_context.window_id; + + let render_future = app_context.with_gui_mut(|gui| { + gui.immediate_ui(|gui| { + let ctx = gui.context(); + + egui::CentralPanel::default().show(&ctx, |ui| { + ui.heading("Paramètres"); + + ui.separator(); + + ui.label(format!( + "Résolution actuelle: {:?}", + state.current_resolution + )); + + ui.separator(); + ui.label("Changer la résolution:"); + + for &(width, height) in &state.available_resolutions { + if ui.button(format!("{}x{}", width, height)).clicked() { + let _ = event_loop_proxy.send_event(UserEvent::ChangeResolution( + window_id, + width as f32, + height as f32, + )); + } + } + + ui.separator(); + + if ui.button("Retour au jeu").clicked() { + let _ = event_loop_proxy.send_event(UserEvent::ChangeScene( + window_id, + Box::new(MainScene::default()), + )); + } + }); + }); + + gui.draw_on_image(render_future, swapchain_image_view.clone()) + }); + + Ok(render_future) + } + + fn unload(&mut self) {} +} diff --git a/src/main.rs b/src/main.rs index 2f48cfe..1ea49c3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,24 +1,92 @@ -use winit::event_loop::{ControlFlow, EventLoop}; +use core::input::{AxisDirection, InputManager, VirtualBinding}; +use std::collections::HashMap; -mod display; -mod renderer; -mod scene; +use vulkano::device::{DeviceExtensions, DeviceFeatures}; +use vulkano_util::context::{VulkanoConfig, VulkanoContext}; +use winit::{ + event::MouseButton, + event_loop::{ControlFlow, EventLoop}, + keyboard::{KeyCode, PhysicalKey}, +}; + +mod core; +mod game; fn main() { env_logger::init(); - let event_loop = EventLoop::new().unwrap(); + let input_manager = InputManager::new(HashMap::from([ + ( + "move_forward".to_string(), + vec![ + VirtualBinding::Keyboard(PhysicalKey::Code(KeyCode::KeyW), AxisDirection::Normal), + VirtualBinding::Keyboard(PhysicalKey::Code(KeyCode::KeyS), AxisDirection::Invert), + ], + ), + ( + "move_right".to_string(), + vec![ + VirtualBinding::Keyboard(PhysicalKey::Code(KeyCode::KeyD), AxisDirection::Normal), + VirtualBinding::Keyboard(PhysicalKey::Code(KeyCode::KeyA), AxisDirection::Invert), + ], + ), + ( + "mouse_x".to_string(), + vec![VirtualBinding::MouseX(AxisDirection::Normal)], + ), + ( + "mouse_y".to_string(), + vec![VirtualBinding::MouseY(AxisDirection::Normal)], + ), + ( + "mouse_wheel".to_string(), + vec![VirtualBinding::MouseWheelY(AxisDirection::Normal)], + ), + ( + "mouse_left".to_string(), + vec![VirtualBinding::MouseButton( + MouseButton::Left, + AxisDirection::Normal, + )], + ), + ( + "mouse_right".to_string(), + vec![VirtualBinding::MouseButton( + MouseButton::Right, + AxisDirection::Normal, + )], + ), + ])); + + let device_extensions = DeviceExtensions { + khr_swapchain: true, + ..Default::default() + }; + + let device_features = DeviceFeatures { + dynamic_rendering: true, + ..Default::default() + }; + + let vulkano_config = VulkanoConfig { + print_device_name: true, + device_extensions, + device_features, + ..Default::default() + }; + + let vulkano_context = VulkanoContext::new(vulkano_config); + + let event_loop = EventLoop::with_user_event().build().unwrap(); event_loop.set_control_flow(ControlFlow::Poll); + let proxy = event_loop.create_proxy(); - let window_attributes = winit::window::Window::default_attributes() - .with_title("Rust ASH Test") - .with_inner_size(winit::dpi::PhysicalSize::new( - f64::from(800), - f64::from(600), - )); + let mut app = core::app::App::new(vulkano_context, input_manager, proxy); - let window = display::Window::new(window_attributes); - let mut app = display::App::new(window); - - event_loop.run_app(&mut app).unwrap(); + match event_loop.run_app(&mut app) { + Ok(_) => {} + Err(e) => { + log::error!("Error running old app: {e}"); + } + } } diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs deleted file mode 100644 index cca608a..0000000 --- a/src/renderer/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -use std::sync::Arc; -use ash::vk; - -pub mod vulkan; - -pub trait Renderable { - fn init(&mut self, device: &Arc, render_pass: &Arc) -> anyhow::Result<()>; - fn render(&self, device: &vulkan::VkDevice, swapchain: &vulkan::VkSwapchain, command_buffer: &vk::CommandBuffer) -> anyhow::Result<()>; -} \ No newline at end of file diff --git a/src/renderer/vulkan/mod.rs b/src/renderer/vulkan/mod.rs deleted file mode 100644 index a00ef58..0000000 --- a/src/renderer/vulkan/mod.rs +++ /dev/null @@ -1,45 +0,0 @@ -mod vk_render_context; -pub use vk_render_context::VkRenderContext; - -mod vk_instance; -pub use vk_instance::VkInstance; - -mod vk_surface; -pub use vk_surface::{SwapchainSupportDetails, VkSurface}; - -mod vk_physical_device; -pub use vk_physical_device::VkPhysicalDevice; - -mod vk_device; -pub use vk_device::VkDevice; - -mod vk_swapchain; -pub use vk_swapchain::VkSwapchain; - -mod vk_shader_module; -pub use vk_shader_module::VkShaderModule; - -mod vk_graphics_pipeline; -pub use vk_graphics_pipeline::VkGraphicsPipeline; - -mod vk_render_pass; -pub use vk_render_pass::VkRenderPass; - -mod vk_semaphore; -pub use vk_semaphore::VkSemaphore; - -mod vk_command_pool; -pub use vk_command_pool::VkCommandPool; - -mod vk_framebuffer; -pub use vk_framebuffer::VkFramebuffer; - -mod vk_fence; -pub use vk_fence::VkFence; - -mod utils; -mod vertex; -mod vk_buffer; -pub use vk_buffer::VkBuffer; - -pub use vertex::Vertex; diff --git a/src/renderer/vulkan/utils/layers.rs b/src/renderer/vulkan/utils/layers.rs deleted file mode 100644 index 9d901fb..0000000 --- a/src/renderer/vulkan/utils/layers.rs +++ /dev/null @@ -1,51 +0,0 @@ -use std::ffi::CString; - -pub enum LayersSelector<'a> { - Nothing, - SpecificLayers(Vec<&'a str>), - All, -} - -pub fn use_layers(entry: &ash::Entry, selector: LayersSelector) -> Vec { - let layers_available = get_layers_available(entry) - .iter() - .filter_map(|layer| { - layer - .layer_name_as_c_str() - .and_then(|layer_name| Ok(CString::from(layer_name))) - .ok() - }) - .collect::>(); - - match selector { - LayersSelector::Nothing => Vec::new(), - LayersSelector::SpecificLayers(layers) => select_layers(&layers_available, &layers), - LayersSelector::All => layers_available, - } -} - -fn get_layers_available(entry: &ash::Entry) -> Vec { - unsafe { - entry - .enumerate_instance_layer_properties() - .unwrap_or_default() - } -} - -fn select_layers(layers_available: &Vec, layers_to_select: &[&str]) -> Vec { - layers_to_select - .iter() - .filter_map(|layer_name| { - if layers_available.iter().any(|layer_available| { - layer_available - .to_str() - .and_then(|layer_available| Ok(layer_available.eq(*layer_name))) - .unwrap_or(false) - }) { - CString::new(*layer_name).ok() - } else { - None - } - }) - .collect::>() -} diff --git a/src/renderer/vulkan/utils/mod.rs b/src/renderer/vulkan/utils/mod.rs deleted file mode 100644 index 759c25e..0000000 --- a/src/renderer/vulkan/utils/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod layers; diff --git a/src/renderer/vulkan/vertex.rs b/src/renderer/vulkan/vertex.rs deleted file mode 100644 index 5d97213..0000000 --- a/src/renderer/vulkan/vertex.rs +++ /dev/null @@ -1,37 +0,0 @@ -use ash::vk; -use std::mem::offset_of; - -#[derive(Default)] -pub struct Vertex { - pub position: [f32; 2], - pub color: [f32; 3], -} - -impl Vertex { - pub fn new(position: [f32; 2], color: [f32; 3]) -> Self { - Self { position, color } - } - - pub fn get_binding_description() -> vk::VertexInputBindingDescription { - vk::VertexInputBindingDescription::default() - .binding(0) - .stride(size_of::() as u32) - .input_rate(vk::VertexInputRate::VERTEX) - } - - pub fn get_attribute_descriptions() -> [vk::VertexInputAttributeDescription; 2] { - let position_attribute = vk::VertexInputAttributeDescription::default() - .binding(0) - .location(0) - .format(vk::Format::R32G32_SFLOAT) - .offset(offset_of!(Vertex, position) as u32); - - let color_attribute = vk::VertexInputAttributeDescription::default() - .binding(0) - .location(1) - .format(vk::Format::R32G32B32_SFLOAT) - .offset(offset_of!(Vertex, color) as u32); - - [position_attribute, color_attribute] - } -} \ No newline at end of file diff --git a/src/renderer/vulkan/vk_buffer.rs b/src/renderer/vulkan/vk_buffer.rs deleted file mode 100644 index b03dea4..0000000 --- a/src/renderer/vulkan/vk_buffer.rs +++ /dev/null @@ -1,31 +0,0 @@ -use std::sync::Arc; -use ash::prelude::VkResult; -use ash::vk; -use crate::renderer::vulkan::VkDevice; - -pub struct VkBuffer { - device: Arc, - - handle: vk::Buffer, -} - -impl VkBuffer { - pub fn new(device: &Arc, info: &vk::BufferCreateInfo) -> VkResult { - let buffer = unsafe { device.handle.create_buffer(info, None)? }; - - Ok(VkBuffer { device: Arc::clone(device), handle: buffer }) - } - - - pub fn mem_requirements(&self) -> vk::MemoryRequirements { - unsafe { self.device.handle.get_buffer_memory_requirements(self.handle) } - } -} - -impl Drop for VkBuffer { - fn drop(&mut self) { - unsafe { - self.device.handle.destroy_buffer(self.handle, None); - } - } -} \ No newline at end of file diff --git a/src/renderer/vulkan/vk_command_pool.rs b/src/renderer/vulkan/vk_command_pool.rs deleted file mode 100644 index c657e97..0000000 --- a/src/renderer/vulkan/vk_command_pool.rs +++ /dev/null @@ -1,52 +0,0 @@ -use super::VkDevice; -use ash::prelude::VkResult; -use ash::vk; -use std::sync::Arc; - -pub struct VkCommandPool { - device: Arc, - - pub handle: vk::CommandPool, -} - -impl VkCommandPool { - pub fn new(device: &Arc) -> VkResult { - let command_pool_info = - vk::CommandPoolCreateInfo::default() - .flags(vk::CommandPoolCreateFlags::RESET_COMMAND_BUFFER) - .queue_family_index(device.queue_family_index); - let command_pool = unsafe { - device - .handle - .create_command_pool(&command_pool_info, None)? - }; - log::debug!("Command pool created ({command_pool:?})"); - - Ok(Self { - device: device.clone(), - handle: command_pool, - }) - } - - pub fn allocate_command_buffers_for_framebuffers(&self, framebuffers_count: u32) -> VkResult> { - let command_buffer_info = vk::CommandBufferAllocateInfo::default() - .command_pool(self.handle) - .level(vk::CommandBufferLevel::PRIMARY) - .command_buffer_count(framebuffers_count); - - let command_buffers = unsafe { - self.device - .handle - .allocate_command_buffers(&command_buffer_info)? - }; - - Ok(command_buffers) - } -} - -impl Drop for VkCommandPool { - fn drop(&mut self) { - unsafe { self.device.handle.destroy_command_pool(self.handle, None) }; - log::debug!("Command pool destroyed ({:?})", self.handle); - } -} diff --git a/src/renderer/vulkan/vk_device.rs b/src/renderer/vulkan/vk_device.rs deleted file mode 100644 index 9f14630..0000000 --- a/src/renderer/vulkan/vk_device.rs +++ /dev/null @@ -1,109 +0,0 @@ -use super::{VkInstance, VkPhysicalDevice}; -use ash::prelude::VkResult; -use ash::vk; -use std::sync::Arc; - -pub struct VkDevice { - instance: Arc, - physical_device: Arc, - - pub handle: ash::Device, - pub swapchain_loader: ash::khr::swapchain::Device, - pub queue_family_index: u32, - - // Arc not used because vk::Queue is destroyed with Device automatically - // so any references of vk::Queue must be destroyed with VkDevice - queues: Vec, -} - -impl VkDevice { - pub fn new_graphics_device( - instance: &Arc, - physical_device: &Arc, - queue_family_index: u32, - ) -> anyhow::Result { - let device_extension_names_raw = [ - ash::khr::swapchain::NAME.as_ptr(), - #[cfg(any(target_os = "macos", target_os = "ios"))] - ash::khr::portability_subset::NAME.as_ptr(), - ]; - let features = vk::PhysicalDeviceFeatures { - shader_clip_distance: 1, - ..Default::default() - }; - - let queues_priorities = [1.0]; - let queue_info = vk::DeviceQueueCreateInfo::default() - .queue_family_index(queue_family_index) - .queue_priorities(&queues_priorities); - - let device_create_info = vk::DeviceCreateInfo::default() - .queue_create_infos(std::slice::from_ref(&queue_info)) - .enabled_extension_names(&device_extension_names_raw) - .enabled_features(&features); - - let device = unsafe { - instance - .handle - .create_device(physical_device.handle, &device_create_info, None)? - }; - log::debug!("Device created ({:?})", device.handle()); - - let queues = queues_priorities - .iter() - .enumerate() - .map(|(index, _)| unsafe { device.get_device_queue(queue_family_index, index as u32) }) - .collect::>(); - - let swapchain_loader = ash::khr::swapchain::Device::new(&instance.handle, &device); - - Ok(Self { - instance: Arc::clone(instance), - physical_device: Arc::clone(&physical_device), - handle: device, - swapchain_loader, - queue_family_index, - queues, - }) - } - - pub fn get_device_queue(&self, queue_index: u32) -> Option<&vk::Queue> { - self.queues.get(queue_index as usize) - } - - pub fn create_command_pool( - &self, - info: &vk::CommandPoolCreateInfo, - ) -> VkResult { - let info = info.queue_family_index(self.queue_family_index); - - unsafe { self.handle.create_command_pool(&info, None) } - } - - pub fn allocate_command_buffers( - &self, - info: &vk::CommandBufferAllocateInfo, - ) -> VkResult> { - unsafe { self.handle.allocate_command_buffers(&info) } - } - - pub fn create_fence(&self, info: &vk::FenceCreateInfo) -> VkResult { - unsafe { self.handle.create_fence(&info, None) } - } - - pub fn create_semaphore( - &self, - info: &vk::SemaphoreCreateInfo, - ) -> VkResult { - unsafe { self.handle.create_semaphore(&info, None) } - } -} - -impl Drop for VkDevice { - fn drop(&mut self) { - unsafe { - self.handle.destroy_device(None); - log::debug!("Device destroyed ({:?})", self.handle.handle()); - } - } -} diff --git a/src/renderer/vulkan/vk_fence.rs b/src/renderer/vulkan/vk_fence.rs deleted file mode 100644 index 9fb71ff..0000000 --- a/src/renderer/vulkan/vk_fence.rs +++ /dev/null @@ -1,30 +0,0 @@ -use super::VkDevice; -use ash::vk; -use std::sync::Arc; - -pub struct VkFence { - device: Arc, - - pub handle: vk::Fence, -} - -impl VkFence { - pub fn new(device: &Arc) -> anyhow::Result { - let fence_info = vk::FenceCreateInfo::default() - .flags(vk::FenceCreateFlags::SIGNALED); - let fence = unsafe { device.handle.create_fence(&fence_info, None)? }; - log::debug!("Fence created ({fence:?})"); - - Ok(Self { - device: device.clone(), - handle: fence, - }) - } -} - -impl Drop for VkFence { - fn drop(&mut self) { - unsafe { self.device.handle.destroy_fence(self.handle, None) }; - log::debug!("Fence destroyed ({:?})", self.handle); - } -} \ No newline at end of file diff --git a/src/renderer/vulkan/vk_framebuffer.rs b/src/renderer/vulkan/vk_framebuffer.rs deleted file mode 100644 index 8486fb5..0000000 --- a/src/renderer/vulkan/vk_framebuffer.rs +++ /dev/null @@ -1,44 +0,0 @@ -use super::{VkDevice, VkRenderPass, VkSwapchain}; -use ash::vk; -use std::sync::Arc; - -pub struct VkFramebuffer { - device: Arc, - image_view: Arc, - render_pass: Arc, - - pub handle: vk::Framebuffer, -} - -impl VkFramebuffer { - pub fn from_swapchain_image_view( - device: &Arc, - render_pass: &Arc, - image_view: &Arc, - swapchain: &VkSwapchain, - ) -> anyhow::Result { - let attachments = [*image_view.as_ref()]; - let framebuffer_info = vk::FramebufferCreateInfo::default() - .render_pass(render_pass.handle) - .width(swapchain.surface_resolution.width) - .height(swapchain.surface_resolution.height) - .attachments(&attachments) - .layers(1); - - let framebuffer = unsafe { device.handle.create_framebuffer(&framebuffer_info, None)? }; - - Ok(Self { - device: device.clone(), - render_pass: render_pass.clone(), - image_view: image_view.clone(), - - handle: framebuffer, - }) - } -} - -impl Drop for VkFramebuffer { - fn drop(&mut self) { - unsafe { self.device.handle.destroy_framebuffer(self.handle, None) }; - } -} diff --git a/src/renderer/vulkan/vk_graphics_pipeline.rs b/src/renderer/vulkan/vk_graphics_pipeline.rs deleted file mode 100644 index a9af298..0000000 --- a/src/renderer/vulkan/vk_graphics_pipeline.rs +++ /dev/null @@ -1,120 +0,0 @@ -use super::{VkDevice, VkRenderPass, VkShaderModule, VkSwapchain}; -use ash::vk; -use std::ffi::CStr; -use std::sync::Arc; - -pub struct VkGraphicsPipeline { - device: Arc, - render_pass: Arc, - - pub pipeline_layout: vk::PipelineLayout, - pub pipeline: vk::Pipeline, - vertex_shader: VkShaderModule, - fragment_shader: VkShaderModule, -} - -impl VkGraphicsPipeline { - pub fn new( - device: &Arc, - render_pass: &Arc, - ) -> anyhow::Result { - let shader_entry_name = CStr::from_bytes_with_nul(b"main\0")?; - - let vert_shader_module = - VkShaderModule::from_spv_file(device, "res/shaders/main.vert.spv")?; - - let vert_shader_info = vk::PipelineShaderStageCreateInfo::default() - .module(vert_shader_module.handle) - .name(shader_entry_name) - .stage(vk::ShaderStageFlags::VERTEX); - - let frag_shader_module = - VkShaderModule::from_spv_file(device, "res/shaders/main.frag.spv")?; - - let frag_shader_info = vk::PipelineShaderStageCreateInfo::default() - .module(frag_shader_module.handle) - .name(shader_entry_name) - .stage(vk::ShaderStageFlags::FRAGMENT); - - let shader_stage_create_infos = [vert_shader_info, frag_shader_info]; - - let vertex_input_info = vk::PipelineVertexInputStateCreateInfo::default(); - - let input_assembly = vk::PipelineInputAssemblyStateCreateInfo::default() - .topology(vk::PrimitiveTopology::TRIANGLE_LIST); - - let viewport_state = vk::PipelineViewportStateCreateInfo::default() - .viewport_count(1) - .scissor_count(1); - - let rasterizer = vk::PipelineRasterizationStateCreateInfo::default() - .polygon_mode(vk::PolygonMode::FILL) - .cull_mode(vk::CullModeFlags::BACK) - .front_face(vk::FrontFace::CLOCKWISE) - .line_width(1.0); - - let multisampling = vk::PipelineMultisampleStateCreateInfo::default() - .rasterization_samples(vk::SampleCountFlags::TYPE_1) - .min_sample_shading(1.0); - - let color_blend_attachment = vk::PipelineColorBlendAttachmentState::default() - .color_write_mask(vk::ColorComponentFlags::RGBA); - - let attachments = [color_blend_attachment]; - let color_blending = - vk::PipelineColorBlendStateCreateInfo::default().attachments(&attachments); - - let dynamic_state = vk::PipelineDynamicStateCreateInfo::default() - .dynamic_states(&[vk::DynamicState::VIEWPORT, vk::DynamicState::SCISSOR]); - - let pipeline_layout_info = vk::PipelineLayoutCreateInfo::default(); - let pipeline_layout = unsafe { - device - .handle - .create_pipeline_layout(&pipeline_layout_info, None)? - }; - log::debug!("Pipeline layout created ({pipeline_layout:?})"); - - let pipeline_info = vk::GraphicsPipelineCreateInfo::default() - .stages(&shader_stage_create_infos) - .vertex_input_state(&vertex_input_info) - .input_assembly_state(&input_assembly) - .viewport_state(&viewport_state) - .rasterization_state(&rasterizer) - .multisample_state(&multisampling) - .color_blend_state(&color_blending) - .dynamic_state(&dynamic_state) - .layout(pipeline_layout) - .render_pass(render_pass.handle); - let pipeline = unsafe { - device - .handle - .create_graphics_pipelines(vk::PipelineCache::null(), &[pipeline_info], None) - .map_err(|(_, error)| error)?[0] - }; - log::debug!("Pipeline created ({pipeline_layout:?})"); - - Ok(Self { - device: device.clone(), - render_pass: render_pass.clone(), - pipeline_layout, - pipeline, - vertex_shader: vert_shader_module, - fragment_shader: frag_shader_module, - }) - } -} - -impl Drop for VkGraphicsPipeline { - fn drop(&mut self) { - unsafe { - self.device.handle.destroy_pipeline(self.pipeline, None); - log::debug!("Pipeline destroyed ({:?})", self.pipeline); - - self.device - .handle - .destroy_pipeline_layout(self.pipeline_layout, None); - log::debug!("Pipeline layout destroyed ({:?})", self.pipeline_layout); - } - } -} diff --git a/src/renderer/vulkan/vk_instance.rs b/src/renderer/vulkan/vk_instance.rs deleted file mode 100644 index 101dec2..0000000 --- a/src/renderer/vulkan/vk_instance.rs +++ /dev/null @@ -1,128 +0,0 @@ -use crate::renderer::vulkan::{ - utils::layers::{use_layers, LayersSelector}, - VkPhysicalDevice, -}; -use ash::khr::surface; -use ash::{vk, Entry, Instance}; -use std::ffi::{c_char, CStr, CString}; -use std::sync::Arc; - -pub struct VkInstance { - pub entry: Entry, - pub handle: Instance, - pub surface_loader: surface::Instance, -} - -impl VkInstance { - pub fn new(required_extensions: &Vec<*const c_char>) -> Self { - let entry = Entry::linked(); - - log::debug!("Initializing Vulkan instance"); - - if log::log_enabled!(log::Level::Debug) { - let layer_properties = - unsafe { entry.enumerate_instance_layer_properties() }.unwrap_or_default(); - - for layer_property in layer_properties { - let layer_extensions = unsafe { - entry.enumerate_instance_extension_properties( - layer_property.layer_name_as_c_str().ok(), - ) - } - .unwrap_or_default(); - log::debug!("{layer_property:#?} {layer_extensions:#?}"); - } - } - - { - let required_extensions = required_extensions - .iter() - .map(|str| unsafe { CStr::from_ptr(*str) }) - .map(|cstr| cstr.to_string_lossy()) - .collect::>(); - log::debug!( - "Required instance extensions: {}", - required_extensions.join(", ") - ); - } - - // Layers - #[allow(unused)] - let mut layer_selector = LayersSelector::Nothing; - #[cfg(debug_assertions)] - { - layer_selector = LayersSelector::SpecificLayers(vec![ - "VK_LAYER_KHRONOS_validation", - "VK_LAYER_MANGOHUD_overlay_x86_64", - "VK_LAYER_NV_optimus", - ]); - } - let layers = use_layers(&entry, layer_selector); - - { - let layers = layers - .iter() - .map(|layer| layer.to_string_lossy()) - .collect::>(); - log::debug!("Selected debug layers : {}", layers.join(", ")) - } - - let layers_raw = layers.iter().map(|s| s.as_ptr()).collect::>(); - - // App Info - let app_name = CString::new("VulkanTriangle").unwrap(); - let appinfo = vk::ApplicationInfo::default() - .application_name(app_name.as_c_str()) - .application_version(0) - .engine_name(app_name.as_c_str()) - .engine_version(0) - .api_version(vk::make_api_version(0, 1, 0, 0)); - - let create_flags = if cfg!(any(target_os = "macos", target_os = "ios")) { - vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR - } else { - vk::InstanceCreateFlags::default() - }; - - // Instance Info - let create_info = vk::InstanceCreateInfo::default() - .application_info(&appinfo) - .enabled_layer_names(&layers_raw) - .enabled_extension_names(&required_extensions) - .flags(create_flags); - - let instance: Instance = unsafe { - entry - .create_instance(&create_info, None) - .expect("Instance creation error") - }; - - let surface_loader = surface::Instance::new(&entry, &instance); - - log::debug!("Vulkan instance created ({:?})", instance.handle()); - - Self { - entry, - handle: instance, - surface_loader, - } - } - - pub fn get_physical_devices(instance: &Arc) -> Vec { - let physical_devices = unsafe { instance.handle.enumerate_physical_devices() }; - physical_devices - .unwrap_or_default() - .iter() - .map(|physical_device| VkPhysicalDevice::new(&instance, *physical_device)) - .collect() - } -} - -impl Drop for VkInstance { - fn drop(&mut self) { - unsafe { - self.handle.destroy_instance(None); - } - log::debug!("Vulkan instance destroyed ({:?})", self.handle.handle()); - } -} diff --git a/src/renderer/vulkan/vk_physical_device.rs b/src/renderer/vulkan/vk_physical_device.rs deleted file mode 100644 index 3534f24..0000000 --- a/src/renderer/vulkan/vk_physical_device.rs +++ /dev/null @@ -1,85 +0,0 @@ -use std::sync::Arc; -use super::{VkInstance, VkSurface}; -use ash::vk; - -pub struct VkPhysicalDevice { - instance: Arc, - pub handle: vk::PhysicalDevice, - - pub properties: vk::PhysicalDeviceProperties, - pub features: vk::PhysicalDeviceFeatures, - pub queue_family_properties: Vec, -} - -impl VkPhysicalDevice { - pub fn new(instance: &Arc, physical_device: vk::PhysicalDevice) -> Self { - log::debug!("New physical device"); - let device_properties = unsafe { instance.handle.get_physical_device_properties(physical_device) }; - log::debug!("{device_properties:#?}"); - let device_features = unsafe { instance.handle.get_physical_device_features(physical_device) }; - log::debug!("{device_features:#?}"); - let device_queue_families = - unsafe { instance.handle.get_physical_device_queue_family_properties(physical_device) }; - log::debug!("{device_queue_families:#?}"); - - Self { - instance: Arc::clone(instance), - handle: physical_device, - properties: device_properties, - features: device_features, - queue_family_properties: device_queue_families, - } - } - - pub fn find_queue_family_by( - &self, - queue_flags: Option, - surface: Option<&VkSurface>, - ) -> Option<(u32, &vk::QueueFamilyProperties)> { - self.queue_family_properties.iter().enumerate().find_map( - |(index, queue_family_property)| { - let surface_check_passed = match surface { - Some(surface) => surface - .physical_device_queue_supported(self, index as u32) - .unwrap_or(false), - None => true, - }; - - let queue_flags_check_passed = match queue_flags { - Some(queue_flags) => queue_family_property.queue_flags.contains(queue_flags), - None => true, - }; - - if surface_check_passed && queue_flags_check_passed { - Some((index as u32, queue_family_property)) - } else { - None - } - }, - ) - } - - pub fn pick_physical_device_and_queue_by<'a>( - physical_devices: &'a Vec, - queue_flags: Option, - surface: Option<&VkSurface>, - ) -> Option<(&'a VkPhysicalDevice, u32, &'a vk::QueueFamilyProperties)> { - physical_devices.iter().find_map(|physical_device| { - physical_device - .find_queue_family_by(queue_flags, surface) - .and_then(|(queue_index, queue_family_properties)| { - Some((physical_device, queue_index, queue_family_properties)) - }) - }) - } - - pub fn priority(&self) -> usize { - match self.properties.device_type { - vk::PhysicalDeviceType::CPU => 1, - vk::PhysicalDeviceType::VIRTUAL_GPU => 2, - vk::PhysicalDeviceType::INTEGRATED_GPU => 3, - vk::PhysicalDeviceType::DISCRETE_GPU => 4, - _ => 0, - } - } -} diff --git a/src/renderer/vulkan/vk_render_context.rs b/src/renderer/vulkan/vk_render_context.rs deleted file mode 100644 index 68dd304..0000000 --- a/src/renderer/vulkan/vk_render_context.rs +++ /dev/null @@ -1,206 +0,0 @@ -use super::{ - VkCommandPool, VkDevice, VkFence, VkFramebuffer, VkGraphicsPipeline, VkInstance, VkPhysicalDevice, - VkRenderPass, VkSemaphore, VkSurface, VkSwapchain, -}; -use ash::vk; -use std::sync::Arc; -use crate::renderer::Renderable; - -pub struct VkRenderContext { - instance: Arc, - surface: Arc, - device: Arc, - - swapchain: Arc, - render_pass: Arc, - framebuffers: Vec>, - - command_pool: VkCommandPool, - command_buffers: Vec, - image_available_semaphore: VkSemaphore, - render_finished_semaphore: VkSemaphore, - in_flight_fence: VkFence, -} - -impl VkRenderContext { - pub fn init(window: &crate::display::Window) -> anyhow::Result { - let required_extensions = window.required_extensions()?; - - let instance = Arc::new(VkInstance::new(&required_extensions)); - let surface = Arc::new(VkSurface::new(&window, instance.clone())?); - - let mut physical_devices = VkInstance::get_physical_devices(&instance); - physical_devices.sort_by(|a, b| b.priority().cmp(&a.priority())); - - let (physical_device, queue_family_index, properties) = - VkPhysicalDevice::pick_physical_device_and_queue_by( - &physical_devices, - Some(vk::QueueFlags::GRAPHICS), - Some(&surface), - ) - .ok_or_else(|| anyhow::anyhow!("Unable to find physical device"))?; - log::debug!( - "Selected queue {properties:#?} for physical device {:?}", - physical_device.properties.device_name_as_c_str() - ); - - let device = Arc::new(VkDevice::new_graphics_device( - &instance, - &physical_device, - queue_family_index, - )?); - - let swapchain = Arc::new(VkSwapchain::new( - &window, - &surface, - &device, - &physical_device, - )?); - - let render_pass = Arc::new(VkRenderPass::new(&device, &swapchain)?); - - let framebuffers = swapchain - .create_framebuffers(&render_pass) - .ok_or_else(|| anyhow::anyhow!("Failed to get framebuffers"))?; - - let command_pool = VkCommandPool::new(&device)?; - - // Destroyed with command pool - let command_buffers = command_pool - .allocate_command_buffers_for_framebuffers(framebuffers.len() as u32)?; - - let image_available_semaphore = VkSemaphore::new(&device)?; - let render_finished_semaphore = VkSemaphore::new(&device)?; - let in_flight_fence = VkFence::new(&device)?; - - Ok(Self { - instance, - surface, - device, - - swapchain, - render_pass, - framebuffers, - - command_pool, - command_buffers, - - image_available_semaphore, - render_finished_semaphore, - in_flight_fence, - }) - } - - pub fn render(&mut self, scene: Option<&Box>) -> anyhow::Result<()> { - unsafe { self.device.handle.wait_for_fences(&[self.in_flight_fence.handle], true, u64::MAX)? }; - unsafe { self.device.handle.reset_fences(&[self.in_flight_fence.handle])? }; - - let (index, _) = self - .swapchain - .acquire_next_image(&self.image_available_semaphore)?; - - // if self.swapchain.is_dirty() { - // self.update_swapchain()? - // } - - let command_buffer = self.command_buffers[index as usize]; - unsafe { self.device.handle.reset_command_buffer(command_buffer, vk::CommandBufferResetFlags::default())? }; - - let render_area = vk::Rect2D::default().extent(self.swapchain.surface_resolution); - let clear_value = vk::ClearValue::default(); - let command_buffer_begin_info = vk::CommandBufferBeginInfo::default(); - unsafe { - self.device - .handle - .begin_command_buffer(command_buffer, &command_buffer_begin_info)? - }; - - let clear_values = [clear_value]; - let framebuffer = self.framebuffers[index as usize].as_ref(); - let render_pass_begin_info = vk::RenderPassBeginInfo::default() - .render_pass(self.render_pass.handle) - .framebuffer(framebuffer.handle) - .render_area(render_area) - .clear_values(&clear_values); - - unsafe { - self.device.handle.cmd_begin_render_pass( - command_buffer, - &render_pass_begin_info, - vk::SubpassContents::INLINE, - ); - }; - - if let Some(scene) = scene { - scene.render(&self.device, &self.swapchain, &command_buffer)?; - } - - unsafe { self.device.handle.cmd_end_render_pass(command_buffer) }; - - unsafe { self.device.handle.end_command_buffer(command_buffer)? }; - - let wait_semaphores = [self.image_available_semaphore.handle]; - let signal_semaphores = [self.render_finished_semaphore.handle]; - let wait_stages = [vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT]; - let command_buffers_to_submit = [command_buffer]; - let submit_info = vk::SubmitInfo::default() - .wait_semaphores(&wait_semaphores) - .wait_dst_stage_mask(&wait_stages) - .command_buffers(&command_buffers_to_submit) - .signal_semaphores(&signal_semaphores); - - let queue = self - .device - .get_device_queue(0) - .ok_or_else(|| anyhow::anyhow!("Failed to get a queue"))?; - - unsafe { - self.device - .handle - .queue_submit(*queue, &[submit_info], self.in_flight_fence.handle)? - }; - - let swapchains = [self.swapchain.handle.unwrap()]; - let indices = [index]; - let present_info = vk::PresentInfoKHR::default() - .wait_semaphores(&signal_semaphores) - .swapchains(&swapchains) - .image_indices(&indices); - - unsafe { self.device.swapchain_loader.queue_present(*queue, &present_info)? }; - - Ok(()) - } - - pub fn update_resolution(&mut self, width: u32, height: u32) -> anyhow::Result<()> { - match Arc::get_mut(&mut self.swapchain) { - Some(swapchain) => swapchain.update_resolution(width, height)?, - None => log::warn!("Impossible to get mutable swapchain"), - } - - Ok(()) - } - - pub fn exit(&self) { - unsafe { self.device.handle.device_wait_idle().unwrap() } - } - - pub fn init_scene(&self, scene: &mut Box) -> anyhow::Result<()> { - scene.init(&self.device, &self.render_pass) - } - - fn update_swapchain(&mut self) -> anyhow::Result<()> { - match Arc::get_mut(&mut self.swapchain) { - Some(swapchain) => { - swapchain.create_swapchain()?; - - self.framebuffers = self.swapchain - .create_framebuffers(&self.render_pass) - .ok_or_else(|| anyhow::anyhow!("Failed to get framebuffers"))?; - } - None => log::warn!("Impossible to get mutable swapchain"), - } - - Ok(()) - } -} diff --git a/src/renderer/vulkan/vk_render_pass.rs b/src/renderer/vulkan/vk_render_pass.rs deleted file mode 100644 index e9819fe..0000000 --- a/src/renderer/vulkan/vk_render_pass.rs +++ /dev/null @@ -1,56 +0,0 @@ -use super::{VkDevice, VkSwapchain}; -use ash::prelude::VkResult; -use ash::vk; -use std::sync::Arc; - -pub struct VkRenderPass { - device: Arc, - - pub handle: vk::RenderPass, -} - -impl VkRenderPass { - pub fn new(device: &Arc, swapchain: &Arc) -> VkResult { - let color_attachment = vk::AttachmentDescription::default() - .format(swapchain.surface_format.format) - .samples(vk::SampleCountFlags::TYPE_1) - .load_op(vk::AttachmentLoadOp::CLEAR) - .store_op(vk::AttachmentStoreOp::STORE) - .stencil_load_op(vk::AttachmentLoadOp::DONT_CARE) - .stencil_store_op(vk::AttachmentStoreOp::DONT_CARE) - .initial_layout(vk::ImageLayout::UNDEFINED) - .final_layout(vk::ImageLayout::PRESENT_SRC_KHR); - - let color_attachment_ref = vk::AttachmentReference::default() - .attachment(0) - .layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL); - - let color_attachments = [color_attachment_ref]; - let subpass = vk::SubpassDescription::default() - .pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS) - .color_attachments(&color_attachments); - - let attachments = [color_attachment]; - let subpasses = [subpass]; - let render_pass_info = vk::RenderPassCreateInfo::default() - .attachments(&attachments) - .subpasses(&subpasses); - - let render_pass = unsafe { device.handle.create_render_pass(&render_pass_info, None)? }; - log::debug!("Render pass created ({render_pass:?})"); - - Ok(Self { - device: device.clone(), - handle: render_pass, - }) - } -} - -impl Drop for VkRenderPass { - fn drop(&mut self) { - unsafe { - self.device.handle.destroy_render_pass(self.handle, None); - log::debug!("Render pass destroyed ({:?})", self.handle); - } - } -} diff --git a/src/renderer/vulkan/vk_semaphore.rs b/src/renderer/vulkan/vk_semaphore.rs deleted file mode 100644 index facaf4e..0000000 --- a/src/renderer/vulkan/vk_semaphore.rs +++ /dev/null @@ -1,29 +0,0 @@ -use super::VkDevice; -use ash::vk; -use std::sync::Arc; - -pub struct VkSemaphore { - device: Arc, - - pub handle: vk::Semaphore, -} - -impl VkSemaphore { - pub fn new(device: &Arc) -> anyhow::Result { - let semaphore_info = vk::SemaphoreCreateInfo::default(); - let semaphore = unsafe { device.handle.create_semaphore(&semaphore_info, None)? }; - log::debug!("Semaphore created ({semaphore:?})"); - - Ok(Self { - device: device.clone(), - handle: semaphore, - }) - } -} - -impl Drop for VkSemaphore { - fn drop(&mut self) { - unsafe { self.device.handle.destroy_semaphore(self.handle, None) }; - log::debug!("Semaphore destroyed ({:?})", self.handle); - } -} \ No newline at end of file diff --git a/src/renderer/vulkan/vk_shader_module.rs b/src/renderer/vulkan/vk_shader_module.rs deleted file mode 100644 index 96ddcc5..0000000 --- a/src/renderer/vulkan/vk_shader_module.rs +++ /dev/null @@ -1,42 +0,0 @@ -use super::VkDevice; -use ash::vk; -use std::path::Path; -use std::sync::Arc; - -pub struct VkShaderModule { - device: Arc, - - pub handle: vk::ShaderModule, -} - -impl VkShaderModule { - pub fn from_spv_file>(device: &Arc, path: P) -> anyhow::Result { - let mut file = std::fs::File::open(&path)?; - let frag_shader_str = ash::util::read_spv(&mut file)?; - - let shader_create_info = vk::ShaderModuleCreateInfo::default().code(&frag_shader_str); - let shader_module = unsafe { - device - .handle - .create_shader_module(&shader_create_info, None)? - }; - log::debug!( - "Shader module created ({shader_module:?}) from {:?}", - path.as_ref() - ); - - Ok(Self { - device: device.clone(), - handle: shader_module, - }) - } -} - -impl Drop for VkShaderModule { - fn drop(&mut self) { - unsafe { - self.device.handle.destroy_shader_module(self.handle, None); - log::debug!("Shader module destroyed ({:?})", self.handle); - } - } -} diff --git a/src/renderer/vulkan/vk_surface.rs b/src/renderer/vulkan/vk_surface.rs deleted file mode 100644 index 9aace7c..0000000 --- a/src/renderer/vulkan/vk_surface.rs +++ /dev/null @@ -1,94 +0,0 @@ -use super::{VkInstance, VkPhysicalDevice}; -use ash::prelude::VkResult; -use ash::vk; -use std::sync::Arc; -use winit::raw_window_handle::{HasDisplayHandle, HasWindowHandle}; - -pub struct SwapchainSupportDetails( - pub Vec, - pub vk::SurfaceCapabilitiesKHR, - pub Vec, -); - -pub struct VkSurface { - instance: Arc, - - pub handle: vk::SurfaceKHR, -} - -impl VkSurface { - pub fn new(window: &crate::display::Window, instance: Arc) -> anyhow::Result { - let window_handle = window - .handle() - .ok_or_else(|| anyhow::anyhow!("Window handle is not available."))?; - - let surface = unsafe { - ash_window::create_surface( - &instance.entry, - &instance.handle, - window_handle.display_handle()?.as_raw(), - window_handle.window_handle()?.as_raw(), - None, - )? - }; - - log::debug!("Surface created ({:?})", surface); - - Ok(Self { instance, handle: surface }) - } - - pub fn physical_device_queue_supported( - &self, - physical_device: &VkPhysicalDevice, - queue_index: u32, - ) -> VkResult { - unsafe { - self.instance - .surface_loader - .get_physical_device_surface_support( - physical_device.handle, - queue_index, - self.handle, - ) - } - } - - pub fn get_physical_device_swapchain_support_details( - &self, - physical_device: &VkPhysicalDevice, - ) -> VkResult { - unsafe { - let formats = self - .instance - .surface_loader - .get_physical_device_surface_formats(physical_device.handle, self.handle)?; - - let capabilities = self - .instance - .surface_loader - .get_physical_device_surface_capabilities(physical_device.handle, self.handle)?; - - let present_modes = self - .instance - .surface_loader - .get_physical_device_surface_present_modes(physical_device.handle, self.handle)?; - - Ok(SwapchainSupportDetails( - formats, - capabilities, - present_modes, - )) - } - } -} - -impl Drop for VkSurface { - fn drop(&mut self) { - unsafe { - self.instance - .surface_loader - .destroy_surface(self.handle, None); - } - log::debug!("Surface destroyed ({:?})", self.handle); - } -} diff --git a/src/renderer/vulkan/vk_swapchain.rs b/src/renderer/vulkan/vk_swapchain.rs deleted file mode 100644 index 758574a..0000000 --- a/src/renderer/vulkan/vk_swapchain.rs +++ /dev/null @@ -1,297 +0,0 @@ -use super::{SwapchainSupportDetails, VkDevice, VkFramebuffer, VkPhysicalDevice, VkRenderPass, VkSemaphore, VkSurface}; -use crate::display::Window; -use ash::prelude::VkResult; -use ash::vk; -use std::sync::Arc; - -pub struct VkSwapchain { - surface: Arc, - device: Arc, - - pub handle: Option, - swapchain_support_details: SwapchainSupportDetails, - - pub desired_image_count: u32, - pub surface_format: vk::SurfaceFormatKHR, - pub surface_resolution: vk::Extent2D, - pub new_requested_surface_resolution: Option, - pub present_mode: vk::PresentModeKHR, - pub pre_transform: vk::SurfaceTransformFlagsKHR, - - pub present_images: Option>, - pub present_image_views: Option>>, -} - -impl VkSwapchain { - pub fn new( - window: &Window, - surface: &Arc, - device: &Arc, - physical_device: &VkPhysicalDevice, - ) -> anyhow::Result { - log::debug!("Creating swapchain"); - - let window_size = window - .physical_size::() - .and_then(|size| { - Some(vk::Extent2D { - width: size.width, - height: size.height, - }) - }) - .ok_or_else(|| anyhow::anyhow!("Failed to get swapchain extent"))?; - log::debug!("Window size ({}x{})", window_size.width, window_size.height); - - let swapchain_support_details = - surface.get_physical_device_swapchain_support_details(physical_device)?; - let SwapchainSupportDetails(surface_formats, surface_capabilities, present_modes) = - &swapchain_support_details; - log::debug!("Supported surface formats by physical device: {surface_formats:#?}"); - log::debug!("Surface capabilities: {surface_capabilities:#?}"); - log::debug!("Present modes: {present_modes:#?}"); - - let surface_format = Self::choose_surface_format(surface_formats) - .ok_or_else(|| anyhow::anyhow!("No available surface formats"))?; - let desired_image_count = Self::choose_desired_image_count(surface_capabilities); - let swapchain_extent = Self::choose_swapchain_extent(window_size, surface_capabilities); - let pre_transform = Self::choose_pre_transform(surface_capabilities); - let present_mode = Self::choose_present_mode(present_modes); - - let mut swapchain = Self { - surface: surface.clone(), - device: device.clone(), - - handle: None, - new_requested_surface_resolution: None, - swapchain_support_details, - desired_image_count, - surface_format, - surface_resolution: swapchain_extent, - present_mode, - pre_transform, - present_images: None, - present_image_views: None, - }; - - swapchain.create_swapchain()?; - - Ok(swapchain) - } - - pub fn create_swapchain(&mut self) -> VkResult<()> { - if let Some(new_requested_surface_resolution) = self.new_requested_surface_resolution { - self.surface_resolution = new_requested_surface_resolution; - self.new_requested_surface_resolution = None; - } - - let mut swapchain_create_info = self.create_swapchain_info(&self.surface); - - if let Some(old_swapchain) = self.handle { - swapchain_create_info.old_swapchain = old_swapchain; - } - - let swapchain = unsafe { - self.device - .swapchain_loader - .create_swapchain(&swapchain_create_info, None)? - }; - - let present_images = unsafe { - self.device - .swapchain_loader - .get_swapchain_images(swapchain)? - }; - let present_images_view = present_images - .iter() - .map(|i| { - self.create_present_image_view(*i) - .expect("Failed to create image view") - }) - .map(|i| Arc::new(i)) - .collect::>(); - - if log::log_enabled!(log::Level::Debug) { - let label = match self.handle { - None => "Swapchain created", - Some(_) => "Swapchain updated", - }; - log::debug!("{label} ({swapchain:?}) : {swapchain_create_info:#?}"); - } - - self.handle = Some(swapchain); - self.present_image_views = Some(present_images_view); - self.present_images = Some(present_images); - - Ok(()) - } - - pub fn create_framebuffers( - &self, - render_pass: &Arc, - ) -> Option>> { - let present_image_views = self.present_image_views.as_ref()?; - - Some( - present_image_views - .iter() - .map(|image_view| { - VkFramebuffer::from_swapchain_image_view( - &self.device, - &render_pass, - &image_view, - &self, - ) - .unwrap() - }) - .map(|framebuffer| Arc::new(framebuffer)) - .collect::>(), - ) - } - - pub fn update_resolution(&mut self, width: u32, height: u32) -> VkResult<()> { - log::debug!("New resolution requested ({width}x{height})"); - - let chosen_extent = Self::choose_swapchain_extent( - vk::Extent2D { width, height }, - &self.swapchain_support_details.1, - ); - if chosen_extent.width != self.surface_resolution.width - || chosen_extent.height != self.surface_resolution.height - { - self.new_requested_surface_resolution = Some(chosen_extent); - log::debug!( - "New resolution submitted ({}x{})", - chosen_extent.width, - chosen_extent.height - ); - } else { - log::debug!("New resolution skipped ({width}x{height}) : Same resolution"); - } - - Ok(()) - } - - pub fn acquire_next_image(&self, semaphore: &VkSemaphore) -> VkResult<(u32, bool)> { - unsafe { - self.device.swapchain_loader.acquire_next_image( - self.handle.unwrap(), - u64::MAX, - semaphore.handle, - vk::Fence::null(), - ) - } - } - - pub fn is_dirty(&self) -> bool { - self.new_requested_surface_resolution.is_some() - } - - fn create_swapchain_info(&self, surface: &VkSurface) -> vk::SwapchainCreateInfoKHR { - vk::SwapchainCreateInfoKHR::default() - .surface(surface.handle) - .min_image_count(self.desired_image_count) - .image_color_space(self.surface_format.color_space) - .image_format(self.surface_format.format) - .image_extent(self.surface_resolution) - .image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT) - .image_sharing_mode(vk::SharingMode::EXCLUSIVE) - .pre_transform(self.pre_transform) - .composite_alpha(vk::CompositeAlphaFlagsKHR::OPAQUE) - .present_mode(self.present_mode) - .clipped(true) - .image_array_layers(1) - } - - fn choose_swapchain_extent( - window_size: vk::Extent2D, - surface_capabilities: &vk::SurfaceCapabilitiesKHR, - ) -> vk::Extent2D { - vk::Extent2D { - width: window_size - .width - .max(surface_capabilities.min_image_extent.width) - .min(surface_capabilities.max_image_extent.width), - height: window_size - .height - .max(surface_capabilities.min_image_extent.height) - .min(surface_capabilities.max_image_extent.height), - } - } - - fn choose_surface_format( - surface_formats: &Vec, - ) -> Option { - surface_formats.first().and_then(|f| Some(*f)) - } - - fn choose_desired_image_count(surface_capabilities: &vk::SurfaceCapabilitiesKHR) -> u32 { - let mut desired_image_count = surface_capabilities.min_image_count + 1; - if surface_capabilities.max_image_count > 0 - && desired_image_count > surface_capabilities.max_image_count - { - desired_image_count = surface_capabilities.max_image_count; - } - desired_image_count - } - - fn choose_pre_transform( - surface_capabilities: &vk::SurfaceCapabilitiesKHR, - ) -> vk::SurfaceTransformFlagsKHR { - if surface_capabilities - .supported_transforms - .contains(vk::SurfaceTransformFlagsKHR::IDENTITY) - { - vk::SurfaceTransformFlagsKHR::IDENTITY - } else { - surface_capabilities.current_transform - } - } - - fn choose_present_mode(present_modes: &Vec) -> vk::PresentModeKHR { - present_modes - .iter() - .cloned() - .find(|&mode| mode == vk::PresentModeKHR::MAILBOX) - .unwrap_or(vk::PresentModeKHR::FIFO) - } - - fn create_present_image_view(&self, image: vk::Image) -> VkResult { - let create_view_info = vk::ImageViewCreateInfo::default() - .view_type(vk::ImageViewType::TYPE_2D) - .format(self.surface_format.format) - .components(vk::ComponentMapping { - r: vk::ComponentSwizzle::IDENTITY, - g: vk::ComponentSwizzle::IDENTITY, - b: vk::ComponentSwizzle::IDENTITY, - a: vk::ComponentSwizzle::IDENTITY, - }) - .subresource_range(vk::ImageSubresourceRange { - aspect_mask: vk::ImageAspectFlags::COLOR, - base_mip_level: 0, - level_count: 1, - base_array_layer: 0, - layer_count: 1, - }) - .image(image); - - unsafe { - self.device - .handle - .create_image_view(&create_view_info, None) - } - } -} - -impl Drop for VkSwapchain { - fn drop(&mut self) { - if let Some(swapchain) = self.handle { - unsafe { - self.device - .swapchain_loader - .destroy_swapchain(swapchain, None); - } - self.handle = None; - log::debug!("Swapchain destroyed ({swapchain:?})"); - } - } -} diff --git a/src/scene/mod.rs b/src/scene/mod.rs deleted file mode 100644 index 46be2e9..0000000 --- a/src/scene/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -mod triangle; -mod vertex; - -pub use triangle::TriangleScene; diff --git a/src/scene/triangle.rs b/src/scene/triangle.rs deleted file mode 100644 index f699930..0000000 --- a/src/scene/triangle.rs +++ /dev/null @@ -1,49 +0,0 @@ -use crate::renderer::vulkan::{VkDevice, VkGraphicsPipeline, VkRenderPass, VkSwapchain}; -use crate::renderer::Renderable; -use ash::vk; -use ash::vk::CommandBuffer; -use std::sync::Arc; - -pub struct TriangleScene { - pipeline: Option, -} - -impl TriangleScene { - pub fn new() -> Self { - Self { pipeline: None } - } -} - -impl Renderable for TriangleScene { - fn init(&mut self, device: &Arc, render_pass: &Arc) -> anyhow::Result<()> { - let pipeline = VkGraphicsPipeline::new(&device, &render_pass)?; - self.pipeline = Some(pipeline); - - Ok(()) - } - - fn render(&self, device: &VkDevice, swapchain: &VkSwapchain, command_buffer: &CommandBuffer) -> anyhow::Result<()> { - unsafe { - device.handle.cmd_bind_pipeline( - *command_buffer, - vk::PipelineBindPoint::GRAPHICS, - self.pipeline.as_ref().unwrap().pipeline, - ) - }; - - let viewport = vk::Viewport::default() - .width(swapchain.surface_resolution.width as f32) - .height(swapchain.surface_resolution.height as f32) - .max_depth(1.0); - - unsafe { device.handle.cmd_set_viewport(*command_buffer, 0, &[viewport]) } - - let scissor = swapchain.surface_resolution.into(); - - unsafe { device.handle.cmd_set_scissor(*command_buffer, 0, &[scissor]) } - - unsafe { device.handle.cmd_draw(*command_buffer, 3, 1, 0, 0) }; - - Ok(()) - } -} \ No newline at end of file diff --git a/src/scene/vertex.rs b/src/scene/vertex.rs deleted file mode 100644 index 0384d0c..0000000 --- a/src/scene/vertex.rs +++ /dev/null @@ -1,39 +0,0 @@ -use std::sync::Arc; -use ash::prelude::VkResult; -use ash::vk; -use crate::renderer::vulkan::{Vertex, VkBuffer, VkDevice}; - -#[derive(Default)] -struct VertexScene { - vertices: Vec, - - vertices_buffer: Option, -} - -impl VertexScene { - pub fn new() -> Self { - let vertices = vec![ - Vertex::new([0.0, -0.5], [1.0, 0.0, 0.0]), - Vertex::new([0.5, 0.5], [0.0, 1.0, 0.0]), - Vertex::new([-0.5, 0.5], [0.0, 0.0, 1.0]), - ]; - - Self { - vertices, - ..Default::default() - } - } - - - fn create_buffer(&mut self, device: &Arc) -> VkResult<()> { - let buffer_info = vk::BufferCreateInfo::default() - .usage(vk::BufferUsageFlags::VERTEX_BUFFER) - .sharing_mode(vk::SharingMode::EXCLUSIVE) - .size(self.vertices.len() as u64 * size_of::() as u64); - - let buffer = VkBuffer::new(device, &buffer_info)?; - self.vertices_buffer = Some(buffer); - - Ok(()) - } -} \ No newline at end of file