diff --git a/.vscode/extensions.json b/.vscode/extensions.json deleted file mode 100644 index a6bd770..0000000 --- a/.vscode/extensions.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "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 deleted file mode 100644 index c0caf03..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - // 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 deleted file mode 100644 index 875f10e..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "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 da7454f..85ed865 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 = 4 +version = 3 [[package]] name = "ab_glyph" @@ -25,7 +25,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "const-random", "getrandom", "once_cell", "version_check", @@ -41,12 +40,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "allocator-api2" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" - [[package]] name = "android-activity" version = "0.6.0" @@ -54,7 +47,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" dependencies = [ "android-properties", - "bitflags 2.9.0", + "bitflags 2.6.0", "cc", "cesu8", "jni", @@ -65,7 +58,7 @@ dependencies = [ "ndk-context", "ndk-sys", "num_enum", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -115,20 +108,19 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "3.0.7" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", - "once_cell", "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.97" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" [[package]] name = "arrayref" @@ -153,40 +145,18 @@ name = "ash" version = "0.38.0+1.3.281" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" -dependencies = [ - "libloading", -] [[package]] -name = "assert_type_match" -version = "0.1.1" +name = "ash-window" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f548ad2c4031f2902e3edc1f29c29e835829437de49562d8eb5dc5584d3a1043" +checksum = "52bca67b61cb81e5553babde81b8211f713cb6db79766f80168f3e5f40ea6c82" dependencies = [ - "proc-macro2", - "quote", - "syn", + "ash", + "raw-window-handle", + "raw-window-metal", ] -[[package]] -name = "async-executor" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand", - "futures-lite", - "slab", -] - -[[package]] -name = "async-task" -version = "4.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" - [[package]] name = "atomic-waker" version = "1.1.2" @@ -199,127 +169,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" -[[package]] -name = "bevy_ecs" -version = "0.15.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1597106cc01e62e6217ccb662e0748b2ce330893f27c7dc17bac33e0bb99bca9" -dependencies = [ - "bevy_ecs_macros", - "bevy_ptr", - "bevy_reflect", - "bevy_tasks", - "bevy_utils", - "bitflags 2.9.0", - "concurrent-queue", - "derive_more", - "disqualified", - "fixedbitset 0.5.7", - "nonmax", - "petgraph", - "smallvec", -] - -[[package]] -name = "bevy_ecs_macros" -version = "0.15.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f453adf07712b39826bc5845e5b0887ce03204ee8359bbe6b40a9afda60564a1" -dependencies = [ - "bevy_macro_utils", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "bevy_macro_utils" -version = "0.15.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bb6ded1ddc124ea214f6a2140e47a78d1fe79b0638dad39419cdeef2e1133f1" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "toml_edit", -] - -[[package]] -name = "bevy_ptr" -version = "0.15.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89fe0b0b919146939481a3a7c38864face2c6d0fd2c73ab3d430dc693ecd9b11" - -[[package]] -name = "bevy_reflect" -version = "0.15.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ddbca0a39e88eff2c301dc794ee9d73a53f4b08d47b2c9b5a6aac182fae6217" -dependencies = [ - "assert_type_match", - "bevy_ptr", - "bevy_reflect_derive", - "bevy_utils", - "derive_more", - "disqualified", - "downcast-rs", - "erased-serde", - "serde", - "smallvec", -] - -[[package]] -name = "bevy_reflect_derive" -version = "0.15.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d62affb769db17d34ad0b75ff27eca94867e2acc8ea350c5eca97d102bd98709" -dependencies = [ - "bevy_macro_utils", - "proc-macro2", - "quote", - "syn", - "uuid", -] - -[[package]] -name = "bevy_tasks" -version = "0.15.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "028630ddc355563bd567df1076db3515858aa26715ddf7467d2086f9b40e5ab1" -dependencies = [ - "async-executor", - "futures-channel", - "futures-lite", - "pin-project", - "wasm-bindgen-futures", -] - -[[package]] -name = "bevy_utils" -version = "0.15.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63c2174d43a0de99f863c98a472370047a2bfa7d1e5cec8d9d647fb500905d9d" -dependencies = [ - "ahash", - "bevy_utils_proc_macros", - "getrandom", - "hashbrown 0.14.5", - "thread_local", - "tracing", - "web-time", -] - -[[package]] -name = "bevy_utils_proc_macros" -version = "0.15.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94847541f6dd2e28f54a9c2b0e857da5f2631e2201ebc25ce68781cdcb721391" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "bitflags" version = "1.3.2" @@ -328,9 +177,15 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" [[package]] name = "block2" @@ -338,40 +193,26 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" dependencies = [ - "objc2 0.5.2", + "objc2", ] [[package]] name = "bumpalo" -version = "3.17.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytemuck" -version = "1.22.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540" -dependencies = [ - "bytemuck_derive", -] - -[[package]] -name = "bytemuck_derive" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] +checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" [[package]] name = "bytes" -version = "1.10.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" [[package]] name = "calloop" @@ -379,12 +220,12 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.6.0", "log", "polling", "rustix", "slab", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -401,9 +242,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.16" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" +checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" dependencies = [ "jobserver", "libc", @@ -429,12 +270,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] -name = "cmake" -version = "0.1.54" +name = "cocoa" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" +checksum = "f6140449f97a6e97f9511815c5632d84c8aacf8ac271ad77c559218161a1373c" dependencies = [ - "cc", + "bitflags 1.3.2", + "block", + "cocoa-foundation", + "core-foundation", + "core-graphics", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "cocoa-foundation" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" +dependencies = [ + "bitflags 1.3.2", + "block", + "core-foundation", + "core-graphics-types", + "libc", + "objc", ] [[package]] @@ -462,26 +324,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "const-random" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" -dependencies = [ - "const-random-macro", -] - -[[package]] -name = "const-random-macro" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" -dependencies = [ - "getrandom", - "once_cell", - "tiny-keccak", -] - [[package]] name = "core-foundation" version = "0.9.4" @@ -522,26 +364,11 @@ dependencies = [ "libc", ] -[[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" +version = "0.8.20" 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" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "cursor-icon" @@ -549,39 +376,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" -[[package]] -name = "derive_more" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" -dependencies = [ - "derive_more-impl", -] - -[[package]] -name = "derive_more-impl" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "unicode-xid", -] - [[package]] name = "dispatch" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" -[[package]] -name = "disqualified" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9c272297e804878a2a4b707cfcfc6d2328b5bb936944613b4fdf2b9269afdfd" - [[package]] name = "dlib" version = "0.5.2" @@ -605,9 +405,9 @@ checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" [[package]] name = "env_filter" -version = "0.1.3" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" dependencies = [ "log", "regex", @@ -615,67 +415,33 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.7" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3716d7a920fb4fac5d84e9d4bce8ceb321e9414b4409da61b07b75c1e3d0697" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" dependencies = [ "anstream", "anstyle", "env_filter", - "jiff", + "humantime", "log", ] [[package]] name = "equivalent" -version = "1.0.2" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "erased-serde" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e004d887f51fcb9fef17317a2f3525c887d8aa3f4f50fed920816a688284a5b7" -dependencies = [ - "serde", - "typeid", -] +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.10" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] -[[package]] -name = "fastrand" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" - -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - -[[package]] -name = "fixedbitset" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" - -[[package]] -name = "foldhash" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" - [[package]] name = "foreign-types" version = "0.5.0" @@ -703,40 +469,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" -[[package]] -name = "futures-channel" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" -dependencies = [ - "futures-core", -] - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-io" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" - -[[package]] -name = "futures-lite" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" -dependencies = [ - "fastrand", - "futures-core", - "futures-io", - "parking", - "pin-project-lite", -] - [[package]] name = "gethostname" version = "0.4.3" @@ -754,51 +486,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", - "js-sys", "libc", "wasi", - "wasm-bindgen", ] [[package]] -name = "glam" -version = "0.30.0" +name = "glob" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17fcdf9683c406c2fc4d124afd29c0d595e22210d633cbdb8695ba9935ab1dc6" - -[[package]] -name = "half" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7db2ff139bba50379da6aa0766b52fdcb62cb5b263009b09ed58ba604e14bbd1" -dependencies = [ - "bytemuck", - "cfg-if", - "crunchy", -] +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", - "allocator-api2", - "serde", -] - -[[package]] -name = "hashbrown" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" [[package]] name = "hermit-abi" @@ -807,13 +509,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" [[package]] -name = "indexmap" -version = "2.8.0" +name = "humantime" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "indexmap" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.15.2", + "hashbrown", ] [[package]] @@ -822,36 +530,6 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" -[[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.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d699bc6dfc879fb1bf9bdff0d4c56f0884fc6f0d0eb0fba397a6d00cd9a6b85e" -dependencies = [ - "jiff-static", - "log", - "portable-atomic", - "portable-atomic-util", - "serde", -] - -[[package]] -name = "jiff-static" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d16e75759ee0aa64c57a56acbf43916987b20c77373cb7e808979e02b93c9f9" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "jni" version = "0.21.1" @@ -863,7 +541,7 @@ dependencies = [ "combine", "jni-sys", "log", - "thiserror 1.0.69", + "thiserror", "walkdir", "windows-sys 0.45.0", ] @@ -885,25 +563,24 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ - "once_cell", "wasm-bindgen", ] [[package]] name = "libc" -version = "0.2.171" +version = "0.2.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" +checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" [[package]] name = "libloading" -version = "0.8.6" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", "windows-targets 0.52.6", @@ -915,32 +592,31 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.6.0", "libc", - "redox_syscall 0.5.10", + "redox_syscall 0.5.7", ] [[package]] name = "linux-raw-sys" -version = "0.4.15" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "log" -version = "0.4.26" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] [[package]] name = "memchr" @@ -957,25 +633,19 @@ dependencies = [ "libc", ] -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - [[package]] name = "ndk" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.6.0", "jni-sys", "log", "ndk-sys", "num_enum", "raw-window-handle", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -993,22 +663,6 @@ dependencies = [ "jni-sys", ] -[[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 = "nonmax" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "610a5acd306ec67f907abe5567859a3c693fb9886eb1f012ab8f2a47bef3db51" - [[package]] name = "num_enum" version = "0.7.3" @@ -1030,6 +684,15 @@ 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" @@ -1046,29 +709,20 @@ dependencies = [ "objc2-encode", ] -[[package]] -name = "objc2" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3531f65190d9cff863b77a99857e74c314dd16bf56c538c4b57c7cbc3f3a6e59" -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.9.0", + "bitflags 2.6.0", "block2", "libc", - "objc2 0.5.2", + "objc2", "objc2-core-data", "objc2-core-image", - "objc2-foundation 0.2.2", - "objc2-quartz-core 0.2.2", + "objc2-foundation", + "objc2-quartz-core", ] [[package]] @@ -1077,11 +731,11 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.6.0", "block2", - "objc2 0.5.2", + "objc2", "objc2-core-location", - "objc2-foundation 0.2.2", + "objc2-foundation", ] [[package]] @@ -1091,8 +745,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" dependencies = [ "block2", - "objc2 0.5.2", - "objc2-foundation 0.2.2", + "objc2", + "objc2-foundation", ] [[package]] @@ -1101,20 +755,10 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.6.0", "block2", - "objc2 0.5.2", - "objc2-foundation 0.2.2", -] - -[[package]] -name = "objc2-core-foundation" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daeaf60f25471d26948a1c2f840e3f7d86f4109e3af4e8e4b5cd70c39690d925" -dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.0", + "objc2", + "objc2-foundation", ] [[package]] @@ -1124,9 +768,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" dependencies = [ "block2", - "objc2 0.5.2", - "objc2-foundation 0.2.2", - "objc2-metal 0.2.2", + "objc2", + "objc2-foundation", + "objc2-metal", ] [[package]] @@ -1136,16 +780,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" dependencies = [ "block2", - "objc2 0.5.2", + "objc2", "objc2-contacts", - "objc2-foundation 0.2.2", + "objc2-foundation", ] [[package]] name = "objc2-encode" -version = "4.1.0" +version = "4.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" +checksum = "7891e71393cd1f227313c9379a26a584ff3d7e6e7159e988851f0934c993f0f8" [[package]] name = "objc2-foundation" @@ -1153,22 +797,11 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.6.0", "block2", "dispatch", "libc", - "objc2 0.5.2", -] - -[[package]] -name = "objc2-foundation" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a21c6c9014b82c39515db5b396f91645182611c97d24637cf56ac01e5f8d998" -dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.0", - "objc2-core-foundation", + "objc2", ] [[package]] @@ -1178,9 +811,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" dependencies = [ "block2", - "objc2 0.5.2", + "objc2", "objc2-app-kit", - "objc2-foundation 0.2.2", + "objc2-foundation", ] [[package]] @@ -1189,21 +822,10 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.6.0", "block2", - "objc2 0.5.2", - "objc2-foundation 0.2.2", -] - -[[package]] -name = "objc2-metal" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01c41bc8b0e50ea7a5304a56f25e0066f526e99641b46fd7b9ad4421dd35bff6" -dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.0", - "objc2-foundation 0.3.0", + "objc2", + "objc2-foundation", ] [[package]] @@ -1212,24 +834,11 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.6.0", "block2", - "objc2 0.5.2", - "objc2-foundation 0.2.2", - "objc2-metal 0.2.2", -] - -[[package]] -name = "objc2-quartz-core" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb3794501bb1bee12f08dcad8c61f2a5875791ad1c6f47faa71a0f033f20071" -dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.0", - "objc2-core-foundation", - "objc2-foundation 0.3.0", - "objc2-metal 0.3.0", + "objc2", + "objc2-foundation", + "objc2-metal", ] [[package]] @@ -1238,8 +847,8 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc" dependencies = [ - "objc2 0.5.2", - "objc2-foundation 0.2.2", + "objc2", + "objc2-foundation", ] [[package]] @@ -1248,16 +857,16 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.6.0", "block2", - "objc2 0.5.2", + "objc2", "objc2-cloud-kit", "objc2-core-data", "objc2-core-image", "objc2-core-location", - "objc2-foundation 0.2.2", + "objc2-foundation", "objc2-link-presentation", - "objc2-quartz-core 0.2.2", + "objc2-quartz-core", "objc2-symbols", "objc2-uniform-type-identifiers", "objc2-user-notifications", @@ -1270,8 +879,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" dependencies = [ "block2", - "objc2 0.5.2", - "objc2-foundation 0.2.2", + "objc2", + "objc2-foundation", ] [[package]] @@ -1280,18 +889,18 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.6.0", "block2", - "objc2 0.5.2", + "objc2", "objc2-core-location", - "objc2-foundation 0.2.2", + "objc2-foundation", ] [[package]] name = "once_cell" -version = "1.21.1" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "orbclient" @@ -1311,65 +920,26 @@ dependencies = [ "ttf-parser", ] -[[package]] -name = "parking" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" - -[[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.10", - "smallvec", - "windows-targets 0.52.6", -] - [[package]] name = "percent-encoding" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" -[[package]] -name = "petgraph" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" -dependencies = [ - "fixedbitset 0.4.2", - "indexmap", -] - [[package]] name = "pin-project" -version = "1.1.10" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.10" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", @@ -1378,15 +948,15 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.16" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pkg-config" -version = "0.3.32" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "polling" @@ -1403,53 +973,38 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "portable-atomic" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -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 = "proc-macro-crate" -version = "3.3.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ "toml_edit", ] [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" dependencies = [ "unicode-ident", ] [[package]] name = "quick-xml" -version = "0.37.2" +version = "0.36.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "165859e9e55f79d67b96c5d96f4e88b6f2695a1972849c15a6a3f5c59fc2c003" +checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe" dependencies = [ "memchr", ] [[package]] name = "quote" -version = "1.0.40" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -1462,14 +1017,14 @@ checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" [[package]] name = "raw-window-metal" -version = "1.1.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40d213455a5f1dc59214213c7330e074ddf8114c9a42411eb890c767357ce135" +checksum = "76e8caa82e31bb98fee12fa8f051c94a6aa36b07cddb03f0d4fc558988360ff1" dependencies = [ - "objc2 0.6.0", - "objc2-core-foundation", - "objc2-foundation 0.3.0", - "objc2-quartz-core 0.3.0", + "cocoa", + "core-graphics", + "objc", + "raw-window-handle", ] [[package]] @@ -1483,11 +1038,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.10" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.6.0", ] [[package]] @@ -1519,55 +1074,32 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" -[[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", - "bevy_ecs", + "ash", + "ash-window", "env_logger", - "glam", + "glob", "log", - "thiserror 2.0.12", - "vulkano", - "vulkano-shaders", "winit", ] [[package]] name = "rustix" -version = "0.38.44" +version = "0.38.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys 0.52.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" @@ -1583,12 +1115,6 @@ 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" @@ -1604,57 +1130,24 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.219" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" 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 = "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" @@ -1670,17 +1163,11 @@ dependencies = [ "autocfg", ] -[[package]] -name = "slabbin" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9db491c0d4152a069911a0fbdaca959691bf0b9d7110d98a7ed1c8e59b79ab30" - [[package]] name = "smallvec" -version = "1.14.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "smithay-client-toolkit" @@ -1688,7 +1175,7 @@ version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.6.0", "calloop", "calloop-wayland-source", "cursor-icon", @@ -1696,7 +1183,7 @@ dependencies = [ "log", "memmap2", "rustix", - "thiserror 1.0.69", + "thiserror", "wayland-backend", "wayland-client", "wayland-csd-frame", @@ -1724,9 +1211,9 @@ checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" [[package]] name = "syn" -version = "2.0.100" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ "proc-macro2", "quote", @@ -1739,16 +1226,7 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl 1.0.69", -] - -[[package]] -name = "thiserror" -version = "2.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" -dependencies = [ - "thiserror-impl 2.0.12", + "thiserror-impl", ] [[package]] @@ -1762,36 +1240,6 @@ 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 = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - [[package]] name = "tiny-skia" version = "0.11.4" @@ -1825,9 +1273,9 @@ checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" [[package]] name = "toml_edit" -version = "0.22.24" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ "indexmap", "toml_datetime", @@ -1836,9 +1284,9 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "pin-project-lite", "tracing-core", @@ -1846,30 +1294,21 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.33" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" -dependencies = [ - "once_cell", -] +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" [[package]] name = "ttf-parser" -version = "0.25.1" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" - -[[package]] -name = "typeid" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" +checksum = "5902c5d130972a0000f60860bfbf46f7ca3db5391eddfedd1b8728bd9dc96c0e" [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-segmentation" @@ -1877,101 +1316,18 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - [[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" -[[package]] -name = "uuid" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b" -dependencies = [ - "getrandom", -] - [[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", - "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", - "proc-macro2", - "quote", - "shaderc", - "syn", - "vulkano", -] - [[package]] name = "walkdir" version = "2.5.0" @@ -1990,24 +1346,24 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if", "once_cell", - "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.100" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", + "once_cell", "proc-macro2", "quote", "syn", @@ -2016,22 +1372,21 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.50" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" dependencies = [ "cfg-if", "js-sys", - "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2039,9 +1394,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", @@ -2052,18 +1407,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" -dependencies = [ - "unicode-ident", -] +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "wayland-backend" -version = "0.3.8" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7208998eaa3870dad37ec8836979581506e0c5c64c20c9e79e9d2a10d6f47bf" +checksum = "056535ced7a150d45159d3a8dc30f91a2e2d588ca0b23f70e56033622b8016f6" dependencies = [ "cc", "downcast-rs", @@ -2075,11 +1427,11 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.31.8" +version = "0.31.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2120de3d33638aaef5b9f4472bff75f07c56379cf76ea320bd3a3d65ecaf73f" +checksum = "b66249d3fc69f76fd74c82cc319300faa554e9d865dab1f7cd66cc20db10b280" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.6.0", "rustix", "wayland-backend", "wayland-scanner", @@ -2091,16 +1443,16 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.6.0", "cursor-icon", "wayland-backend", ] [[package]] name = "wayland-cursor" -version = "0.31.8" +version = "0.31.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a93029cbb6650748881a00e4922b076092a6a08c11e7fbdb923f064b23968c5d" +checksum = "32b08bc3aafdb0035e7fe0fdf17ba0c09c268732707dca4ae098f60cb28c9e4c" dependencies = [ "rustix", "wayland-client", @@ -2109,11 +1461,11 @@ dependencies = [ [[package]] name = "wayland-protocols" -version = "0.32.6" +version = "0.32.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0781cf46869b37e36928f7b432273c0995aa8aed9552c556fb18754420541efc" +checksum = "7cd0ade57c4e6e9a8952741325c30bf82f4246885dca8bf561898b86d0c1f58e" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.6.0", "wayland-backend", "wayland-client", "wayland-scanner", @@ -2121,11 +1473,11 @@ dependencies = [ [[package]] name = "wayland-protocols-plasma" -version = "0.3.6" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ccaacc76703fefd6763022ac565b590fcade92202492381c95b2edfdf7d46b3" +checksum = "9b31cab548ee68c7eb155517f2212049dc151f7cd7910c2b66abfd31c3ee12bd" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.6.0", "wayland-backend", "wayland-client", "wayland-protocols", @@ -2134,11 +1486,11 @@ dependencies = [ [[package]] name = "wayland-protocols-wlr" -version = "0.3.6" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248a02e6f595aad796561fa82d25601bd2c8c3b145b1c7453fc8f94c1a58f8b2" +checksum = "782e12f6cd923c3c316130d56205ebab53f55d6666b7faddfad36cecaeeb4022" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.6.0", "wayland-backend", "wayland-client", "wayland-protocols", @@ -2147,9 +1499,9 @@ dependencies = [ [[package]] name = "wayland-scanner" -version = "0.31.6" +version = "0.31.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "896fdafd5d28145fce7958917d69f2fd44469b1d4e861cb5961bcbeebc6d1484" +checksum = "597f2001b2e5fc1121e3d5b9791d3e78f05ba6bfa4641053846248e3a13661c3" dependencies = [ "proc-macro2", "quick-xml", @@ -2158,9 +1510,9 @@ dependencies = [ [[package]] name = "wayland-sys" -version = "0.31.6" +version = "0.31.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbcebb399c77d5aa9fa5db874806ee7b4eba4e73650948e8f93963f128896615" +checksum = "efa8ac0d8e8ed3e3b5c9fc92c7881406a268e11555abe36493efabe649a29e09" dependencies = [ "dlib", "log", @@ -2170,9 +1522,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.77" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" dependencies = [ "js-sys", "wasm-bindgen", @@ -2404,14 +1756,14 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winit" -version = "0.30.9" +version = "0.30.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a809eacf18c8eca8b6635091543f02a5a06ddf3dad846398795460e6e0ae3cc0" +checksum = "0be9e76a1f1077e04a411f0b989cbd3c93339e1771cb41e71ac4aee95bfd2c67" dependencies = [ "ahash", "android-activity", "atomic-waker", - "bitflags 2.9.0", + "bitflags 2.6.0", "block2", "bytemuck", "calloop", @@ -2425,9 +1777,9 @@ dependencies = [ "libc", "memmap2", "ndk", - "objc2 0.5.2", + "objc2", "objc2-app-kit", - "objc2-foundation 0.2.2", + "objc2-foundation", "objc2-ui-kit", "orbclient", "percent-encoding", @@ -2456,9 +1808,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.4" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] @@ -2507,7 +1859,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.6.0", "dlib", "log", "once_cell", @@ -2520,18 +1872,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" -[[package]] -name = "xml-rs" -version = "0.8.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5b940ebc25896e71dd073bad2dbaa2abfe97b0a391415e22ad1326d9c54e3c4" - -[[package]] -name = "xmlparser" -version = "0.13.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" - [[package]] name = "zerocopy" version = "0.7.35" diff --git a/Cargo.toml b/Cargo.toml index a84f681..3865769 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,24 +1,19 @@ [package] name = "rust_vulkan_test" version = "0.1.0" -edition = "2024" +edition = "2021" authors = ["Florian RICHER "] publish = false [dependencies] anyhow = "1.0" -thiserror = "2.0" winit = { version = "0.30", features = ["rwh_06"] } - -vulkano = "0.35" -vulkano-shaders = "0.35" - -# Math -glam = { version = "0.30" } - -# ECS -bevy_ecs = "0.15.3" +ash = { version = "0.38", default-features = false, features = ["linked", "debug", "std"] } +ash-window = "0.13" # Log and tracing log = "0.4" env_logger = "0.11.5" + +[build-dependencies] +glob = "0.3" \ No newline at end of file diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..be949e6 --- /dev/null +++ b/build.rs @@ -0,0 +1,24 @@ +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/flake.lock b/flake.lock index 2853bb7..9ff2d00 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1731533236, - "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "lastModified": 1726560853, + "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", "owner": "numtide", "repo": "flake-utils", - "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", "type": "github" }, "original": { @@ -28,27 +28,26 @@ ] }, "locked": { - "lastModified": 1735283791, - "narHash": "sha256-JlT4VFs8aVlW+l151HZIZumfFsccZXcO/k5WpbYF09Y=", - "owner": "phirsch", + "lastModified": 1713543440, + "narHash": "sha256-lnzZQYG0+EXl/6NkGpyIz+FEOc/DSEG57AP1VsdeNrM=", + "owner": "nix-community", "repo": "nixGL", - "rev": "ea8baea3b9d854bf9cf5c834a805c50948dd2603", + "rev": "310f8e49a149e4c9ea52f1adf70cdc768ec53f8a", "type": "github" }, "original": { - "owner": "phirsch", - "ref": "fix-versionMatch", + "owner": "nix-community", "repo": "nixGL", "type": "github" } }, "nixpkgs": { "locked": { - "lastModified": 1742546557, - "narHash": "sha256-QyhimDBaDBtMfRc7kyL28vo+HTwXRPq3hz+BgSJDotw=", + "lastModified": 1730831018, + "narHash": "sha256-2S0HwIFRxYp+afuoFORcZA9TjryAf512GmE0MTfEOPU=", "owner": "nixos", "repo": "nixpkgs", - "rev": "bfa9810ff7104a17555ab68ebdeafb6705f129b1", + "rev": "8c4dc69b9732f6bbe826b5fbb32184987520ff26", "type": "github" }, "original": { @@ -73,11 +72,11 @@ ] }, "locked": { - "lastModified": 1742524367, - "narHash": "sha256-KzTwk/5ETJavJZYV1DEWdCx05M4duFCxCpRbQSKWpng=", + "lastModified": 1730860036, + "narHash": "sha256-u0sfA4B65Q9cRO3xpIkQ4nldB8isfdIb3rWtsnRZ+Iw=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "70bf752d176b2ce07417e346d85486acea9040ef", + "rev": "b8eb3aeb21629cbe14968a5e3b1cbaefb0d1b260", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 4f7cd2e..624590d 100644 --- a/flake.nix +++ b/flake.nix @@ -9,8 +9,7 @@ inputs.nixpkgs.follows = "nixpkgs"; }; nixgl = { - # Revert this to community version when https://github.com/nix-community/nixGL/pull/187 is merged - url = "github:phirsch/nixGL/fix-versionMatch"; + url = "github:nix-community/nixGL"; inputs.nixpkgs.follows = "nixpkgs"; inputs.flake-utils.follows = "flake-utils"; }; @@ -31,53 +30,24 @@ cargo = rust; }); - renderdoc = pkgs.renderdoc.overrideAttrs (oldAttrs: { - cmakeFlags = oldAttrs.cmakeFlags ++ [ - (pkgs.lib.cmakeBool "ENABLE_UNSUPPORTED_EXPERIMENTAL_POSSIBLY_BROKEN_WAYLAND" true) - ]; - }); - - 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 - ]) + libs = with pkgs; [ vulkan-headers vulkan-loader vulkan-validation-layers ] + ++ pkgs.lib.optionals pkgs.stdenv.hostPlatform.isLinux (with pkgs; [ libxkbcommon wayland libGL ]) ++ 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 = [ - 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:${renderdoc}/share/vulkan/implicit_layer.d"; - RUST_LOG = "info,rust_vulkan_test=trace"; - }; in { devShells = { - default = mkCustomShell { packages = [ pkgs.nixgl.auto.nixVulkanNvidia pkgs.nixgl.nixVulkanMesa ]; }; - nixos = mkCustomShell { }; + 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 ]); + }; }; packages = { @@ -87,7 +57,8 @@ src = self; - inherit nativeBuildInputs buildInputs; + nativeBuildInputs = with pkgs; [ pkg-config shaderc ]; + buildInputs = libs; cargoLock = { lockFile = ./Cargo.lock; diff --git a/res/shaders/main.frag b/res/shaders/main.frag new file mode 100644 index 0000000..33ca4af --- /dev/null +++ b/res/shaders/main.frag @@ -0,0 +1,8 @@ +#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 new file mode 100644 index 0000000..d141c1d --- /dev/null +++ b/res/shaders/main.vert @@ -0,0 +1 @@ +#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 720d192..04f88bd 100644 --- a/res/shaders/vertex.frag +++ b/res/shaders/vertex.frag @@ -1,9 +1,10 @@ #version 450 +#extension GL_ARB_separate_shader_objects: enable -layout (location = 0) in vec3 color; +layout (location = 0) in vec3 fragColor; -layout (location = 0) out vec4 f_color; +layout (location = 0) out vec4 outColor; void main() { - f_color = vec4(color, 1.0); + outColor = vec4(fragColor, 1.0); } \ No newline at end of file diff --git a/res/shaders/vertex.vert b/res/shaders/vertex.vert index 65b0acf..d7b1aac 100644 --- a/res/shaders/vertex.vert +++ b/res/shaders/vertex.vert @@ -1 +1 @@ -#version 450 layout (location = 0) in vec2 position; layout (location = 1) in vec3 color; layout (location = 0) out vec3 fragColor; layout (set = 0, binding = 0) uniform MVPData { mat4 world; mat4 view; mat4 projection; } uniforms; void main() { mat4 worldview = uniforms.view * uniforms.world; gl_Position = uniforms.projection * worldview * vec4(position, 0.0, 1.0); fragColor = color; } \ No newline at end of file +#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 diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 00822fd..2e2b8c8 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "1.85.1" +channel = "1.82.0" diff --git a/src/core/app/app.rs b/src/core/app/app.rs deleted file mode 100644 index 3821bfc..0000000 --- a/src/core/app/app.rs +++ /dev/null @@ -1,56 +0,0 @@ -use std::error::Error; - -use bevy_ecs::world::World; - -pub enum AppExit { - Success, - Error(Box), -} - -pub type RunnerFn = Box AppExit>; - -#[derive(Debug, thiserror::Error)] -pub enum AppError { - #[error("Runner is not set")] - RunnerNotSet, - #[error("Runner returned an error : {0}")] - RunnerError(Box), -} - -pub struct App { - world: World, - runner: Option, -} - -impl Default for App { - fn default() -> Self { - Self { - world: World::new(), - runner: None, - } - } -} - -impl App { - pub fn world_mut(&mut self) -> &mut World { - &mut self.world - } - - pub fn world(&self) -> &World { - &self.world - } - - pub fn run(mut self) -> Result<(), AppError> { - match self.runner.take() { - Some(runner) => match runner(self) { - AppExit::Success => Ok(()), - AppExit::Error(e) => Err(AppError::RunnerError(e)), - }, - None => Err(AppError::RunnerNotSet), - } - } - - pub fn set_runner(&mut self, runner: RunnerFn) { - self.runner = Some(runner); - } -} diff --git a/src/core/app/mod.rs b/src/core/app/mod.rs deleted file mode 100644 index c6c8a20..0000000 --- a/src/core/app/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -mod app; -pub use app::*; diff --git a/src/core/camera/mod.rs b/src/core/camera/mod.rs deleted file mode 100644 index f9b6925..0000000 --- a/src/core/camera/mod.rs +++ /dev/null @@ -1,19 +0,0 @@ -use bevy_ecs::component::Component; -use glam::{Mat4, Quat, Vec3}; - -pub trait Camera: Into + Component {} - -#[derive(Component)] -pub struct Camera3D { - pub projection: Mat4, - pub position: Vec3, - pub rotation: Quat, -} - -impl Into for Camera3D { - fn into(self) -> Mat4 { - Mat4::from_rotation_translation(self.rotation, self.position) * self.projection - } -} - -impl Camera for Camera3D {} diff --git a/src/core/mod.rs b/src/core/mod.rs deleted file mode 100644 index abaeeae..0000000 --- a/src/core/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod app; -pub mod camera; -pub mod render; -pub mod vulkan; -pub mod window; diff --git a/src/core/render/material.rs b/src/core/render/material.rs deleted file mode 100644 index 539d4bc..0000000 --- a/src/core/render/material.rs +++ /dev/null @@ -1,7 +0,0 @@ -use std::sync::Arc; - -use bevy_ecs::component::Component; -use vulkano::pipeline::GraphicsPipeline; - -#[derive(Component)] -pub struct Material(pub Arc); diff --git a/src/core/render/mesh.rs b/src/core/render/mesh.rs deleted file mode 100644 index ca5ec0f..0000000 --- a/src/core/render/mesh.rs +++ /dev/null @@ -1,14 +0,0 @@ -use bevy_ecs::component::Component; - -use super::vertex::Vertex2D; - -#[derive(Component)] -pub struct Mesh2D { - pub vertices: Vec, -} - -impl Mesh2D { - pub fn new(vertices: Vec) -> Self { - Self { vertices } - } -} diff --git a/src/core/render/mod.rs b/src/core/render/mod.rs deleted file mode 100644 index 5d003a8..0000000 --- a/src/core/render/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod material; -pub mod mesh; -pub mod vertex; diff --git a/src/core/render/vertex.rs b/src/core/render/vertex.rs deleted file mode 100644 index 9bf133e..0000000 --- a/src/core/render/vertex.rs +++ /dev/null @@ -1,38 +0,0 @@ -use std::sync::Arc; -use vulkano::Validated; -use vulkano::buffer::{ - AllocateBufferError, Buffer, BufferContents, BufferCreateInfo, BufferUsage, Subbuffer, -}; -use vulkano::memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator}; -use vulkano::pipeline::graphics::vertex_input::Vertex; - -#[derive(BufferContents, Vertex)] -#[repr(C)] -pub struct Vertex2D { - #[format(R32G32_SFLOAT)] - pub position: [f32; 2], - - #[format(R32G32B32_SFLOAT)] - pub color: [f32; 3], -} - -impl Vertex2D { - pub fn create_buffer( - vertices: Vec, - memory_allocator: &Arc, - ) -> Result, Validated> { - 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() - }, - vertices, - ) - } -} diff --git a/src/core/vulkan/mod.rs b/src/core/vulkan/mod.rs deleted file mode 100644 index fe22fb3..0000000 --- a/src/core/vulkan/mod.rs +++ /dev/null @@ -1,28 +0,0 @@ -use vulkan_context::VulkanContext; -use window_render_context::WindowRenderContext; - -use super::app::App; - -mod utils; -mod vulkan_context; -mod window_render_context; - -#[derive(Debug, thiserror::Error)] -pub enum VulkanError { - #[error("Failed to create vulkan context")] - FailedToCreateVulkanContext, -} - -pub struct Vulkan; - -impl Vulkan { - pub fn new(app: &mut App) -> Result<(), VulkanError> { - let vulkan_context = VulkanContext::from(app as &App); - app.world_mut().insert_resource(vulkan_context); - - let window_render_context = WindowRenderContext::from(app as &App); - app.world_mut().insert_resource(window_render_context); - - Ok(()) - } -} diff --git a/src/core/vulkan/utils.rs b/src/core/vulkan/utils.rs deleted file mode 100644 index 046528f..0000000 --- a/src/core/vulkan/utils.rs +++ /dev/null @@ -1,137 +0,0 @@ -use std::sync::Arc; - -use vulkano::{ - Version, VulkanLibrary, - device::{ - Device, DeviceCreateInfo, DeviceExtensions, DeviceFeatures, Queue, QueueCreateInfo, - QueueFlags, - physical::{PhysicalDevice, PhysicalDeviceType}, - }, - instance::{Instance, InstanceCreateFlags, InstanceCreateInfo, InstanceExtensions}, -}; -use winit::raw_window_handle::HasDisplayHandle; - -pub(super) fn load_library() -> Arc { - let library = VulkanLibrary::new().unwrap(); - - log::debug!("Available layer:"); - for layer in library.layer_properties().unwrap() { - log::debug!( - "\t - Layer name: {}, Description: {}, Implementation Version: {}, Vulkan Version: {}", - layer.name(), - layer.description(), - layer.implementation_version(), - layer.vulkan_version() - ); - } - - library -} - -pub(super) fn create_instance( - library: Arc, - required_extensions: InstanceExtensions, -) -> Arc { - Instance::new( - library, - InstanceCreateInfo { - // Enable enumerating devices that use non-conformant Vulkan implementations. - // (e.g. MoltenVK) - flags: InstanceCreateFlags::ENUMERATE_PORTABILITY, - enabled_extensions: required_extensions, - enabled_layers: vec![String::from("VK_LAYER_KHRONOS_validation")], - ..Default::default() - }, - ) - .unwrap() -} - -pub(super) fn find_physical_device_queue_family_indexes( - physical_device: &Arc, - display_handle: &impl HasDisplayHandle, -) -> Option { - let mut graphic_queue_family_index = None; - - for (i, queue_family_property) in physical_device.queue_family_properties().iter().enumerate() { - if queue_family_property - .queue_flags - .intersects(QueueFlags::GRAPHICS) - && physical_device - .presentation_support(i as u32, display_handle) - .unwrap() - { - graphic_queue_family_index = Some(i as u32); - } - } - - graphic_queue_family_index -} - -pub(super) fn pick_physical_device_and_queue_family_indexes( - instance: &Arc, - display_handle: &impl HasDisplayHandle, - device_extensions: &DeviceExtensions, -) -> Option<(Arc, u32)> { - instance - .enumerate_physical_devices() - .unwrap() - .filter(|p| { - p.api_version() >= Version::V1_3 || p.supported_extensions().khr_dynamic_rendering - }) - .filter(|p| p.supported_extensions().contains(device_extensions)) - .filter_map(|p| { - find_physical_device_queue_family_indexes(&p, display_handle) - .and_then(|indexes| Some((p, indexes))) - }) - .min_by_key(|(p, _)| match p.properties().device_type { - PhysicalDeviceType::DiscreteGpu => 0, - PhysicalDeviceType::IntegratedGpu => 1, - PhysicalDeviceType::VirtualGpu => 2, - PhysicalDeviceType::Cpu => 3, - PhysicalDeviceType::Other => 4, - _ => 5, - }) -} - -pub(super) fn pick_graphics_device( - instance: &Arc, - display_handle: &impl HasDisplayHandle, -) -> (Arc, impl ExactSizeIterator>) { - let mut device_extensions = DeviceExtensions { - khr_swapchain: true, - ..DeviceExtensions::empty() - }; - - let (physical_device, graphics_family_index) = - pick_physical_device_and_queue_family_indexes(instance, display_handle, &device_extensions) - .unwrap(); - - log::debug!( - "Using device: {} (type: {:?})", - physical_device.properties().device_name, - physical_device.properties().device_type, - ); - - if physical_device.api_version() < Version::V1_3 { - device_extensions.khr_dynamic_rendering = true; - } - - log::debug!("Using device extensions: {:#?}", device_extensions); - - Device::new( - physical_device, - DeviceCreateInfo { - queue_create_infos: vec![QueueCreateInfo { - queue_family_index: graphics_family_index, - ..Default::default() - }], - enabled_extensions: device_extensions, - enabled_features: DeviceFeatures { - dynamic_rendering: true, - ..DeviceFeatures::empty() - }, - ..Default::default() - }, - ) - .unwrap() -} diff --git a/src/core/vulkan/vulkan_context.rs b/src/core/vulkan/vulkan_context.rs deleted file mode 100644 index f59d9a3..0000000 --- a/src/core/vulkan/vulkan_context.rs +++ /dev/null @@ -1,87 +0,0 @@ -use std::{any::Any, sync::Arc}; - -use bevy_ecs::system::Resource; -use vulkano::{ - command_buffer::{ - AutoCommandBufferBuilder, CommandBufferUsage, PrimaryAutoCommandBuffer, - allocator::StandardCommandBufferAllocator, - }, - descriptor_set::allocator::StandardDescriptorSetAllocator, - device::{Device, Queue}, - instance::Instance, - memory::allocator::StandardMemoryAllocator, - swapchain::Surface, -}; -use winit::raw_window_handle::{HasDisplayHandle, HasWindowHandle}; - -use crate::core::{app::App, window::raw_handle::DisplayHandleWrapper}; - -use super::utils; - -#[derive(Resource)] -pub struct VulkanContext { - pub instance: Arc, - pub device: Arc, - pub graphics_queue: Arc, - - pub memory_allocator: Arc, - pub command_buffer_allocator: Arc, - pub descriptor_set_allocator: Arc, -} - -impl VulkanContext { - pub fn create_surface( - &self, - window: Arc, - ) -> Arc { - Surface::from_window(self.instance.clone(), window).unwrap() - } - - pub fn create_render_builder(&self) -> AutoCommandBufferBuilder { - AutoCommandBufferBuilder::primary( - self.command_buffer_allocator.clone(), - self.graphics_queue.queue_family_index(), - CommandBufferUsage::OneTimeSubmit, - ) - .unwrap() - } -} - -impl From<&App> for VulkanContext { - fn from(app: &App) -> Self { - let library = utils::load_library(); - - let world = app.world(); - - let display_handle: &DisplayHandleWrapper = - world.get_resource::().unwrap(); - - let enabled_extensions = Surface::required_extensions(&display_handle.0).unwrap(); - - let instance = utils::create_instance(library.clone(), enabled_extensions); - - let (device, mut queues) = utils::pick_graphics_device(&instance, &display_handle.0); - let graphics_queue = queues.next().unwrap(); - - let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device.clone())); - - let command_buffer_allocator = Arc::new(StandardCommandBufferAllocator::new( - device.clone(), - Default::default(), - )); - - let descriptor_set_allocator = Arc::new(StandardDescriptorSetAllocator::new( - device.clone(), - Default::default(), - )); - - Self { - instance: instance.clone(), - device, - graphics_queue, - memory_allocator, - command_buffer_allocator, - descriptor_set_allocator, - } - } -} diff --git a/src/core/vulkan/window_render_context.rs b/src/core/vulkan/window_render_context.rs deleted file mode 100644 index 1c653a7..0000000 --- a/src/core/vulkan/window_render_context.rs +++ /dev/null @@ -1,117 +0,0 @@ -use bevy_ecs::system::Resource; -use std::sync::Arc; -use vulkano::image::view::ImageView; -use vulkano::image::{Image, ImageUsage}; -use vulkano::pipeline::graphics::viewport::Viewport; -use vulkano::swapchain::{Swapchain, SwapchainCreateInfo}; -use vulkano::sync::{self, GpuFuture}; -use vulkano::{Validated, VulkanError}; -use winit::window::Window; - -use crate::core::app::App; -use crate::core::window::raw_handle::WindowWrapper; - -use super::vulkan_context::VulkanContext; - -#[derive(Resource)] -pub struct WindowRenderContext { - pub window: Arc, - pub swapchain: Arc, - pub attachment_image_views: Vec>, - pub viewport: Viewport, - pub recreate_swapchain: bool, - pub previous_frame_end: Option>, -} - -impl From<&App> for WindowRenderContext { - fn from(app: &App) -> Self { - let world = app.world(); - let vulkan_context = world.get_resource::().unwrap(); - let window_handle = world.get_resource::().unwrap(); - let window_size = window_handle.0.inner_size(); - - let surface = vulkan_context.create_surface(window_handle.0.clone()); - - let (swapchain, images) = { - let surface_capabilities = vulkan_context - .device - .physical_device() - .surface_capabilities(&surface, Default::default()) - .unwrap(); - - let (image_format, _) = vulkan_context - .device - .physical_device() - .surface_formats(&surface, Default::default()) - .unwrap()[0]; - - Swapchain::new( - vulkan_context.device.clone(), - surface, - SwapchainCreateInfo { - // 2 because with some graphics driver, it crash on fullscreen because fullscreen need to min image to works. - min_image_count: surface_capabilities.min_image_count.max(2), - image_format, - image_extent: window_size.into(), - image_usage: ImageUsage::COLOR_ATTACHMENT, - composite_alpha: surface_capabilities - .supported_composite_alpha - .into_iter() - .next() - .unwrap(), - - ..Default::default() - }, - ) - .unwrap() - }; - - let attachment_image_views = window_size_dependent_setup(&images); - - let viewport = Viewport { - offset: [0.0, 0.0], - extent: window_size.into(), - depth_range: 0.0..=1.0, - }; - - let recreate_swapchain = false; - let previous_frame_end = Some(sync::now(vulkan_context.device.clone()).boxed_send_sync()); - - Self { - window: window_handle.0.clone(), - swapchain, - attachment_image_views, - viewport, - recreate_swapchain, - previous_frame_end, - } - } -} - -impl WindowRenderContext { - pub fn update_swapchain(&mut self) -> Result<(), Validated> { - if !self.recreate_swapchain { - return Ok(()); - } - - let window_size = self.window.inner_size(); - let (new_swapchain, new_images) = self.swapchain.recreate(SwapchainCreateInfo { - image_extent: window_size.into(), - ..self.swapchain.create_info() - })?; - - self.swapchain = new_swapchain; - self.attachment_image_views = window_size_dependent_setup(&new_images); - self.viewport.extent = window_size.into(); - self.recreate_swapchain = false; - - Ok(()) - } -} - -fn window_size_dependent_setup(images: &[Arc]) -> Vec> { - images - .iter() - .map(|image| ImageView::new_default(image.clone()).unwrap()) - .collect::>() -} diff --git a/src/core/window/config.rs b/src/core/window/config.rs deleted file mode 100644 index 8fbef8c..0000000 --- a/src/core/window/config.rs +++ /dev/null @@ -1,17 +0,0 @@ -use bevy_ecs::system::Resource; -use winit::{dpi::PhysicalSize, window::WindowAttributes}; - -#[derive(Resource, Clone)] -pub struct WindowConfig { - pub title: String, - pub width: u32, - pub height: u32, -} - -impl Into for &WindowConfig { - fn into(self) -> WindowAttributes { - WindowAttributes::default() - .with_title(self.title.clone()) - .with_inner_size(PhysicalSize::new(self.width as f64, self.height as f64)) - } -} diff --git a/src/core/window/mod.rs b/src/core/window/mod.rs deleted file mode 100644 index 4368310..0000000 --- a/src/core/window/mod.rs +++ /dev/null @@ -1,48 +0,0 @@ -use config::WindowConfig; -use raw_handle::{DisplayHandleWrapper, EventLoopProxyWrapper}; -use state::WindowState; -use winit::event_loop::EventLoop; - -use super::app::{App, AppExit}; - -pub mod config; -pub mod raw_handle; -pub mod state; - -#[derive(Debug, thiserror::Error)] -pub enum WindowError { - #[error("Failed to create event loop")] - FailedToCreateEventLoop, -} - -pub struct Window; - -impl Window { - pub fn new(app: &mut App, window_config: WindowConfig) -> Result<(), WindowError> { - let world = app.world_mut(); - world.insert_resource(window_config); - - let mut event_loop_builder = EventLoop::with_user_event(); - let event_loop = event_loop_builder - .build() - .map_err(|_| WindowError::FailedToCreateEventLoop)?; - - world.insert_resource(DisplayHandleWrapper(event_loop.owned_display_handle())); - - app.set_runner(Box::new(move |app| runner(app, event_loop))); - - Ok(()) - } -} - -fn runner(mut app: App, event_loop: EventLoop<()>) -> AppExit { - app.world_mut() - .insert_resource(EventLoopProxyWrapper::new(event_loop.create_proxy())); - - let mut window_state = WindowState::new(app); - - match event_loop.run_app(&mut window_state) { - Ok(_) => AppExit::Success, - Err(e) => AppExit::Error(Box::new(e)), - } -} diff --git a/src/core/window/raw_handle.rs b/src/core/window/raw_handle.rs deleted file mode 100644 index ad9c8dd..0000000 --- a/src/core/window/raw_handle.rs +++ /dev/null @@ -1,23 +0,0 @@ -use std::sync::Arc; - -use bevy_ecs::system::Resource; -use winit::{event_loop::EventLoopProxy, window::Window}; - -#[derive(Resource)] -pub struct EventLoopProxyWrapper(EventLoopProxy); - -impl EventLoopProxyWrapper { - pub fn new(event_loop: EventLoopProxy) -> Self { - Self(event_loop) - } - - pub fn proxy(&self) -> &EventLoopProxy { - &self.0 - } -} - -#[derive(Resource)] -pub struct DisplayHandleWrapper(pub winit::event_loop::OwnedDisplayHandle); - -#[derive(Resource)] -pub struct WindowWrapper(pub Arc); diff --git a/src/core/window/state.rs b/src/core/window/state.rs deleted file mode 100644 index 0b0966e..0000000 --- a/src/core/window/state.rs +++ /dev/null @@ -1,46 +0,0 @@ -use std::sync::Arc; - -use bevy_ecs::world::World; -use winit::{ - application::ApplicationHandler, event::WindowEvent, event_loop::ActiveEventLoop, - window::WindowId, -}; - -use crate::core::app::App; - -use super::{config::WindowConfig, raw_handle::WindowWrapper}; - -pub struct WindowState { - app: App, -} - -impl WindowState { - pub fn new(app: App) -> Self { - Self { app } - } - - fn world(&self) -> &World { - self.app.world() - } -} - -impl ApplicationHandler for WindowState { - fn resumed(&mut self, event_loop: &ActiveEventLoop) { - let window_config = self.world().get_resource::().unwrap(); - - let window = event_loop.create_window(window_config.into()).unwrap(); - self.app - .world_mut() - .insert_resource(WindowWrapper(Arc::new(window))); - } - - fn window_event(&mut self, event_loop: &ActiveEventLoop, _id: WindowId, event: WindowEvent) { - match event { - WindowEvent::CloseRequested => { - log::debug!("The close button was pressed; stopping"); - event_loop.exit(); - } - _ => {} - } - } -} diff --git a/src/display/app.rs b/src/display/app.rs new file mode 100644 index 0000000..0d5fb1d --- /dev/null +++ b/src/display/app.rs @@ -0,0 +1,93 @@ +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 new file mode 100644 index 0000000..f7758ab --- /dev/null +++ b/src/display/mod.rs @@ -0,0 +1,5 @@ +mod app; +mod window; + +pub use app::App; +pub use window::Window; diff --git a/src/display/window.rs b/src/display/window.rs new file mode 100644 index 0000000..803fd35 --- /dev/null +++ b/src/display/window.rs @@ -0,0 +1,65 @@ +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/mod.rs b/src/game/mod.rs deleted file mode 100644 index 0b7787d..0000000 --- a/src/game/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -use crate::core::{ - app::App, - vulkan::Vulkan, - window::{Window, config::WindowConfig}, -}; - -pub fn init(app: &mut App) { - let window_config = WindowConfig { - title: "Rust ASH Test".to_string(), - width: 800, - height: 600, - }; - - Window::new(app, window_config).unwrap(); - Vulkan::new(app).unwrap(); -} diff --git a/src/main.rs b/src/main.rs index 8297797..2f48cfe 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,29 +1,24 @@ -use std::error::Error; use winit::event_loop::{ControlFlow, EventLoop}; -pub mod core; -pub mod game; -pub mod old_app; +mod display; +mod renderer; +mod scene; -fn main() -> Result<(), impl Error> { +fn main() { env_logger::init(); - run_new_app() - // run_old_app() -} - -fn run_new_app() -> Result<(), impl Error> { - let mut app = core::app::App::default(); - game::init(&mut app); - app.run() -} - -fn run_old_app() -> Result<(), impl Error> { let event_loop = EventLoop::new().unwrap(); event_loop.set_control_flow(ControlFlow::Poll); - let vulkan_context = old_app::vulkan_context::VulkanContext::from(&event_loop); - let mut app = old_app::app::App::from(vulkan_context); + 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), + )); - event_loop.run_app(&mut app) + let window = display::Window::new(window_attributes); + let mut app = display::App::new(window); + + event_loop.run_app(&mut app).unwrap(); } diff --git a/src/old_app/app.rs b/src/old_app/app.rs deleted file mode 100644 index cfcf038..0000000 --- a/src/old_app/app.rs +++ /dev/null @@ -1,178 +0,0 @@ -use crate::old_app::scene::Scene; -use crate::old_app::vulkan_context::VulkanContext; -use crate::old_app::window_render_context::WindowRenderContext; -use std::sync::Arc; -use vulkano::command_buffer::{RenderingAttachmentInfo, RenderingInfo}; -use vulkano::render_pass::{AttachmentLoadOp, AttachmentStoreOp}; -use vulkano::swapchain::{SwapchainPresentInfo, acquire_next_image}; -use vulkano::sync::GpuFuture; -use vulkano::{Validated, VulkanError, sync}; -use winit::application::ApplicationHandler; -use winit::event::WindowEvent; -use winit::event_loop::ActiveEventLoop; -use winit::window::WindowId; - -pub struct App { - vulkan_context: VulkanContext, - window_render_context: Option, - scene: Option, -} - -impl From for App { - fn from(vulkan_context: VulkanContext) -> Self { - Self { - vulkan_context, - window_render_context: None, - scene: None, - } - } -} - -impl ApplicationHandler for App { - fn resumed(&mut self, event_loop: &ActiveEventLoop) { - 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 window = Arc::new(event_loop.create_window(window_attributes).unwrap()); - - let surface = self.vulkan_context.create_surface(window.clone()); - - self.window_render_context = Some(WindowRenderContext::new( - window, - surface, - &self.vulkan_context.device, - )); - self.scene = Some( - Scene::load( - &self.vulkan_context, - self.window_render_context.as_ref().unwrap(), - ) - .unwrap(), - ); - } - - fn window_event(&mut self, event_loop: &ActiveEventLoop, _id: WindowId, event: WindowEvent) { - match event { - WindowEvent::CloseRequested => { - log::debug!("The close button was pressed; stopping"); - event_loop.exit(); - } - WindowEvent::Resized(_) => { - let rcx = self.window_render_context.as_mut().unwrap(); - rcx.recreate_swapchain = true; - } - WindowEvent::RedrawRequested => { - let (image_index, acquire_future) = { - let rcx = self.window_render_context.as_mut().unwrap(); - let window_size = rcx.window.inner_size(); - - if window_size.width == 0 || window_size.height == 0 { - return; - } - - rcx.previous_frame_end.as_mut().unwrap().cleanup_finished(); - rcx.update_swapchain().unwrap(); - - let (image_index, suboptimal, acquire_future) = - match acquire_next_image(rcx.swapchain.clone(), None) - .map_err(Validated::unwrap) - { - Ok(r) => r, - Err(VulkanError::OutOfDate) => { - rcx.recreate_swapchain = true; - return; - } - Err(e) => panic!("failed to acquire next image: {e}"), - }; - - if suboptimal { - rcx.recreate_swapchain = true; - } - - (image_index, acquire_future) - }; - - let mut builder = self.vulkan_context.create_render_builder(); - - { - let rcx = self.window_render_context.as_ref().unwrap(); - builder - .begin_rendering(RenderingInfo { - color_attachments: vec![Some(RenderingAttachmentInfo { - load_op: AttachmentLoadOp::Clear, - store_op: AttachmentStoreOp::Store, - clear_value: Some([0.0, 0.0, 0.0, 1.0].into()), - ..RenderingAttachmentInfo::image_view( - rcx.attachment_image_views[image_index as usize].clone(), - ) - })], - ..Default::default() - }) - .unwrap() - .set_viewport(0, [rcx.viewport.clone()].into_iter().collect()) - .unwrap(); - } - - if let Some(scene) = self.scene.as_ref() { - scene - .render( - &self.vulkan_context, - &self.window_render_context.as_ref().unwrap(), - &mut builder, - ) - .unwrap(); - } - - builder.end_rendering().unwrap(); - - let command_buffer = builder.build().unwrap(); - - { - let rcx = self.window_render_context.as_mut().unwrap(); - - let future = rcx - .previous_frame_end - .take() - .unwrap() - .join(acquire_future) - .then_execute(self.vulkan_context.graphics_queue.clone(), command_buffer) - .unwrap() - .then_swapchain_present( - self.vulkan_context.graphics_queue.clone(), - SwapchainPresentInfo::swapchain_image_index( - rcx.swapchain.clone(), - image_index, - ), - ) - .then_signal_fence_and_flush(); - - match future.map_err(Validated::unwrap) { - Ok(future) => { - rcx.previous_frame_end = Some(future.boxed()); - } - Err(VulkanError::OutOfDate) => { - rcx.recreate_swapchain = true; - rcx.previous_frame_end = - Some(sync::now(self.vulkan_context.device.clone()).boxed()); - } - Err(e) => { - println!("failed to flush future: {e}"); - rcx.previous_frame_end = - Some(sync::now(self.vulkan_context.device.clone()).boxed()); - } - } - } - } - _ => {} - } - } - - fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) { - let rcx = self.window_render_context.as_mut().unwrap(); - rcx.window.request_redraw(); - } -} diff --git a/src/old_app/mod.rs b/src/old_app/mod.rs deleted file mode 100644 index 9fce0a9..0000000 --- a/src/old_app/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod app; -pub mod pipelines; -pub mod scene; -pub mod vulkan_context; -pub mod window_render_context; diff --git a/src/old_app/pipelines/mod.rs b/src/old_app/pipelines/mod.rs deleted file mode 100644 index e5f30a7..0000000 --- a/src/old_app/pipelines/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod triangle_pipeline; diff --git a/src/old_app/pipelines/triangle_pipeline.rs b/src/old_app/pipelines/triangle_pipeline.rs deleted file mode 100644 index e573747..0000000 --- a/src/old_app/pipelines/triangle_pipeline.rs +++ /dev/null @@ -1,111 +0,0 @@ -use std::collections::BTreeMap; -use std::error::Error; -use std::sync::Arc; -use vulkano::descriptor_set::layout::{ - DescriptorSetLayoutBinding, DescriptorSetLayoutCreateInfo, DescriptorType, -}; -use vulkano::device::Device; -use vulkano::pipeline::graphics::GraphicsPipelineCreateInfo; -use vulkano::pipeline::graphics::color_blend::{ColorBlendAttachmentState, ColorBlendState}; -use vulkano::pipeline::graphics::input_assembly::InputAssemblyState; -use vulkano::pipeline::graphics::multisample::MultisampleState; -use vulkano::pipeline::graphics::rasterization::RasterizationState; -use vulkano::pipeline::graphics::subpass::PipelineRenderingCreateInfo; -use vulkano::pipeline::graphics::vertex_input::{Vertex, VertexDefinition}; -use vulkano::pipeline::graphics::viewport::ViewportState; -use vulkano::pipeline::layout::{PipelineDescriptorSetLayoutCreateInfo, PipelineLayoutCreateFlags}; -use vulkano::pipeline::{ - DynamicState, GraphicsPipeline, PipelineLayout, PipelineShaderStageCreateInfo, -}; -use vulkano::shader::{EntryPoint, ShaderStages}; -use vulkano::swapchain::Swapchain; - -use crate::core::render::vertex::Vertex2D; - -pub mod shaders { - pub mod vs { - vulkano_shaders::shader! { - ty: "vertex", - path: r"res/shaders/vertex.vert", - } - } - - pub mod fs { - vulkano_shaders::shader! { - ty: "fragment", - path: r"res/shaders/vertex.frag", - } - } -} - -pub fn create_triangle_pipeline( - device: &Arc, - swapchain: &Arc, -) -> Result, Box> { - let (vs, fs) = load_shaders(device)?; - let vertex_input_state = Vertex2D::per_vertex().definition(&vs)?; - - let stages = [ - PipelineShaderStageCreateInfo::new(vs), - PipelineShaderStageCreateInfo::new(fs), - ]; - - let mut bindings = BTreeMap::::new(); - let mut descriptor_set_layout_binding = - DescriptorSetLayoutBinding::descriptor_type(DescriptorType::UniformBuffer); - descriptor_set_layout_binding.stages = ShaderStages::VERTEX; - bindings.insert(0, descriptor_set_layout_binding); - - let descriptor_set_layout = DescriptorSetLayoutCreateInfo { - bindings, - ..Default::default() - }; - - let create_info = PipelineDescriptorSetLayoutCreateInfo { - set_layouts: vec![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.image_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(), - )), - dynamic_state: [DynamicState::Viewport].into_iter().collect(), - subpass: Some(subpass.into()), - ..GraphicsPipelineCreateInfo::layout(layout) - }, - )?; - - Ok(pipeline) -} - -fn load_shaders(device: &Arc) -> Result<(EntryPoint, EntryPoint), Box> { - 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())?; - - Ok((vs, fs)) -} diff --git a/src/old_app/scene.rs b/src/old_app/scene.rs deleted file mode 100644 index 72e3f48..0000000 --- a/src/old_app/scene.rs +++ /dev/null @@ -1,175 +0,0 @@ -use crate::old_app::pipelines::triangle_pipeline::shaders::vs; -use glam::{Mat3, Mat4, Vec3}; -use std::error::Error; -use std::sync::Arc; -use std::time::Instant; -use vulkano::buffer::{Buffer, BufferCreateInfo, BufferUsage, Subbuffer}; -use vulkano::command_buffer::{AutoCommandBufferBuilder, PrimaryAutoCommandBuffer}; -use vulkano::descriptor_set::{DescriptorSet, WriteDescriptorSet}; -use vulkano::memory::allocator::{AllocationCreateInfo, MemoryTypeFilter}; -use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint}; - -use crate::core::render::vertex::Vertex2D; -use crate::old_app::pipelines::triangle_pipeline::create_triangle_pipeline; - -use super::vulkan_context::VulkanContext; -use super::window_render_context::WindowRenderContext; - -const VERTICES: [Vertex2D; 12] = [ - // Triangle en haut à gauche - Vertex2D { - position: [-0.5, -0.75], - color: [1.0, 0.0, 0.0], - }, - Vertex2D { - position: [-0.75, -0.25], - color: [0.0, 1.0, 0.0], - }, - Vertex2D { - position: [-0.25, -0.25], - color: [0.0, 0.0, 1.0], - }, - // Triangle en bas à gauche - Vertex2D { - position: [-0.5, 0.25], - color: [0.5, 0.5, 0.5], - }, - Vertex2D { - position: [-0.75, 0.75], - color: [0.2, 0.8, 0.2], - }, - Vertex2D { - position: [-0.25, 0.75], - color: [0.8, 0.2, 0.2], - }, - // Triangle en haut à droite - Vertex2D { - position: [0.5, -0.75], - color: [1.0, 1.0, 0.0], - }, - Vertex2D { - position: [0.25, -0.25], - color: [0.0, 1.0, 1.0], - }, - Vertex2D { - position: [0.75, -0.25], - color: [1.0, 0.0, 1.0], - }, - // Triangle en bas à droite - Vertex2D { - position: [0.5, 0.25], - color: [0.1, 0.5, 0.8], - }, - Vertex2D { - position: [0.25, 0.75], - color: [0.8, 0.6, 0.1], - }, - Vertex2D { - position: [0.75, 0.75], - color: [0.3, 0.4, 0.6], - }, -]; - -pub struct Scene { - pipeline: Arc, - vertex_buffer: Subbuffer<[Vertex2D]>, - - rotation_start: Instant, -} - -impl Scene { - pub fn load( - vulkan_context: &VulkanContext, - window_render_context: &WindowRenderContext, - ) -> Result> { - let pipeline = - create_triangle_pipeline(&vulkan_context.device, &window_render_context.swapchain)?; - let vertex_buffer = - Vertex2D::create_buffer(Vec::from_iter(VERTICES), &vulkan_context.memory_allocator)?; - - Ok(Scene { - pipeline, - vertex_buffer, - rotation_start: Instant::now(), - }) - } - - pub fn render( - &self, - vulkan_context: &VulkanContext, - window_render_context: &WindowRenderContext, - builder: &mut AutoCommandBufferBuilder, - ) -> Result<(), Box> { - let vertex_count = self.vertex_buffer.len() as u32; - let instance_count = vertex_count / 3; - - let uniform_buffer = self.get_uniform_buffer(vulkan_context, window_render_context); - let layout = &self.pipeline.layout().set_layouts()[0]; - let descriptor_set = DescriptorSet::new( - vulkan_context.descriptor_set_allocator.clone(), - layout.clone(), - [WriteDescriptorSet::buffer(0, uniform_buffer)], - [], - ) - .unwrap(); - - unsafe { - builder - .bind_pipeline_graphics(self.pipeline.clone())? - .bind_descriptor_sets( - PipelineBindPoint::Graphics, - self.pipeline.layout().clone(), - 0, - descriptor_set, - )? - .bind_vertex_buffers(0, self.vertex_buffer.clone())? - .draw(vertex_count, instance_count, 0, 0)?; - } - - Ok(()) - } - - fn get_uniform_buffer( - &self, - vulkan_context: &VulkanContext, - window_render_context: &WindowRenderContext, - ) -> Subbuffer { - let swapchain = &window_render_context.swapchain; - let elapsed = self.rotation_start.elapsed(); - let rotation = elapsed.as_secs() as f64 + elapsed.subsec_nanos() as f64 / 1_000_000_000.0; - let rotation = Mat3::from_rotation_y(rotation as f32); - - // NOTE: This teapot was meant for OpenGL where the origin is at the lower left - // instead the origin is at the upper left in Vulkan, so we reverse the Y axis. - let aspect_ratio = swapchain.image_extent()[0] as f32 / swapchain.image_extent()[1] as f32; - - let proj = Mat4::perspective_rh_gl(std::f32::consts::FRAC_PI_2, aspect_ratio, 0.01, 100.0); - let view = Mat4::look_at_rh( - Vec3::new(0.3, 0.3, 1.0), - Vec3::new(0.0, 0.0, 0.0), - Vec3::new(0.0, -1.0, 0.0), - ); - let scale = Mat4::from_scale(Vec3::splat(1.0)); - - let uniform_data = vs::MVPData { - world: Mat4::from_mat3(rotation).to_cols_array_2d(), - view: (view * scale).to_cols_array_2d(), - projection: proj.to_cols_array_2d(), - }; - - Buffer::from_data( - vulkan_context.memory_allocator.clone(), - BufferCreateInfo { - usage: BufferUsage::UNIFORM_BUFFER, - ..Default::default() - }, - AllocationCreateInfo { - memory_type_filter: MemoryTypeFilter::PREFER_DEVICE - | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, - ..Default::default() - }, - uniform_data, - ) - .unwrap() - } -} diff --git a/src/old_app/vulkan_context.rs b/src/old_app/vulkan_context.rs deleted file mode 100644 index bad47de..0000000 --- a/src/old_app/vulkan_context.rs +++ /dev/null @@ -1,212 +0,0 @@ -use std::{any::Any, sync::Arc}; - -use vulkano::{ - Version, VulkanLibrary, - command_buffer::{ - AutoCommandBufferBuilder, CommandBufferUsage, PrimaryAutoCommandBuffer, - allocator::StandardCommandBufferAllocator, - }, - descriptor_set::allocator::StandardDescriptorSetAllocator, - device::{ - Device, DeviceCreateInfo, DeviceExtensions, DeviceFeatures, Queue, QueueCreateInfo, - QueueFlags, - physical::{PhysicalDevice, PhysicalDeviceType}, - }, - instance::{Instance, InstanceCreateFlags, InstanceCreateInfo, InstanceExtensions}, - memory::allocator::StandardMemoryAllocator, - swapchain::Surface, -}; -use winit::{ - event_loop::EventLoop, - raw_window_handle::{HasDisplayHandle, HasWindowHandle}, -}; - -pub struct VulkanContext { - instance: Arc, - pub device: Arc, - pub graphics_queue: Arc, - - pub memory_allocator: Arc, - pub command_buffer_allocator: Arc, - pub descriptor_set_allocator: Arc, -} - -impl From<&EventLoop<()>> for VulkanContext { - fn from(event_loop: &EventLoop<()>) -> Self { - let library = load_library(); - - let enabled_extensions = Surface::required_extensions(event_loop).unwrap(); - - let instance = create_instance(library.clone(), enabled_extensions); - - let (device, mut queues) = pick_graphics_device(&instance, event_loop); - let graphics_queue = queues.next().unwrap(); - - let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device.clone())); - - let command_buffer_allocator = Arc::new(StandardCommandBufferAllocator::new( - device.clone(), - Default::default(), - )); - - let descriptor_set_allocator = Arc::new(StandardDescriptorSetAllocator::new( - device.clone(), - Default::default(), - )); - - Self { - instance, - device, - graphics_queue, - memory_allocator, - command_buffer_allocator, - descriptor_set_allocator, - } - } -} - -impl VulkanContext { - pub fn create_surface( - &self, - window: Arc, - ) -> Arc { - Surface::from_window(self.instance.clone(), window).unwrap() - } - - pub fn create_render_builder(&self) -> AutoCommandBufferBuilder { - AutoCommandBufferBuilder::primary( - self.command_buffer_allocator.clone(), - self.graphics_queue.queue_family_index(), - CommandBufferUsage::OneTimeSubmit, - ) - .unwrap() - } -} - -fn load_library() -> Arc { - let library = VulkanLibrary::new().unwrap(); - - log::debug!("Available layer:"); - for layer in library.layer_properties().unwrap() { - log::debug!( - "\t - Layer name: {}, Description: {}, Implementation Version: {}, Vulkan Version: {}", - layer.name(), - layer.description(), - layer.implementation_version(), - layer.vulkan_version() - ); - } - - library -} - -fn create_instance( - library: Arc, - required_extensions: InstanceExtensions, -) -> Arc { - Instance::new( - library, - InstanceCreateInfo { - // Enable enumerating devices that use non-conformant Vulkan implementations. - // (e.g. MoltenVK) - flags: InstanceCreateFlags::ENUMERATE_PORTABILITY, - enabled_extensions: required_extensions, - enabled_layers: vec![String::from("VK_LAYER_KHRONOS_validation")], - ..Default::default() - }, - ) - .unwrap() -} - -fn find_physical_device_queue_family_indexes( - physical_device: &Arc, - event_loop: &EventLoop<()>, -) -> Option { - let mut graphic_queue_family_index = None; - - for (i, queue_family_property) in physical_device.queue_family_properties().iter().enumerate() { - if queue_family_property - .queue_flags - .intersects(QueueFlags::GRAPHICS) - && physical_device - .presentation_support(i as u32, event_loop) - .unwrap() - { - graphic_queue_family_index = Some(i as u32); - } - } - - graphic_queue_family_index -} - -fn pick_physical_device_and_queue_family_indexes( - instance: &Arc, - event_loop: &EventLoop<()>, - device_extensions: &DeviceExtensions, -) -> Option<(Arc, u32)> { - instance - .enumerate_physical_devices() - .unwrap() - .filter(|p| { - p.api_version() >= Version::V1_3 || p.supported_extensions().khr_dynamic_rendering - }) - .filter(|p| p.supported_extensions().contains(device_extensions)) - .filter_map(|p| { - find_physical_device_queue_family_indexes(&p, event_loop) - .and_then(|indexes| Some((p, indexes))) - }) - .min_by_key(|(p, _)| match p.properties().device_type { - PhysicalDeviceType::DiscreteGpu => 0, - PhysicalDeviceType::IntegratedGpu => 1, - PhysicalDeviceType::VirtualGpu => 2, - PhysicalDeviceType::Cpu => 3, - PhysicalDeviceType::Other => 4, - _ => 5, - }) -} - -fn pick_graphics_device( - instance: &Arc, - event_loop: &EventLoop<()>, -) -> ( - Arc, - impl ExactSizeIterator> + use<>, -) { - let mut device_extensions = DeviceExtensions { - khr_swapchain: true, - ..DeviceExtensions::empty() - }; - - let (physical_device, graphics_family_index) = - pick_physical_device_and_queue_family_indexes(instance, event_loop, &device_extensions) - .unwrap(); - - log::debug!( - "Using device: {} (type: {:?})", - physical_device.properties().device_name, - physical_device.properties().device_type, - ); - - if physical_device.api_version() < Version::V1_3 { - device_extensions.khr_dynamic_rendering = true; - } - - log::debug!("Using device extensions: {:#?}", device_extensions); - - Device::new( - physical_device, - DeviceCreateInfo { - queue_create_infos: vec![QueueCreateInfo { - queue_family_index: graphics_family_index, - ..Default::default() - }], - enabled_extensions: device_extensions, - enabled_features: DeviceFeatures { - dynamic_rendering: true, - ..DeviceFeatures::empty() - }, - ..Default::default() - }, - ) - .unwrap() -} diff --git a/src/old_app/window_render_context.rs b/src/old_app/window_render_context.rs deleted file mode 100644 index 54120d0..0000000 --- a/src/old_app/window_render_context.rs +++ /dev/null @@ -1,102 +0,0 @@ -use std::sync::Arc; -use vulkano::device::Device; -use vulkano::image::view::ImageView; -use vulkano::image::{Image, ImageUsage}; -use vulkano::pipeline::graphics::viewport::Viewport; -use vulkano::swapchain::{Surface, Swapchain, SwapchainCreateInfo}; -use vulkano::sync::GpuFuture; -use vulkano::{Validated, VulkanError, sync}; -use winit::window::Window; - -pub struct WindowRenderContext { - pub window: Arc, - pub swapchain: Arc, - pub attachment_image_views: Vec>, - pub viewport: Viewport, - pub recreate_swapchain: bool, - pub previous_frame_end: Option>, -} - -impl WindowRenderContext { - pub fn new(window: Arc, surface: Arc, device: &Arc) -> Self { - let window_size = window.inner_size(); - - let (swapchain, images) = { - let surface_capabilities = device - .physical_device() - .surface_capabilities(&surface, Default::default()) - .unwrap(); - - let (image_format, _) = device - .physical_device() - .surface_formats(&surface, Default::default()) - .unwrap()[0]; - - Swapchain::new( - device.clone(), - surface, - SwapchainCreateInfo { - // 2 because with some graphics driver, it crash on fullscreen because fullscreen need to min image to works. - min_image_count: surface_capabilities.min_image_count.max(2), - image_format, - image_extent: window_size.into(), - image_usage: ImageUsage::COLOR_ATTACHMENT, - composite_alpha: surface_capabilities - .supported_composite_alpha - .into_iter() - .next() - .unwrap(), - - ..Default::default() - }, - ) - .unwrap() - }; - - let attachment_image_views = window_size_dependent_setup(&images); - - let viewport = Viewport { - offset: [0.0, 0.0], - extent: window_size.into(), - depth_range: 0.0..=1.0, - }; - - let recreate_swapchain = false; - let previous_frame_end = Some(sync::now(device.clone()).boxed()); - - Self { - window, - swapchain, - attachment_image_views, - viewport, - recreate_swapchain, - previous_frame_end, - } - } - - pub fn update_swapchain(&mut self) -> Result<(), Validated> { - if !self.recreate_swapchain { - return Ok(()); - } - - let window_size = self.window.inner_size(); - let (new_swapchain, new_images) = self.swapchain.recreate(SwapchainCreateInfo { - image_extent: window_size.into(), - ..self.swapchain.create_info() - })?; - - self.swapchain = new_swapchain; - self.attachment_image_views = window_size_dependent_setup(&new_images); - self.viewport.extent = window_size.into(); - self.recreate_swapchain = false; - - Ok(()) - } -} - -fn window_size_dependent_setup(images: &[Arc]) -> Vec> { - images - .iter() - .map(|image| ImageView::new_default(image.clone()).unwrap()) - .collect::>() -} diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs new file mode 100644 index 0000000..cca608a --- /dev/null +++ b/src/renderer/mod.rs @@ -0,0 +1,9 @@ +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 new file mode 100644 index 0000000..a00ef58 --- /dev/null +++ b/src/renderer/vulkan/mod.rs @@ -0,0 +1,45 @@ +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 new file mode 100644 index 0000000..9d901fb --- /dev/null +++ b/src/renderer/vulkan/utils/layers.rs @@ -0,0 +1,51 @@ +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 new file mode 100644 index 0000000..759c25e --- /dev/null +++ b/src/renderer/vulkan/utils/mod.rs @@ -0,0 +1 @@ +pub mod layers; diff --git a/src/renderer/vulkan/vertex.rs b/src/renderer/vulkan/vertex.rs new file mode 100644 index 0000000..5d97213 --- /dev/null +++ b/src/renderer/vulkan/vertex.rs @@ -0,0 +1,37 @@ +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 new file mode 100644 index 0000000..b03dea4 --- /dev/null +++ b/src/renderer/vulkan/vk_buffer.rs @@ -0,0 +1,31 @@ +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 new file mode 100644 index 0000000..c657e97 --- /dev/null +++ b/src/renderer/vulkan/vk_command_pool.rs @@ -0,0 +1,52 @@ +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 new file mode 100644 index 0000000..9f14630 --- /dev/null +++ b/src/renderer/vulkan/vk_device.rs @@ -0,0 +1,109 @@ +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 new file mode 100644 index 0000000..9fb71ff --- /dev/null +++ b/src/renderer/vulkan/vk_fence.rs @@ -0,0 +1,30 @@ +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 new file mode 100644 index 0000000..8486fb5 --- /dev/null +++ b/src/renderer/vulkan/vk_framebuffer.rs @@ -0,0 +1,44 @@ +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 new file mode 100644 index 0000000..a9af298 --- /dev/null +++ b/src/renderer/vulkan/vk_graphics_pipeline.rs @@ -0,0 +1,120 @@ +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 new file mode 100644 index 0000000..101dec2 --- /dev/null +++ b/src/renderer/vulkan/vk_instance.rs @@ -0,0 +1,128 @@ +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 new file mode 100644 index 0000000..3534f24 --- /dev/null +++ b/src/renderer/vulkan/vk_physical_device.rs @@ -0,0 +1,85 @@ +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 new file mode 100644 index 0000000..68dd304 --- /dev/null +++ b/src/renderer/vulkan/vk_render_context.rs @@ -0,0 +1,206 @@ +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 new file mode 100644 index 0000000..e9819fe --- /dev/null +++ b/src/renderer/vulkan/vk_render_pass.rs @@ -0,0 +1,56 @@ +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 new file mode 100644 index 0000000..facaf4e --- /dev/null +++ b/src/renderer/vulkan/vk_semaphore.rs @@ -0,0 +1,29 @@ +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 new file mode 100644 index 0000000..96ddcc5 --- /dev/null +++ b/src/renderer/vulkan/vk_shader_module.rs @@ -0,0 +1,42 @@ +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 new file mode 100644 index 0000000..9aace7c --- /dev/null +++ b/src/renderer/vulkan/vk_surface.rs @@ -0,0 +1,94 @@ +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 new file mode 100644 index 0000000..758574a --- /dev/null +++ b/src/renderer/vulkan/vk_swapchain.rs @@ -0,0 +1,297 @@ +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 new file mode 100644 index 0000000..46be2e9 --- /dev/null +++ b/src/scene/mod.rs @@ -0,0 +1,4 @@ +mod triangle; +mod vertex; + +pub use triangle::TriangleScene; diff --git a/src/scene/triangle.rs b/src/scene/triangle.rs new file mode 100644 index 0000000..f699930 --- /dev/null +++ b/src/scene/triangle.rs @@ -0,0 +1,49 @@ +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 new file mode 100644 index 0000000..0384d0c --- /dev/null +++ b/src/scene/vertex.rs @@ -0,0 +1,39 @@ +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