From 0597579115876943f37795ffe85d1612eaa7ea3f Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Sun, 8 Dec 2024 18:19:37 +0100 Subject: [PATCH 01/41] First work with vulkano --- Cargo.lock | 339 ++++++++++++---- Cargo.toml | 10 +- build.rs | 24 -- res/shaders/main.frag | 8 - res/shaders/main.vert | 1 - res/shaders/vertex.frag | 7 +- res/shaders/vertex.vert | 2 +- src/display/app.rs | 93 ----- src/display/mod.rs | 5 - src/display/window.rs | 65 --- src/main.rs | 17 +- src/renderer/app.rs | 421 ++++++++++++++++++++ src/renderer/mod.rs | 22 +- src/renderer/render_context.rs | 133 +++++++ src/renderer/scene.rs | 210 ++++++++++ src/renderer/vulkan/mod.rs | 45 --- src/renderer/vulkan/utils/layers.rs | 51 --- src/renderer/vulkan/utils/mod.rs | 1 - src/renderer/vulkan/vertex.rs | 37 -- src/renderer/vulkan/vk_buffer.rs | 31 -- src/renderer/vulkan/vk_command_pool.rs | 52 --- src/renderer/vulkan/vk_device.rs | 109 ----- src/renderer/vulkan/vk_fence.rs | 30 -- src/renderer/vulkan/vk_framebuffer.rs | 44 -- src/renderer/vulkan/vk_graphics_pipeline.rs | 120 ------ src/renderer/vulkan/vk_instance.rs | 128 ------ src/renderer/vulkan/vk_physical_device.rs | 85 ---- src/renderer/vulkan/vk_render_context.rs | 206 ---------- src/renderer/vulkan/vk_render_pass.rs | 56 --- src/renderer/vulkan/vk_semaphore.rs | 29 -- src/renderer/vulkan/vk_shader_module.rs | 42 -- src/renderer/vulkan/vk_surface.rs | 94 ----- src/renderer/vulkan/vk_swapchain.rs | 297 -------------- src/scene/mod.rs | 4 - src/scene/triangle.rs | 49 --- src/scene/vertex.rs | 39 -- 36 files changed, 1059 insertions(+), 1847 deletions(-) delete mode 100644 build.rs delete mode 100644 res/shaders/main.frag delete mode 100644 res/shaders/main.vert delete mode 100644 src/display/app.rs delete mode 100644 src/display/mod.rs delete mode 100644 src/display/window.rs create mode 100644 src/renderer/app.rs create mode 100644 src/renderer/render_context.rs create mode 100644 src/renderer/scene.rs delete mode 100644 src/renderer/vulkan/mod.rs delete mode 100644 src/renderer/vulkan/utils/layers.rs delete mode 100644 src/renderer/vulkan/utils/mod.rs delete mode 100644 src/renderer/vulkan/vertex.rs delete mode 100644 src/renderer/vulkan/vk_buffer.rs delete mode 100644 src/renderer/vulkan/vk_command_pool.rs delete mode 100644 src/renderer/vulkan/vk_device.rs delete mode 100644 src/renderer/vulkan/vk_fence.rs delete mode 100644 src/renderer/vulkan/vk_framebuffer.rs delete mode 100644 src/renderer/vulkan/vk_graphics_pipeline.rs delete mode 100644 src/renderer/vulkan/vk_instance.rs delete mode 100644 src/renderer/vulkan/vk_physical_device.rs delete mode 100644 src/renderer/vulkan/vk_render_context.rs delete mode 100644 src/renderer/vulkan/vk_render_pass.rs delete mode 100644 src/renderer/vulkan/vk_semaphore.rs delete mode 100644 src/renderer/vulkan/vk_shader_module.rs delete mode 100644 src/renderer/vulkan/vk_surface.rs delete mode 100644 src/renderer/vulkan/vk_swapchain.rs delete mode 100644 src/scene/mod.rs delete mode 100644 src/scene/triangle.rs delete mode 100644 src/scene/vertex.rs diff --git a/Cargo.lock b/Cargo.lock index 85ed865..7092bb5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -145,16 +145,8 @@ name = "ash" version = "0.38.0+1.3.281" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" - -[[package]] -name = "ash-window" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52bca67b61cb81e5553babde81b8211f713cb6db79766f80168f3e5f40ea6c82" dependencies = [ - "ash", - "raw-window-handle", - "raw-window-metal", + "libloading", ] [[package]] @@ -181,12 +173,6 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" -[[package]] -name = "block" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" - [[package]] name = "block2" version = "0.5.1" @@ -207,6 +193,20 @@ name = "bytemuck" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "bytes" @@ -270,33 +270,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] -name = "cocoa" -version = "0.25.0" +name = "cmake" +version = "0.1.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6140449f97a6e97f9511815c5632d84c8aacf8ac271ad77c559218161a1373c" +checksum = "c682c223677e0e5b6b7f63a64b9351844c3f1b1678a68b7ee617e30fb082620e" dependencies = [ - "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", + "cc", ] [[package]] @@ -364,12 +343,27 @@ dependencies = [ "libc", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "cursor-icon" version = "1.1.0" @@ -491,10 +485,15 @@ dependencies = [ ] [[package]] -name = "glob" -version = "0.3.1" +name = "half" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "bytemuck", + "cfg-if", + "crunchy", +] [[package]] name = "hashbrown" @@ -502,6 +501,12 @@ version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hermit-abi" version = "0.4.0" @@ -530,6 +535,12 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +[[package]] +name = "itoa" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" + [[package]] name = "jni" version = "0.21.1" @@ -603,21 +614,22 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" 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" version = "2.7.4" @@ -633,6 +645,12 @@ 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" @@ -644,7 +662,8 @@ dependencies = [ "log", "ndk-sys", "num_enum", - "raw-window-handle", + "raw-window-handle 0.5.2", + "raw-window-handle 0.6.2", "thiserror", ] @@ -663,6 +682,16 @@ 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 = "num_enum" version = "0.7.3" @@ -684,15 +713,6 @@ dependencies = [ "syn", ] -[[package]] -name = "objc" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" -dependencies = [ - "malloc_buf", -] - [[package]] name = "objc-sys" version = "0.3.5" @@ -920,6 +940,29 @@ dependencies = [ "ttf-parser", ] +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.7", + "smallvec", + "windows-targets 0.52.6", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -1009,6 +1052,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "raw-window-handle" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" + [[package]] name = "raw-window-handle" version = "0.6.2" @@ -1017,14 +1066,13 @@ checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" [[package]] name = "raw-window-metal" -version = "0.4.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76e8caa82e31bb98fee12fa8f051c94a6aa36b07cddb03f0d4fc558988360ff1" +checksum = "b2000e45d7daa9b6d946e88dfa1d7ae330424a81918a6545741821c989eb80a9" dependencies = [ - "cocoa", - "core-graphics", - "objc", - "raw-window-handle", + "objc2", + "objc2-foundation", + "objc2-quartz-core", ] [[package]] @@ -1074,16 +1122,24 @@ 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", - "ash", - "ash-window", "env_logger", - "glob", "log", + "vulkano", + "vulkano-shaders", "winit", ] @@ -1100,6 +1156,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + [[package]] name = "same-file" version = "1.0.6" @@ -1115,6 +1177,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "sctk-adwaita" version = "0.10.1" @@ -1148,6 +1216,39 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.133" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +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" @@ -1163,6 +1264,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "slabbin" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd33b7a607dbd960b5e78bb4740d1f86e84250eb03a12960ee1482c2a256063" + [[package]] name = "smallvec" version = "1.13.2" @@ -1240,6 +1347,16 @@ dependencies = [ "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-skia" version = "0.11.4" @@ -1328,6 +1445,71 @@ 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.34.0" +source = "git+https://github.com/vulkano-rs/vulkano.git?branch=master#23606f05825adf5212f104ead9e95f9d325db1aa" +dependencies = [ + "ahash", + "ash", + "bytemuck", + "crossbeam-queue", + "half", + "heck", + "indexmap", + "libloading", + "nom", + "once_cell", + "parking_lot", + "proc-macro2", + "quote", + "raw-window-handle 0.6.2", + "raw-window-metal", + "serde", + "serde_json", + "slabbin", + "smallvec", + "thread_local", + "vk-parse", + "vulkano-macros", + "x11-dl", + "x11rb", +] + +[[package]] +name = "vulkano-macros" +version = "0.34.0" +source = "git+https://github.com/vulkano-rs/vulkano.git?branch=master#23606f05825adf5212f104ead9e95f9d325db1aa" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "vulkano-shaders" +version = "0.34.0" +source = "git+https://github.com/vulkano-rs/vulkano.git?branch=master#23606f05825adf5212f104ead9e95f9d325db1aa" +dependencies = [ + "ahash", + "heck", + "proc-macro2", + "quote", + "shaderc", + "syn", + "vulkano", +] + [[package]] name = "walkdir" version = "2.5.0" @@ -1784,7 +1966,8 @@ dependencies = [ "orbclient", "percent-encoding", "pin-project", - "raw-window-handle", + "raw-window-handle 0.5.2", + "raw-window-handle 0.6.2", "redox_syscall 0.4.1", "rustix", "sctk-adwaita", @@ -1872,6 +2055,18 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" +[[package]] +name = "xml-rs" +version = "0.8.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea8b391c9a790b496184c29f7f93b9ed5b16abb306c05415b68bcc16e4d06432" + +[[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 3865769..3cf3338 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,13 +7,11 @@ publish = false [dependencies] anyhow = "1.0" -winit = { version = "0.30", features = ["rwh_06"] } -ash = { version = "0.38", default-features = false, features = ["linked", "debug", "std"] } -ash-window = "0.13" +winit = { version = "0.30", features = ["rwh_05"] } + +vulkano = { git = "https://github.com/vulkano-rs/vulkano.git", branch = "master" } +vulkano-shaders = { git = "https://github.com/vulkano-rs/vulkano.git", branch = "master" } # 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 deleted file mode 100644 index be949e6..0000000 --- a/build.rs +++ /dev/null @@ -1,24 +0,0 @@ -use std::process::Command; - -fn main() { - for shader in glob::glob("res/shaders/*").unwrap().filter_map(Result::ok) { - if !shader.is_file() { - continue; - } - - let shader_file_name = shader.to_str().unwrap(); - - let mut command = Command::new("glslc"); - command.arg(&shader); - - let out_file = match shader.extension().unwrap().to_str().unwrap() { - "vert" => shader_file_name.replace(".vert", ".vert.spv"), - "frag" => shader_file_name.replace(".frag", ".frag.spv"), - _ => continue, - }; - - command.arg("-o"); - command.arg(out_file); - command.output().unwrap(); - } -} diff --git a/res/shaders/main.frag b/res/shaders/main.frag deleted file mode 100644 index 33ca4af..0000000 --- a/res/shaders/main.frag +++ /dev/null @@ -1,8 +0,0 @@ -#version 450 - -layout (location = 0) in vec3 fragColor; -layout (location = 0) out vec4 outColor; - -void main() { - outColor = vec4(fragColor, 1.0); -} \ No newline at end of file diff --git a/res/shaders/main.vert b/res/shaders/main.vert deleted file mode 100644 index d141c1d..0000000 --- a/res/shaders/main.vert +++ /dev/null @@ -1 +0,0 @@ -#version 450 out gl_PerVertex { vec4 gl_Position; }; layout (location = 0) out vec3 fragColor; vec2 positions[3] = vec2[]( vec2(0.0, -0.5), vec2(0.5, 0.5), vec2(-0.5, 0.5) ); vec3 colors[3] = vec3[]( vec3(1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, 0.0, 1.0) ); void main() { gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); fragColor = colors[gl_VertexIndex]; } \ No newline at end of file diff --git a/res/shaders/vertex.frag b/res/shaders/vertex.frag index 04f88bd..720d192 100644 --- a/res/shaders/vertex.frag +++ b/res/shaders/vertex.frag @@ -1,10 +1,9 @@ #version 450 -#extension GL_ARB_separate_shader_objects: enable -layout (location = 0) in vec3 fragColor; +layout (location = 0) in vec3 color; -layout (location = 0) out vec4 outColor; +layout (location = 0) out vec4 f_color; void main() { - outColor = vec4(fragColor, 1.0); + f_color = vec4(color, 1.0); } \ No newline at end of file diff --git a/res/shaders/vertex.vert b/res/shaders/vertex.vert index d7b1aac..3adb319 100644 --- a/res/shaders/vertex.vert +++ b/res/shaders/vertex.vert @@ -1 +1 @@ -#version 450 #extension GL_ARB_separate_shader_objects: enable // NOTE: names must match the `Vertex` struct in Rust layout (location = 0) in vec2 pos; layout (location = 1) in vec3 color; layout (location = 0) out vec3 fragColor; out gl_PerVertex { vec4 gl_Position; }; void main() { gl_Position = vec4(pos, 0.0, 1.0); fragColor = color; } \ No newline at end of file +#version 450 layout (location = 0) in vec2 position; layout (location = 1) in vec3 color; layout (location = 0) out vec3 fragColor; void main() { gl_Position = vec4(position, 0.0, 1.0); fragColor = color; } \ No newline at end of file diff --git a/src/display/app.rs b/src/display/app.rs deleted file mode 100644 index 0d5fb1d..0000000 --- a/src/display/app.rs +++ /dev/null @@ -1,93 +0,0 @@ -use crate::display::window::Window; -use crate::renderer::{vulkan::VkRenderContext, Renderable}; -use winit::application::ApplicationHandler; -use winit::event::WindowEvent; -use winit::event_loop::ActiveEventLoop; -use winit::window::WindowId; -use crate::scene::TriangleScene; - -pub struct App { - window: Window, - render_context: Option, - scene: Option>, -} - -impl App { - pub fn new(window: Window) -> Self { - Self { - window, - render_context: None, - scene: None, - } - } - - pub fn set_scene(&mut self, mut scene: Box) { - let result = self.render_context.as_mut() - .ok_or_else(|| anyhow::anyhow!("No render context")) - .and_then(|render_context| render_context.init_scene(&mut scene)); - - match result { - Ok(_) => self.scene = Some(scene), - Err(err) => log::warn!("{err}"), - } - } -} - -impl ApplicationHandler for App { - fn resumed(&mut self, event_loop: &ActiveEventLoop) { - self.window - .create_window(event_loop) - .map_err(|err| format!("Failed to create window: {}", err)) - .unwrap(); - - self.render_context = VkRenderContext::init(&self.window).ok(); - - let scene = TriangleScene::new(); - self.set_scene(Box::new(scene)); - } - - fn window_event(&mut self, event_loop: &ActiveEventLoop, _id: WindowId, event: WindowEvent) { - match event { - WindowEvent::CloseRequested => { - match self.render_context.as_ref() { - Some(render_context) => render_context.exit(), - None => log::warn!("Window closed but no render context found"), - }; - - log::debug!("The close button was pressed; stopping"); - event_loop.exit(); - } - WindowEvent::Resized(size) => { - match self.render_context.as_mut() { - Some(render_context) => { - if let Err(error) = - render_context.update_resolution(size.width, size.height) - { - log::error!( - "Failed to update resolution of render context : {}", - error - ); - } - } - None => log::warn!("Window resized but no render context found"), - }; - } - WindowEvent::RedrawRequested => { - if !event_loop.exiting() { - match self.render_context.as_mut() { - Some(render_context) => { - if let Err(error) = render_context.render(self.scene.as_ref()) { - log::error!("Failed to render with render context : {}", error); - event_loop.exit(); - } - } - None => log::warn!("Window resized but no render context found"), - }; - } - - self.window.request_redraw(); - } - _ => {} - } - } -} diff --git a/src/display/mod.rs b/src/display/mod.rs deleted file mode 100644 index f7758ab..0000000 --- a/src/display/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod app; -mod window; - -pub use app::App; -pub use window::Window; diff --git a/src/display/window.rs b/src/display/window.rs deleted file mode 100644 index 803fd35..0000000 --- a/src/display/window.rs +++ /dev/null @@ -1,65 +0,0 @@ -use std::ffi::c_char; -use winit::dpi::Pixel; -use winit::event_loop::ActiveEventLoop; -use winit::raw_window_handle::HasDisplayHandle; - -pub struct Window { - handle: Option, - window_attributes: winit::window::WindowAttributes, -} - -impl Window { - pub fn new(window_attributes: winit::window::WindowAttributes) -> Self { - Self { - handle: None, - window_attributes, - } - } - - pub fn create_window(&mut self, event_loop: &ActiveEventLoop) -> anyhow::Result<()> { - let window = event_loop.create_window(self.window_attributes.clone())?; - - self.handle = Some(window); - - Ok(()) - } - - pub fn required_extensions(&self) -> anyhow::Result> { - let display_handle = self - .handle - .as_ref() - .ok_or_else(|| anyhow::anyhow!("Window not found"))? - .display_handle()?; - - #[allow(unused_mut)] - let mut extension_names = - ash_window::enumerate_required_extensions(display_handle.as_raw())?.to_vec(); - - // TODO: Move this because is not related to Window extensions - #[cfg(any(target_os = "macos", target_os = "ios"))] - { - extension_names.push(ash::khr::portability_enumeration::NAME.as_ptr()); - // Enabling this extension is a requirement when using `VK_KHR_portability_subset` - extension_names.push(ash::khr::get_physical_device_properties2::NAME.as_ptr()); - } - - Ok(extension_names) - } - - pub fn handle(&self) -> Option<&winit::window::Window> { - self.handle.as_ref() - } - - pub fn physical_size(&self) -> Option> { - self.window_attributes - .inner_size - .and_then(|size| Some(size.to_physical::

(1.0))) - } - - pub fn request_redraw(&self) { - match self.handle.as_ref() { - Some(window) => window.request_redraw(), - None => log::warn!("Redraw requested but no window found"), - } - } -} diff --git a/src/main.rs b/src/main.rs index 2f48cfe..6c01c40 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,24 +1,15 @@ +use std::error::Error; use winit::event_loop::{ControlFlow, EventLoop}; -mod display; mod renderer; -mod scene; -fn main() { +fn main() -> Result<(), impl Error> { env_logger::init(); let event_loop = EventLoop::new().unwrap(); event_loop.set_control_flow(ControlFlow::Poll); - let window_attributes = winit::window::Window::default_attributes() - .with_title("Rust ASH Test") - .with_inner_size(winit::dpi::PhysicalSize::new( - f64::from(800), - f64::from(600), - )); + let mut app = renderer::App::new(&event_loop); - let window = display::Window::new(window_attributes); - let mut app = display::App::new(window); - - event_loop.run_app(&mut app).unwrap(); + event_loop.run_app(&mut app) } diff --git a/src/renderer/app.rs b/src/renderer/app.rs new file mode 100644 index 0000000..438f946 --- /dev/null +++ b/src/renderer/app.rs @@ -0,0 +1,421 @@ +use std::sync::Arc; +use vulkano::command_buffer::allocator::StandardCommandBufferAllocator; +use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, DeviceFeatures, Queue, QueueCreateInfo, QueueFlags}; +use vulkano::device::physical::PhysicalDeviceType; +use vulkano::instance::{Instance, InstanceCreateFlags, InstanceCreateInfo}; +use vulkano::memory::allocator::StandardMemoryAllocator; +use vulkano::swapchain::{acquire_next_image, Surface, SwapchainCreateInfo, SwapchainPresentInfo}; +use vulkano::{sync, Validated, Version, VulkanError, VulkanLibrary}; +use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, RenderingAttachmentInfo, RenderingInfo}; +use vulkano::render_pass::{AttachmentLoadOp, AttachmentStoreOp}; +use vulkano::sync::GpuFuture; +use winit::application::ApplicationHandler; +use winit::event::WindowEvent; +use winit::event_loop::{ActiveEventLoop, EventLoop}; +use winit::window::{Window, WindowId}; +use crate::renderer::render_context::RenderContext; +use crate::renderer::{window_size_dependent_setup, Scene}; + +pub struct App { + instance: Arc, + device: Arc, + queue: Arc, + memory_allocator: Arc, + command_buffer_allocator: Arc, + rcx: Option, + scene: Option, +} + +impl App { + pub fn new(event_loop: &EventLoop<()>) -> Self { + let library = VulkanLibrary::new().unwrap(); + + // The first step of any Vulkan program is to create an instance. + // + // When we create an instance, we have to pass a list of extensions that we want to enable. + // + // All the window-drawing functionalities are part of non-core extensions that we need to + // enable manually. To do so, we ask `Surface` for the list of extensions required to draw + // to a window. + let required_extensions = Surface::required_extensions(event_loop).unwrap(); + + // Now creating the instance. + let instance = 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"), + String::from("VK_LAYER_MANGOHUD_overlay_x86_64"), + String::from("VK_LAYER_NV_optimus"), + ], + ..Default::default() + }, + ) + .unwrap(); + + // Choose device extensions that we're going to use. In order to present images to a + // surface, we need a `Swapchain`, which is provided by the `khr_swapchain` extension. + let mut device_extensions = DeviceExtensions { + khr_swapchain: true, + ..DeviceExtensions::empty() + }; + + // We then choose which physical device to use. First, we enumerate all the available + // physical devices, then apply filters to narrow them down to those that can support our + // needs. + let (physical_device, queue_family_index) = instance + .enumerate_physical_devices() + .unwrap() + .filter(|p| { + // For this example, we require at least Vulkan 1.3, or a device that has the + // `khr_dynamic_rendering` extension available. + p.api_version() >= Version::V1_3 || p.supported_extensions().khr_dynamic_rendering + }) + .filter(|p| { + // Some devices may not support the extensions or features that your application, + // or report properties and limits that are not sufficient for your application. + // These should be filtered out here. + p.supported_extensions().contains(&device_extensions) + }) + .filter_map(|p| { + // For each physical device, we try to find a suitable queue family that will + // execute our draw commands. + // + // Devices can provide multiple queues to run commands in parallel (for example a + // draw queue and a compute queue), similar to CPU threads. This is something you + // have to have to manage manually in Vulkan. Queues of the same type belong to the + // same queue family. + // + // Here, we look for a single queue family that is suitable for our purposes. In a + // real-world application, you may want to use a separate dedicated transfer queue + // to handle data transfers in parallel with graphics operations. You may also need + // a separate queue for compute operations, if your application uses those. + p.queue_family_properties() + .iter() + .enumerate() + .position(|(i, q)| { + // We select a queue family that supports graphics operations. When drawing + // to a window surface, as we do in this example, we also need to check + // that queues in this queue family are capable of presenting images to the + // surface. + q.queue_flags.intersects(QueueFlags::GRAPHICS) + && p.presentation_support(i as u32, event_loop).unwrap() + }) + // The code here searches for the first queue family that is suitable. If none + // is found, `None` is returned to `filter_map`, which disqualifies this + // physical device. + .map(|i| (p, i as u32)) + }) + // All the physical devices that pass the filters above are suitable for the + // application. However, not every device is equal, some are preferred over others. + // Now, we assign each physical device a score, and pick the device with the lowest + // ("best") score. + // + // In this example, we simply select the best-scoring device to use in the application. + // In a real-world setting, you may want to use the best-scoring device only as a + // "default" or "recommended" device, and let the user choose the device themself. + .min_by_key(|(p, _)| { + // We assign a lower score to device types that are likely to be faster/better. + match p.properties().device_type { + PhysicalDeviceType::DiscreteGpu => 0, + PhysicalDeviceType::IntegratedGpu => 1, + PhysicalDeviceType::VirtualGpu => 2, + PhysicalDeviceType::Cpu => 3, + PhysicalDeviceType::Other => 4, + _ => 5, + } + }) + .expect("no suitable physical device found"); + + // Some little debug infos. + println!( + "Using device: {} (type: {:?})", + physical_device.properties().device_name, + physical_device.properties().device_type, + ); + + // If the selected device doesn't have Vulkan 1.3 available, then we need to enable the + // `khr_dynamic_rendering` extension manually. This extension became a core part of Vulkan + // in version 1.3 and later, so it's always available then and it does not need to be + // enabled. We can be sure that this extension will be available on the selected physical + // device, because we filtered out unsuitable devices in the device selection code above. + if physical_device.api_version() < Version::V1_3 { + device_extensions.khr_dynamic_rendering = true; + } + + // Now initializing the device. This is probably the most important object of Vulkan. + // + // An iterator of created queues is returned by the function alongside the device. + let (device, mut queues) = Device::new( + // Which physical device to connect to. + physical_device, + DeviceCreateInfo { + // The list of queues that we are going to use. Here we only use one queue, from + // the previously chosen queue family. + queue_create_infos: vec![QueueCreateInfo { + queue_family_index, + ..Default::default() + }], + + // A list of optional features and extensions that our program needs to work + // correctly. Some parts of the Vulkan specs are optional and must be enabled + // manually at device creation. In this example the only things we are going to + // need are the `khr_swapchain` extension that allows us to draw to a window, and + // `khr_dynamic_rendering` if we don't have Vulkan 1.3 available. + enabled_extensions: device_extensions, + + // In order to render with Vulkan 1.3's dynamic rendering, we need to enable it + // here. Otherwise, we are only allowed to render with a render pass object, as in + // the standard triangle example. The feature is required to be supported by the + // device if it supports Vulkan 1.3 and higher, or if the `khr_dynamic_rendering` + // extension is available, so we don't need to check for support. + enabled_features: DeviceFeatures { + dynamic_rendering: true, + ..DeviceFeatures::empty() + }, + + ..Default::default() + }, + ) + .unwrap(); + + // Since we can request multiple queues, the `queues` variable is in fact an iterator. We + // only use one queue in this example, so we just retrieve the first and only element of + // the iterator. + let queue = queues.next().unwrap(); + + let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device.clone())); + + // Before we can start creating and recording command buffers, we need a way of allocating + // them. Vulkano provides a command buffer allocator, which manages raw Vulkan command + // pools underneath and provides a safe interface for them. + let command_buffer_allocator = Arc::new(StandardCommandBufferAllocator::new( + device.clone(), + Default::default(), + )); + + Self { + instance, + device, + queue, + memory_allocator, + command_buffer_allocator, + rcx: 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 = Surface::from_window(self.instance.clone(), window.clone()).unwrap(); + + self.rcx = Some(RenderContext::new(window, surface, &self.device)); + self.scene = Some(Scene::initialize(&self.device, &self.rcx.as_ref().unwrap().swapchain, &self.memory_allocator)); + } + + fn window_event(&mut self, event_loop: &ActiveEventLoop, _id: WindowId, event: WindowEvent) { + let rcx = self.rcx.as_mut().unwrap(); + + match event { + WindowEvent::CloseRequested => { + log::debug!("The close button was pressed; stopping"); + event_loop.exit(); + } + WindowEvent::Resized(_) => { + rcx.recreate_swapchain = true; + } + WindowEvent::RedrawRequested => { + let window_size = rcx.window.inner_size(); + + // Do not draw the frame when the screen size is zero. On Windows, this can occur + // when minimizing the application. + if window_size.width == 0 || window_size.height == 0 { + return; + } + + // It is important to call this function from time to time, otherwise resources + // will keep accumulating and you will eventually reach an out of memory error. + // Calling this function polls various fences in order to determine what the GPU + // has already processed, and frees the resources that are no longer needed. + rcx.previous_frame_end.as_mut().unwrap().cleanup_finished(); + + // Whenever the window resizes we need to recreate everything dependent on the + // window size. In this example that includes the swapchain, the framebuffers and + // the dynamic state viewport. + if rcx.recreate_swapchain { + let (new_swapchain, new_images) = rcx + .swapchain + .recreate(SwapchainCreateInfo { + image_extent: window_size.into(), + ..rcx.swapchain.create_info() + }) + .expect("failed to recreate swapchain"); + + rcx.swapchain = new_swapchain; + + // Now that we have new swapchain images, we must create new image views from + // them as well. + rcx.attachment_image_views = window_size_dependent_setup(&new_images); + + rcx.viewport.extent = window_size.into(); + + rcx.recreate_swapchain = false; + } + + // Before we can draw on the output, we have to *acquire* an image from the + // swapchain. If no image is available (which happens if you submit draw commands + // too quickly), then the function will block. This operation returns the index of + // the image that we are allowed to draw upon. + // + // This function can block if no image is available. The parameter is an optional + // timeout after which the function call will return an error. + 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}"), + }; + + // `acquire_next_image` can be successful, but suboptimal. This means that the + // swapchain image will still work, but it may not display correctly. With some + // drivers this can be when the window resizes, but it may not cause the swapchain + // to become out of date. + if suboptimal { + rcx.recreate_swapchain = true; + } + + // In order to draw, we have to record a *command buffer*. The command buffer + // object holds the list of commands that are going to be executed. + // + // Recording a command buffer is an expensive operation (usually a few hundred + // microseconds), but it is known to be a hot path in the driver and is expected to + // be optimized. + // + // Note that we have to pass a queue family when we create the command buffer. The + // command buffer will only be executable on that given queue family. + let mut builder = AutoCommandBufferBuilder::primary( + self.command_buffer_allocator.clone(), + self.queue.queue_family_index(), + CommandBufferUsage::OneTimeSubmit, + ) + .unwrap(); + + builder + // Before we can draw, we have to *enter a render pass*. We specify which + // attachments we are going to use for rendering here, which needs to match + // what was previously specified when creating the pipeline. + .begin_rendering(RenderingInfo { + // As before, we specify one color attachment, but now we specify the image + // view to use as well as how it should be used. + color_attachments: vec![Some(RenderingAttachmentInfo { + // `Clear` means that we ask the GPU to clear the content of this + // attachment at the start of rendering. + load_op: AttachmentLoadOp::Clear, + // `Store` means that we ask the GPU to store the rendered output in + // the attachment image. We could also ask it to discard the result. + store_op: AttachmentStoreOp::Store, + // The value to clear the attachment with. Here we clear it with a blue + // color. + // + // Only attachments that have `AttachmentLoadOp::Clear` are provided + // with clear values, any others should use `None` as the clear value. + clear_value: Some([0.0, 0.0, 0.0, 1.0].into()), + ..RenderingAttachmentInfo::image_view( + // We specify image view corresponding to the currently acquired + // swapchain image, to use for this attachment. + rcx.attachment_image_views[image_index as usize].clone(), + ) + })], + ..Default::default() + }) + .unwrap() + // We are now inside the first subpass of the render pass. + // + // TODO: Document state setting and how it affects subsequent draw commands. + .set_viewport(0, [rcx.viewport.clone()].into_iter().collect()) + .unwrap(); + + if let Some(scene) = self.scene.as_ref() { + scene.render(&mut builder); + } + + builder + // We leave the render pass. + .end_rendering() + .unwrap(); + + // Finish recording the command buffer by calling `end`. + let command_buffer = builder.build().unwrap(); + + let future = rcx + .previous_frame_end + .take() + .unwrap() + .join(acquire_future) + .then_execute(self.queue.clone(), command_buffer) + .unwrap() + // The color output is now expected to contain our triangle. But in order to + // show it on the screen, we have to *present* the image by calling + // `then_swapchain_present`. + // + // This function does not actually present the image immediately. Instead it + // submits a present command at the end of the queue. This means that it will + // only be presented once the GPU has finished executing the command buffer + // that draws the triangle. + .then_swapchain_present( + self.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.device.clone()).boxed()); + } + Err(e) => { + println!("failed to flush future: {e}"); + rcx.previous_frame_end = Some(sync::now(self.device.clone()).boxed()); + } + } + } + _ => {} + } + } + + fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) { + let rcx = self.rcx.as_mut().unwrap(); + rcx.window.request_redraw(); + } +} diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index cca608a..e72d412 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -1,9 +1,19 @@ +mod render_context; +mod app; +pub use app::App; + +mod scene; +pub use scene::Scene; + use std::sync::Arc; -use ash::vk; +use vulkano::image::Image; +use vulkano::image::view::ImageView; -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 +/// This function is called once during initialization, then again whenever the window is resized. +fn window_size_dependent_setup(images: &[Arc]) -> Vec> { + images + .iter() + .map(|image| ImageView::new_default(image.clone()).unwrap()) + .collect::>() +} diff --git a/src/renderer/render_context.rs b/src/renderer/render_context.rs new file mode 100644 index 0000000..cd2bc24 --- /dev/null +++ b/src/renderer/render_context.rs @@ -0,0 +1,133 @@ +use std::sync::Arc; +use vulkano::device::Device; +use vulkano::image::{Image, ImageUsage}; +use vulkano::image::view::ImageView; +use vulkano::pipeline::graphics::subpass::PipelineRenderingCreateInfo; +use vulkano::pipeline::graphics::viewport::Viewport; +use vulkano::pipeline::GraphicsPipeline; +use vulkano::render_pass::{Framebuffer, RenderPass}; +use vulkano::swapchain::{Surface, Swapchain, SwapchainCreateInfo}; +use vulkano::sync; +use vulkano::sync::GpuFuture; +use winit::window::Window; +use crate::renderer::window_size_dependent_setup; + +pub struct RenderContext { + pub(super) window: Arc, + pub(super) swapchain: Arc, + pub(super) attachment_image_views: Vec>, + pub(super) viewport: Viewport, + pub(super) recreate_swapchain: bool, + pub(super) previous_frame_end: Option>, +} + +impl RenderContext { + pub fn new(window: Arc, surface: Arc, device: &Arc) -> Self { + let window_size = window.inner_size(); + + + // Before we can draw on the surface, we have to create what is called a swapchain. + // Creating a swapchain allocates the color buffers that will contain the image that will + // ultimately be visible on the screen. These images are returned alongside the swapchain. + let (swapchain, images) = { + // Querying the capabilities of the surface. When we create the swapchain we can only + // pass values that are allowed by the capabilities. + let surface_capabilities = device + .physical_device() + .surface_capabilities(&surface, Default::default()) + .unwrap(); + + // Choosing the internal format that the images will have. + let (image_format, _) = device + .physical_device() + .surface_formats(&surface, Default::default()) + .unwrap()[0]; + + // Please take a look at the docs for the meaning of the parameters we didn't mention. + Swapchain::new( + device.clone(), + surface, + SwapchainCreateInfo { + // Some drivers report an `min_image_count` of 1, but fullscreen mode requires + // at least 2. Therefore we must ensure the count is at least 2, otherwise the + // program would crash when entering fullscreen mode on those drivers. + min_image_count: surface_capabilities.min_image_count.max(2), + + image_format, + + // The size of the window, only used to initially setup the swapchain. + // + // NOTE: + // On some drivers the swapchain extent is specified by + // `surface_capabilities.current_extent` and the swapchain size must use this + // extent. This extent is always the same as the window size. + // + // However, other drivers don't specify a value, i.e. + // `surface_capabilities.current_extent` is `None`. These drivers will allow + // anything, but the only sensible value is the window size. + // + // Both of these cases need the swapchain to use the window size, so we just + // use that. + image_extent: window_size.into(), + + image_usage: ImageUsage::COLOR_ATTACHMENT, + + // The alpha mode indicates how the alpha value of the final image will behave. + // For example, you can choose whether the window will be opaque or + // transparent. + composite_alpha: surface_capabilities + .supported_composite_alpha + .into_iter() + .next() + .unwrap(), + + ..Default::default() + }, + ) + .unwrap() + }; + + // When creating the swapchain, we only created plain images. To use them as an attachment + // for rendering, we must wrap then in an image view. + // + // Since we need to draw to multiple images, we are going to create a different image view + // for each image. + let attachment_image_views = window_size_dependent_setup(&images); + + // Dynamic viewports allow us to recreate just the viewport when the window is resized. + // Otherwise we would have to recreate the whole pipeline. + let viewport = Viewport { + offset: [0.0, 0.0], + extent: window_size.into(), + depth_range: 0.0..=1.0, + }; + + // In some situations, the swapchain will become invalid by itself. This includes for + // example when the window is resized (as the images of the swapchain will no longer match + // the window's) or, on Android, when the application went to the background and goes back + // to the foreground. + // + // In this situation, acquiring a swapchain image or presenting it will return an error. + // Rendering to an image of that swapchain will not produce any error, but may or may not + // work. To continue rendering, we need to recreate the swapchain by creating a new + // swapchain. Here, we remember that we need to do this for the next loop iteration. + let recreate_swapchain = false; + + // In the loop below we are going to submit commands to the GPU. Submitting a command + // produces an object that implements the `GpuFuture` trait, which holds the resources for + // as long as they are in use by the GPU. + // + // Destroying the `GpuFuture` blocks until the GPU is finished executing it. In order to + // avoid that, we store the submission of the previous frame here. + let previous_frame_end = Some(sync::now(device.clone()).boxed()); + + Self { + window, + swapchain, + attachment_image_views, + viewport, + recreate_swapchain, + previous_frame_end, + } + } +} diff --git a/src/renderer/scene.rs b/src/renderer/scene.rs new file mode 100644 index 0000000..174ba7e --- /dev/null +++ b/src/renderer/scene.rs @@ -0,0 +1,210 @@ +use std::sync::Arc; +use vulkano::buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage, Subbuffer}; +use vulkano::command_buffer::{AutoCommandBufferBuilder, PrimaryAutoCommandBuffer}; +use vulkano::device::Device; +use vulkano::memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator}; +use vulkano::pipeline::graphics::vertex_input::{Vertex, VertexDefinition}; +use vulkano::pipeline::{DynamicState, GraphicsPipeline, PipelineLayout, PipelineShaderStageCreateInfo}; +use vulkano::pipeline::graphics::color_blend::{ColorBlendAttachmentState, ColorBlendState}; +use vulkano::pipeline::graphics::GraphicsPipelineCreateInfo; +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::viewport::ViewportState; +use vulkano::pipeline::layout::PipelineDescriptorSetLayoutCreateInfo; +use vulkano::swapchain::Swapchain; + +// We use `#[repr(C)]` here to force rustc to use a defined layout for our data, as the default +// representation has *no guarantees*. +#[derive(BufferContents, Vertex)] +#[repr(C)] +struct MyVertex { + #[format(R32G32_SFLOAT)] + position: [f32; 2], + + #[format(R32G32B32_SFLOAT)] + color: [f32; 3], +} + +pub struct Scene { + pipeline: Arc, + vertex_buffer: Subbuffer<[MyVertex]>, +} + +impl Scene { + pub fn initialize(device: &Arc, swapchain: &Arc, memory_allocator: &Arc) -> Scene { + // The next step is to create the shaders. + // + // The raw shader creation API provided by the vulkano library is unsafe for various + // reasons, so The `shader!` macro provides a way to generate a Rust module from GLSL + // source - in the example below, the source is provided as a string input directly to the + // shader, but a path to a source file can be provided as well. Note that the user must + // specify the type of shader (e.g. "vertex", "fragment", etc.) using the `ty` option of + // the macro. + // + // The items generated by the `shader!` macro include a `load` function which loads the + // shader using an input logical device. The module also includes type definitions for + // layout structures defined in the shader source, for example uniforms and push constants. + // + // A more detailed overview of what the `shader!` macro generates can be found in the + // vulkano-shaders crate docs. You can view them at https://docs.rs/vulkano-shaders/ + mod vs { + vulkano_shaders::shader! { + ty: "vertex", + path: r"res/shaders/vertex.vert", + } + } + + mod fs { + vulkano_shaders::shader! { + ty: "fragment", + path: r"res/shaders/vertex.frag", + } + } + + // Before we draw, we have to create what is called a **pipeline**. A pipeline describes + // how a GPU operation is to be performed. It is similar to an OpenGL program, but it also + // contains many settings for customization, all baked into a single object. For drawing, + // we create a **graphics** pipeline, but there are also other types of pipeline. + let pipeline = { + // First, we load the shaders that the pipeline will use: the vertex shader and the + // fragment shader. + // + // A Vulkan shader can in theory contain multiple entry points, so we have to specify + // which one. + let vs = vs::load(device.clone()) + .unwrap() + .entry_point("main") + .unwrap(); + let fs = fs::load(device.clone()) + .unwrap() + .entry_point("main") + .unwrap(); + + // Automatically generate a vertex input state from the vertex shader's input + // interface, that takes a single vertex buffer containing `Vertex` structs. + let vertex_input_state = MyVertex::per_vertex().definition(&vs).unwrap(); + + // Make a list of the shader stages that the pipeline will have. + let stages = [ + PipelineShaderStageCreateInfo::new(vs), + PipelineShaderStageCreateInfo::new(fs), + ]; + + // We must now create a **pipeline layout** object, which describes the locations and + // types of descriptor sets and push constants used by the shaders in the pipeline. + // + // Multiple pipelines can share a common layout object, which is more efficient. The + // shaders in a pipeline must use a subset of the resources described in its pipeline + // layout, but the pipeline layout is allowed to contain resources that are not present + // in the shaders; they can be used by shaders in other pipelines that share the same + // layout. Thus, it is a good idea to design shaders so that many pipelines have common + // resource locations, which allows them to share pipeline layouts. + let layout = PipelineLayout::new( + device.clone(), + // Since we only have one pipeline in this example, and thus one pipeline layout, + // we automatically generate the creation info for it from the resources used in + // the shaders. In a real application, you would specify this information manually + // so that you can re-use one layout in multiple pipelines. + PipelineDescriptorSetLayoutCreateInfo::from_stages(&stages) + .into_pipeline_layout_create_info(device.clone()) + .unwrap(), + ) + .unwrap(); + + // We describe the formats of attachment images where the colors, depth and/or stencil + // information will be written. The pipeline will only be usable with this particular + // configuration of the attachment images. + let subpass = PipelineRenderingCreateInfo { + // We specify a single color attachment that will be rendered to. When we begin + // rendering, we will specify a swapchain image to be used as this attachment, so + // here we set its format to be the same format as the swapchain. + color_attachment_formats: vec![Some(swapchain.image_format())], + ..Default::default() + }; + + // Finally, create the pipeline. + GraphicsPipeline::new( + device.clone(), + None, + GraphicsPipelineCreateInfo { + stages: stages.into_iter().collect(), + // How vertex data is read from the vertex buffers into the vertex shader. + vertex_input_state: Some(vertex_input_state), + // How vertices are arranged into primitive shapes. The default primitive shape + // is a triangle. + input_assembly_state: Some(InputAssemblyState::default()), + // How primitives are transformed and clipped to fit the framebuffer. We use a + // resizable viewport, set to draw over the entire window. + viewport_state: Some(ViewportState::default()), + // How polygons are culled and converted into a raster of pixels. The default + // value does not perform any culling. + rasterization_state: Some(RasterizationState::default()), + // How multiple fragment shader samples are converted to a single pixel value. + // The default value does not perform any multisampling. + multisample_state: Some(MultisampleState::default()), + // How pixel values are combined with the values already present in the + // framebuffer. The default value overwrites the old value with the new one, + // without any blending. + color_blend_state: Some(ColorBlendState::with_attachment_states( + subpass.color_attachment_formats.len() as u32, + ColorBlendAttachmentState::default(), + )), + // Dynamic states allows us to specify parts of the pipeline settings when + // recording the command buffer, before we perform drawing. Here, we specify + // that the viewport should be dynamic. + dynamic_state: [DynamicState::Viewport].into_iter().collect(), + subpass: Some(subpass.into()), + ..GraphicsPipelineCreateInfo::layout(layout) + }, + ) + .unwrap() + }; + + // We now create a buffer that will store the shape of our triangle. + let vertices = [ + MyVertex { + position: [-0.5, -0.25], + color: [1.0, 0.0, 0.0], + }, + MyVertex { + position: [0.0, 0.5], + color: [0.0, 1.0, 0.0], + }, + MyVertex { + position: [0.25, -0.1], + color: [0.0, 0.0, 1.0], + }, + ]; + let vertex_buffer = Buffer::from_iter( + memory_allocator.clone(), + BufferCreateInfo { + usage: BufferUsage::VERTEX_BUFFER, + ..Default::default() + }, + AllocationCreateInfo { + memory_type_filter: MemoryTypeFilter::PREFER_DEVICE + | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, + ..Default::default() + }, + vertices, + ) + .unwrap(); + + Self { + pipeline, + vertex_buffer, + } + } + + pub fn render(&self, builder: &mut AutoCommandBufferBuilder) { + builder.bind_pipeline_graphics(self.pipeline.clone()) + .unwrap() + .bind_vertex_buffers(0, self.vertex_buffer.clone()) + .unwrap(); + + // We add a draw command. + unsafe { builder.draw(self.vertex_buffer.len() as u32, 1, 0, 0) }.unwrap(); + } +} \ No newline at end of file diff --git a/src/renderer/vulkan/mod.rs b/src/renderer/vulkan/mod.rs deleted file mode 100644 index a00ef58..0000000 --- a/src/renderer/vulkan/mod.rs +++ /dev/null @@ -1,45 +0,0 @@ -mod vk_render_context; -pub use vk_render_context::VkRenderContext; - -mod vk_instance; -pub use vk_instance::VkInstance; - -mod vk_surface; -pub use vk_surface::{SwapchainSupportDetails, VkSurface}; - -mod vk_physical_device; -pub use vk_physical_device::VkPhysicalDevice; - -mod vk_device; -pub use vk_device::VkDevice; - -mod vk_swapchain; -pub use vk_swapchain::VkSwapchain; - -mod vk_shader_module; -pub use vk_shader_module::VkShaderModule; - -mod vk_graphics_pipeline; -pub use vk_graphics_pipeline::VkGraphicsPipeline; - -mod vk_render_pass; -pub use vk_render_pass::VkRenderPass; - -mod vk_semaphore; -pub use vk_semaphore::VkSemaphore; - -mod vk_command_pool; -pub use vk_command_pool::VkCommandPool; - -mod vk_framebuffer; -pub use vk_framebuffer::VkFramebuffer; - -mod vk_fence; -pub use vk_fence::VkFence; - -mod utils; -mod vertex; -mod vk_buffer; -pub use vk_buffer::VkBuffer; - -pub use vertex::Vertex; diff --git a/src/renderer/vulkan/utils/layers.rs b/src/renderer/vulkan/utils/layers.rs deleted file mode 100644 index 9d901fb..0000000 --- a/src/renderer/vulkan/utils/layers.rs +++ /dev/null @@ -1,51 +0,0 @@ -use std::ffi::CString; - -pub enum LayersSelector<'a> { - Nothing, - SpecificLayers(Vec<&'a str>), - All, -} - -pub fn use_layers(entry: &ash::Entry, selector: LayersSelector) -> Vec { - let layers_available = get_layers_available(entry) - .iter() - .filter_map(|layer| { - layer - .layer_name_as_c_str() - .and_then(|layer_name| Ok(CString::from(layer_name))) - .ok() - }) - .collect::>(); - - match selector { - LayersSelector::Nothing => Vec::new(), - LayersSelector::SpecificLayers(layers) => select_layers(&layers_available, &layers), - LayersSelector::All => layers_available, - } -} - -fn get_layers_available(entry: &ash::Entry) -> Vec { - unsafe { - entry - .enumerate_instance_layer_properties() - .unwrap_or_default() - } -} - -fn select_layers(layers_available: &Vec, layers_to_select: &[&str]) -> Vec { - layers_to_select - .iter() - .filter_map(|layer_name| { - if layers_available.iter().any(|layer_available| { - layer_available - .to_str() - .and_then(|layer_available| Ok(layer_available.eq(*layer_name))) - .unwrap_or(false) - }) { - CString::new(*layer_name).ok() - } else { - None - } - }) - .collect::>() -} diff --git a/src/renderer/vulkan/utils/mod.rs b/src/renderer/vulkan/utils/mod.rs deleted file mode 100644 index 759c25e..0000000 --- a/src/renderer/vulkan/utils/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod layers; diff --git a/src/renderer/vulkan/vertex.rs b/src/renderer/vulkan/vertex.rs deleted file mode 100644 index 5d97213..0000000 --- a/src/renderer/vulkan/vertex.rs +++ /dev/null @@ -1,37 +0,0 @@ -use ash::vk; -use std::mem::offset_of; - -#[derive(Default)] -pub struct Vertex { - pub position: [f32; 2], - pub color: [f32; 3], -} - -impl Vertex { - pub fn new(position: [f32; 2], color: [f32; 3]) -> Self { - Self { position, color } - } - - pub fn get_binding_description() -> vk::VertexInputBindingDescription { - vk::VertexInputBindingDescription::default() - .binding(0) - .stride(size_of::() as u32) - .input_rate(vk::VertexInputRate::VERTEX) - } - - pub fn get_attribute_descriptions() -> [vk::VertexInputAttributeDescription; 2] { - let position_attribute = vk::VertexInputAttributeDescription::default() - .binding(0) - .location(0) - .format(vk::Format::R32G32_SFLOAT) - .offset(offset_of!(Vertex, position) as u32); - - let color_attribute = vk::VertexInputAttributeDescription::default() - .binding(0) - .location(1) - .format(vk::Format::R32G32B32_SFLOAT) - .offset(offset_of!(Vertex, color) as u32); - - [position_attribute, color_attribute] - } -} \ No newline at end of file diff --git a/src/renderer/vulkan/vk_buffer.rs b/src/renderer/vulkan/vk_buffer.rs deleted file mode 100644 index b03dea4..0000000 --- a/src/renderer/vulkan/vk_buffer.rs +++ /dev/null @@ -1,31 +0,0 @@ -use std::sync::Arc; -use ash::prelude::VkResult; -use ash::vk; -use crate::renderer::vulkan::VkDevice; - -pub struct VkBuffer { - device: Arc, - - handle: vk::Buffer, -} - -impl VkBuffer { - pub fn new(device: &Arc, info: &vk::BufferCreateInfo) -> VkResult { - let buffer = unsafe { device.handle.create_buffer(info, None)? }; - - Ok(VkBuffer { device: Arc::clone(device), handle: buffer }) - } - - - pub fn mem_requirements(&self) -> vk::MemoryRequirements { - unsafe { self.device.handle.get_buffer_memory_requirements(self.handle) } - } -} - -impl Drop for VkBuffer { - fn drop(&mut self) { - unsafe { - self.device.handle.destroy_buffer(self.handle, None); - } - } -} \ No newline at end of file diff --git a/src/renderer/vulkan/vk_command_pool.rs b/src/renderer/vulkan/vk_command_pool.rs deleted file mode 100644 index c657e97..0000000 --- a/src/renderer/vulkan/vk_command_pool.rs +++ /dev/null @@ -1,52 +0,0 @@ -use super::VkDevice; -use ash::prelude::VkResult; -use ash::vk; -use std::sync::Arc; - -pub struct VkCommandPool { - device: Arc, - - pub handle: vk::CommandPool, -} - -impl VkCommandPool { - pub fn new(device: &Arc) -> VkResult { - let command_pool_info = - vk::CommandPoolCreateInfo::default() - .flags(vk::CommandPoolCreateFlags::RESET_COMMAND_BUFFER) - .queue_family_index(device.queue_family_index); - let command_pool = unsafe { - device - .handle - .create_command_pool(&command_pool_info, None)? - }; - log::debug!("Command pool created ({command_pool:?})"); - - Ok(Self { - device: device.clone(), - handle: command_pool, - }) - } - - pub fn allocate_command_buffers_for_framebuffers(&self, framebuffers_count: u32) -> VkResult> { - let command_buffer_info = vk::CommandBufferAllocateInfo::default() - .command_pool(self.handle) - .level(vk::CommandBufferLevel::PRIMARY) - .command_buffer_count(framebuffers_count); - - let command_buffers = unsafe { - self.device - .handle - .allocate_command_buffers(&command_buffer_info)? - }; - - Ok(command_buffers) - } -} - -impl Drop for VkCommandPool { - fn drop(&mut self) { - unsafe { self.device.handle.destroy_command_pool(self.handle, None) }; - log::debug!("Command pool destroyed ({:?})", self.handle); - } -} diff --git a/src/renderer/vulkan/vk_device.rs b/src/renderer/vulkan/vk_device.rs deleted file mode 100644 index 9f14630..0000000 --- a/src/renderer/vulkan/vk_device.rs +++ /dev/null @@ -1,109 +0,0 @@ -use super::{VkInstance, VkPhysicalDevice}; -use ash::prelude::VkResult; -use ash::vk; -use std::sync::Arc; - -pub struct VkDevice { - instance: Arc, - physical_device: Arc, - - pub handle: ash::Device, - pub swapchain_loader: ash::khr::swapchain::Device, - pub queue_family_index: u32, - - // Arc not used because vk::Queue is destroyed with Device automatically - // so any references of vk::Queue must be destroyed with VkDevice - queues: Vec, -} - -impl VkDevice { - pub fn new_graphics_device( - instance: &Arc, - physical_device: &Arc, - queue_family_index: u32, - ) -> anyhow::Result { - let device_extension_names_raw = [ - ash::khr::swapchain::NAME.as_ptr(), - #[cfg(any(target_os = "macos", target_os = "ios"))] - ash::khr::portability_subset::NAME.as_ptr(), - ]; - let features = vk::PhysicalDeviceFeatures { - shader_clip_distance: 1, - ..Default::default() - }; - - let queues_priorities = [1.0]; - let queue_info = vk::DeviceQueueCreateInfo::default() - .queue_family_index(queue_family_index) - .queue_priorities(&queues_priorities); - - let device_create_info = vk::DeviceCreateInfo::default() - .queue_create_infos(std::slice::from_ref(&queue_info)) - .enabled_extension_names(&device_extension_names_raw) - .enabled_features(&features); - - let device = unsafe { - instance - .handle - .create_device(physical_device.handle, &device_create_info, None)? - }; - log::debug!("Device created ({:?})", device.handle()); - - let queues = queues_priorities - .iter() - .enumerate() - .map(|(index, _)| unsafe { device.get_device_queue(queue_family_index, index as u32) }) - .collect::>(); - - let swapchain_loader = ash::khr::swapchain::Device::new(&instance.handle, &device); - - Ok(Self { - instance: Arc::clone(instance), - physical_device: Arc::clone(&physical_device), - handle: device, - swapchain_loader, - queue_family_index, - queues, - }) - } - - pub fn get_device_queue(&self, queue_index: u32) -> Option<&vk::Queue> { - self.queues.get(queue_index as usize) - } - - pub fn create_command_pool( - &self, - info: &vk::CommandPoolCreateInfo, - ) -> VkResult { - let info = info.queue_family_index(self.queue_family_index); - - unsafe { self.handle.create_command_pool(&info, None) } - } - - pub fn allocate_command_buffers( - &self, - info: &vk::CommandBufferAllocateInfo, - ) -> VkResult> { - unsafe { self.handle.allocate_command_buffers(&info) } - } - - pub fn create_fence(&self, info: &vk::FenceCreateInfo) -> VkResult { - unsafe { self.handle.create_fence(&info, None) } - } - - pub fn create_semaphore( - &self, - info: &vk::SemaphoreCreateInfo, - ) -> VkResult { - unsafe { self.handle.create_semaphore(&info, None) } - } -} - -impl Drop for VkDevice { - fn drop(&mut self) { - unsafe { - self.handle.destroy_device(None); - log::debug!("Device destroyed ({:?})", self.handle.handle()); - } - } -} diff --git a/src/renderer/vulkan/vk_fence.rs b/src/renderer/vulkan/vk_fence.rs deleted file mode 100644 index 9fb71ff..0000000 --- a/src/renderer/vulkan/vk_fence.rs +++ /dev/null @@ -1,30 +0,0 @@ -use super::VkDevice; -use ash::vk; -use std::sync::Arc; - -pub struct VkFence { - device: Arc, - - pub handle: vk::Fence, -} - -impl VkFence { - pub fn new(device: &Arc) -> anyhow::Result { - let fence_info = vk::FenceCreateInfo::default() - .flags(vk::FenceCreateFlags::SIGNALED); - let fence = unsafe { device.handle.create_fence(&fence_info, None)? }; - log::debug!("Fence created ({fence:?})"); - - Ok(Self { - device: device.clone(), - handle: fence, - }) - } -} - -impl Drop for VkFence { - fn drop(&mut self) { - unsafe { self.device.handle.destroy_fence(self.handle, None) }; - log::debug!("Fence destroyed ({:?})", self.handle); - } -} \ No newline at end of file diff --git a/src/renderer/vulkan/vk_framebuffer.rs b/src/renderer/vulkan/vk_framebuffer.rs deleted file mode 100644 index 8486fb5..0000000 --- a/src/renderer/vulkan/vk_framebuffer.rs +++ /dev/null @@ -1,44 +0,0 @@ -use super::{VkDevice, VkRenderPass, VkSwapchain}; -use ash::vk; -use std::sync::Arc; - -pub struct VkFramebuffer { - device: Arc, - image_view: Arc, - render_pass: Arc, - - pub handle: vk::Framebuffer, -} - -impl VkFramebuffer { - pub fn from_swapchain_image_view( - device: &Arc, - render_pass: &Arc, - image_view: &Arc, - swapchain: &VkSwapchain, - ) -> anyhow::Result { - let attachments = [*image_view.as_ref()]; - let framebuffer_info = vk::FramebufferCreateInfo::default() - .render_pass(render_pass.handle) - .width(swapchain.surface_resolution.width) - .height(swapchain.surface_resolution.height) - .attachments(&attachments) - .layers(1); - - let framebuffer = unsafe { device.handle.create_framebuffer(&framebuffer_info, None)? }; - - Ok(Self { - device: device.clone(), - render_pass: render_pass.clone(), - image_view: image_view.clone(), - - handle: framebuffer, - }) - } -} - -impl Drop for VkFramebuffer { - fn drop(&mut self) { - unsafe { self.device.handle.destroy_framebuffer(self.handle, None) }; - } -} diff --git a/src/renderer/vulkan/vk_graphics_pipeline.rs b/src/renderer/vulkan/vk_graphics_pipeline.rs deleted file mode 100644 index a9af298..0000000 --- a/src/renderer/vulkan/vk_graphics_pipeline.rs +++ /dev/null @@ -1,120 +0,0 @@ -use super::{VkDevice, VkRenderPass, VkShaderModule, VkSwapchain}; -use ash::vk; -use std::ffi::CStr; -use std::sync::Arc; - -pub struct VkGraphicsPipeline { - device: Arc, - render_pass: Arc, - - pub pipeline_layout: vk::PipelineLayout, - pub pipeline: vk::Pipeline, - vertex_shader: VkShaderModule, - fragment_shader: VkShaderModule, -} - -impl VkGraphicsPipeline { - pub fn new( - device: &Arc, - render_pass: &Arc, - ) -> anyhow::Result { - let shader_entry_name = CStr::from_bytes_with_nul(b"main\0")?; - - let vert_shader_module = - VkShaderModule::from_spv_file(device, "res/shaders/main.vert.spv")?; - - let vert_shader_info = vk::PipelineShaderStageCreateInfo::default() - .module(vert_shader_module.handle) - .name(shader_entry_name) - .stage(vk::ShaderStageFlags::VERTEX); - - let frag_shader_module = - VkShaderModule::from_spv_file(device, "res/shaders/main.frag.spv")?; - - let frag_shader_info = vk::PipelineShaderStageCreateInfo::default() - .module(frag_shader_module.handle) - .name(shader_entry_name) - .stage(vk::ShaderStageFlags::FRAGMENT); - - let shader_stage_create_infos = [vert_shader_info, frag_shader_info]; - - let vertex_input_info = vk::PipelineVertexInputStateCreateInfo::default(); - - let input_assembly = vk::PipelineInputAssemblyStateCreateInfo::default() - .topology(vk::PrimitiveTopology::TRIANGLE_LIST); - - let viewport_state = vk::PipelineViewportStateCreateInfo::default() - .viewport_count(1) - .scissor_count(1); - - let rasterizer = vk::PipelineRasterizationStateCreateInfo::default() - .polygon_mode(vk::PolygonMode::FILL) - .cull_mode(vk::CullModeFlags::BACK) - .front_face(vk::FrontFace::CLOCKWISE) - .line_width(1.0); - - let multisampling = vk::PipelineMultisampleStateCreateInfo::default() - .rasterization_samples(vk::SampleCountFlags::TYPE_1) - .min_sample_shading(1.0); - - let color_blend_attachment = vk::PipelineColorBlendAttachmentState::default() - .color_write_mask(vk::ColorComponentFlags::RGBA); - - let attachments = [color_blend_attachment]; - let color_blending = - vk::PipelineColorBlendStateCreateInfo::default().attachments(&attachments); - - let dynamic_state = vk::PipelineDynamicStateCreateInfo::default() - .dynamic_states(&[vk::DynamicState::VIEWPORT, vk::DynamicState::SCISSOR]); - - let pipeline_layout_info = vk::PipelineLayoutCreateInfo::default(); - let pipeline_layout = unsafe { - device - .handle - .create_pipeline_layout(&pipeline_layout_info, None)? - }; - log::debug!("Pipeline layout created ({pipeline_layout:?})"); - - let pipeline_info = vk::GraphicsPipelineCreateInfo::default() - .stages(&shader_stage_create_infos) - .vertex_input_state(&vertex_input_info) - .input_assembly_state(&input_assembly) - .viewport_state(&viewport_state) - .rasterization_state(&rasterizer) - .multisample_state(&multisampling) - .color_blend_state(&color_blending) - .dynamic_state(&dynamic_state) - .layout(pipeline_layout) - .render_pass(render_pass.handle); - let pipeline = unsafe { - device - .handle - .create_graphics_pipelines(vk::PipelineCache::null(), &[pipeline_info], None) - .map_err(|(_, error)| error)?[0] - }; - log::debug!("Pipeline created ({pipeline_layout:?})"); - - Ok(Self { - device: device.clone(), - render_pass: render_pass.clone(), - pipeline_layout, - pipeline, - vertex_shader: vert_shader_module, - fragment_shader: frag_shader_module, - }) - } -} - -impl Drop for VkGraphicsPipeline { - fn drop(&mut self) { - unsafe { - self.device.handle.destroy_pipeline(self.pipeline, None); - log::debug!("Pipeline destroyed ({:?})", self.pipeline); - - self.device - .handle - .destroy_pipeline_layout(self.pipeline_layout, None); - log::debug!("Pipeline layout destroyed ({:?})", self.pipeline_layout); - } - } -} diff --git a/src/renderer/vulkan/vk_instance.rs b/src/renderer/vulkan/vk_instance.rs deleted file mode 100644 index 101dec2..0000000 --- a/src/renderer/vulkan/vk_instance.rs +++ /dev/null @@ -1,128 +0,0 @@ -use crate::renderer::vulkan::{ - utils::layers::{use_layers, LayersSelector}, - VkPhysicalDevice, -}; -use ash::khr::surface; -use ash::{vk, Entry, Instance}; -use std::ffi::{c_char, CStr, CString}; -use std::sync::Arc; - -pub struct VkInstance { - pub entry: Entry, - pub handle: Instance, - pub surface_loader: surface::Instance, -} - -impl VkInstance { - pub fn new(required_extensions: &Vec<*const c_char>) -> Self { - let entry = Entry::linked(); - - log::debug!("Initializing Vulkan instance"); - - if log::log_enabled!(log::Level::Debug) { - let layer_properties = - unsafe { entry.enumerate_instance_layer_properties() }.unwrap_or_default(); - - for layer_property in layer_properties { - let layer_extensions = unsafe { - entry.enumerate_instance_extension_properties( - layer_property.layer_name_as_c_str().ok(), - ) - } - .unwrap_or_default(); - log::debug!("{layer_property:#?} {layer_extensions:#?}"); - } - } - - { - let required_extensions = required_extensions - .iter() - .map(|str| unsafe { CStr::from_ptr(*str) }) - .map(|cstr| cstr.to_string_lossy()) - .collect::>(); - log::debug!( - "Required instance extensions: {}", - required_extensions.join(", ") - ); - } - - // Layers - #[allow(unused)] - let mut layer_selector = LayersSelector::Nothing; - #[cfg(debug_assertions)] - { - layer_selector = LayersSelector::SpecificLayers(vec![ - "VK_LAYER_KHRONOS_validation", - "VK_LAYER_MANGOHUD_overlay_x86_64", - "VK_LAYER_NV_optimus", - ]); - } - let layers = use_layers(&entry, layer_selector); - - { - let layers = layers - .iter() - .map(|layer| layer.to_string_lossy()) - .collect::>(); - log::debug!("Selected debug layers : {}", layers.join(", ")) - } - - let layers_raw = layers.iter().map(|s| s.as_ptr()).collect::>(); - - // App Info - let app_name = CString::new("VulkanTriangle").unwrap(); - let appinfo = vk::ApplicationInfo::default() - .application_name(app_name.as_c_str()) - .application_version(0) - .engine_name(app_name.as_c_str()) - .engine_version(0) - .api_version(vk::make_api_version(0, 1, 0, 0)); - - let create_flags = if cfg!(any(target_os = "macos", target_os = "ios")) { - vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR - } else { - vk::InstanceCreateFlags::default() - }; - - // Instance Info - let create_info = vk::InstanceCreateInfo::default() - .application_info(&appinfo) - .enabled_layer_names(&layers_raw) - .enabled_extension_names(&required_extensions) - .flags(create_flags); - - let instance: Instance = unsafe { - entry - .create_instance(&create_info, None) - .expect("Instance creation error") - }; - - let surface_loader = surface::Instance::new(&entry, &instance); - - log::debug!("Vulkan instance created ({:?})", instance.handle()); - - Self { - entry, - handle: instance, - surface_loader, - } - } - - pub fn get_physical_devices(instance: &Arc) -> Vec { - let physical_devices = unsafe { instance.handle.enumerate_physical_devices() }; - physical_devices - .unwrap_or_default() - .iter() - .map(|physical_device| VkPhysicalDevice::new(&instance, *physical_device)) - .collect() - } -} - -impl Drop for VkInstance { - fn drop(&mut self) { - unsafe { - self.handle.destroy_instance(None); - } - log::debug!("Vulkan instance destroyed ({:?})", self.handle.handle()); - } -} diff --git a/src/renderer/vulkan/vk_physical_device.rs b/src/renderer/vulkan/vk_physical_device.rs deleted file mode 100644 index 3534f24..0000000 --- a/src/renderer/vulkan/vk_physical_device.rs +++ /dev/null @@ -1,85 +0,0 @@ -use std::sync::Arc; -use super::{VkInstance, VkSurface}; -use ash::vk; - -pub struct VkPhysicalDevice { - instance: Arc, - pub handle: vk::PhysicalDevice, - - pub properties: vk::PhysicalDeviceProperties, - pub features: vk::PhysicalDeviceFeatures, - pub queue_family_properties: Vec, -} - -impl VkPhysicalDevice { - pub fn new(instance: &Arc, physical_device: vk::PhysicalDevice) -> Self { - log::debug!("New physical device"); - let device_properties = unsafe { instance.handle.get_physical_device_properties(physical_device) }; - log::debug!("{device_properties:#?}"); - let device_features = unsafe { instance.handle.get_physical_device_features(physical_device) }; - log::debug!("{device_features:#?}"); - let device_queue_families = - unsafe { instance.handle.get_physical_device_queue_family_properties(physical_device) }; - log::debug!("{device_queue_families:#?}"); - - Self { - instance: Arc::clone(instance), - handle: physical_device, - properties: device_properties, - features: device_features, - queue_family_properties: device_queue_families, - } - } - - pub fn find_queue_family_by( - &self, - queue_flags: Option, - surface: Option<&VkSurface>, - ) -> Option<(u32, &vk::QueueFamilyProperties)> { - self.queue_family_properties.iter().enumerate().find_map( - |(index, queue_family_property)| { - let surface_check_passed = match surface { - Some(surface) => surface - .physical_device_queue_supported(self, index as u32) - .unwrap_or(false), - None => true, - }; - - let queue_flags_check_passed = match queue_flags { - Some(queue_flags) => queue_family_property.queue_flags.contains(queue_flags), - None => true, - }; - - if surface_check_passed && queue_flags_check_passed { - Some((index as u32, queue_family_property)) - } else { - None - } - }, - ) - } - - pub fn pick_physical_device_and_queue_by<'a>( - physical_devices: &'a Vec, - queue_flags: Option, - surface: Option<&VkSurface>, - ) -> Option<(&'a VkPhysicalDevice, u32, &'a vk::QueueFamilyProperties)> { - physical_devices.iter().find_map(|physical_device| { - physical_device - .find_queue_family_by(queue_flags, surface) - .and_then(|(queue_index, queue_family_properties)| { - Some((physical_device, queue_index, queue_family_properties)) - }) - }) - } - - pub fn priority(&self) -> usize { - match self.properties.device_type { - vk::PhysicalDeviceType::CPU => 1, - vk::PhysicalDeviceType::VIRTUAL_GPU => 2, - vk::PhysicalDeviceType::INTEGRATED_GPU => 3, - vk::PhysicalDeviceType::DISCRETE_GPU => 4, - _ => 0, - } - } -} diff --git a/src/renderer/vulkan/vk_render_context.rs b/src/renderer/vulkan/vk_render_context.rs deleted file mode 100644 index 68dd304..0000000 --- a/src/renderer/vulkan/vk_render_context.rs +++ /dev/null @@ -1,206 +0,0 @@ -use super::{ - VkCommandPool, VkDevice, VkFence, VkFramebuffer, VkGraphicsPipeline, VkInstance, VkPhysicalDevice, - VkRenderPass, VkSemaphore, VkSurface, VkSwapchain, -}; -use ash::vk; -use std::sync::Arc; -use crate::renderer::Renderable; - -pub struct VkRenderContext { - instance: Arc, - surface: Arc, - device: Arc, - - swapchain: Arc, - render_pass: Arc, - framebuffers: Vec>, - - command_pool: VkCommandPool, - command_buffers: Vec, - image_available_semaphore: VkSemaphore, - render_finished_semaphore: VkSemaphore, - in_flight_fence: VkFence, -} - -impl VkRenderContext { - pub fn init(window: &crate::display::Window) -> anyhow::Result { - let required_extensions = window.required_extensions()?; - - let instance = Arc::new(VkInstance::new(&required_extensions)); - let surface = Arc::new(VkSurface::new(&window, instance.clone())?); - - let mut physical_devices = VkInstance::get_physical_devices(&instance); - physical_devices.sort_by(|a, b| b.priority().cmp(&a.priority())); - - let (physical_device, queue_family_index, properties) = - VkPhysicalDevice::pick_physical_device_and_queue_by( - &physical_devices, - Some(vk::QueueFlags::GRAPHICS), - Some(&surface), - ) - .ok_or_else(|| anyhow::anyhow!("Unable to find physical device"))?; - log::debug!( - "Selected queue {properties:#?} for physical device {:?}", - physical_device.properties.device_name_as_c_str() - ); - - let device = Arc::new(VkDevice::new_graphics_device( - &instance, - &physical_device, - queue_family_index, - )?); - - let swapchain = Arc::new(VkSwapchain::new( - &window, - &surface, - &device, - &physical_device, - )?); - - let render_pass = Arc::new(VkRenderPass::new(&device, &swapchain)?); - - let framebuffers = swapchain - .create_framebuffers(&render_pass) - .ok_or_else(|| anyhow::anyhow!("Failed to get framebuffers"))?; - - let command_pool = VkCommandPool::new(&device)?; - - // Destroyed with command pool - let command_buffers = command_pool - .allocate_command_buffers_for_framebuffers(framebuffers.len() as u32)?; - - let image_available_semaphore = VkSemaphore::new(&device)?; - let render_finished_semaphore = VkSemaphore::new(&device)?; - let in_flight_fence = VkFence::new(&device)?; - - Ok(Self { - instance, - surface, - device, - - swapchain, - render_pass, - framebuffers, - - command_pool, - command_buffers, - - image_available_semaphore, - render_finished_semaphore, - in_flight_fence, - }) - } - - pub fn render(&mut self, scene: Option<&Box>) -> anyhow::Result<()> { - unsafe { self.device.handle.wait_for_fences(&[self.in_flight_fence.handle], true, u64::MAX)? }; - unsafe { self.device.handle.reset_fences(&[self.in_flight_fence.handle])? }; - - let (index, _) = self - .swapchain - .acquire_next_image(&self.image_available_semaphore)?; - - // if self.swapchain.is_dirty() { - // self.update_swapchain()? - // } - - let command_buffer = self.command_buffers[index as usize]; - unsafe { self.device.handle.reset_command_buffer(command_buffer, vk::CommandBufferResetFlags::default())? }; - - let render_area = vk::Rect2D::default().extent(self.swapchain.surface_resolution); - let clear_value = vk::ClearValue::default(); - let command_buffer_begin_info = vk::CommandBufferBeginInfo::default(); - unsafe { - self.device - .handle - .begin_command_buffer(command_buffer, &command_buffer_begin_info)? - }; - - let clear_values = [clear_value]; - let framebuffer = self.framebuffers[index as usize].as_ref(); - let render_pass_begin_info = vk::RenderPassBeginInfo::default() - .render_pass(self.render_pass.handle) - .framebuffer(framebuffer.handle) - .render_area(render_area) - .clear_values(&clear_values); - - unsafe { - self.device.handle.cmd_begin_render_pass( - command_buffer, - &render_pass_begin_info, - vk::SubpassContents::INLINE, - ); - }; - - if let Some(scene) = scene { - scene.render(&self.device, &self.swapchain, &command_buffer)?; - } - - unsafe { self.device.handle.cmd_end_render_pass(command_buffer) }; - - unsafe { self.device.handle.end_command_buffer(command_buffer)? }; - - let wait_semaphores = [self.image_available_semaphore.handle]; - let signal_semaphores = [self.render_finished_semaphore.handle]; - let wait_stages = [vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT]; - let command_buffers_to_submit = [command_buffer]; - let submit_info = vk::SubmitInfo::default() - .wait_semaphores(&wait_semaphores) - .wait_dst_stage_mask(&wait_stages) - .command_buffers(&command_buffers_to_submit) - .signal_semaphores(&signal_semaphores); - - let queue = self - .device - .get_device_queue(0) - .ok_or_else(|| anyhow::anyhow!("Failed to get a queue"))?; - - unsafe { - self.device - .handle - .queue_submit(*queue, &[submit_info], self.in_flight_fence.handle)? - }; - - let swapchains = [self.swapchain.handle.unwrap()]; - let indices = [index]; - let present_info = vk::PresentInfoKHR::default() - .wait_semaphores(&signal_semaphores) - .swapchains(&swapchains) - .image_indices(&indices); - - unsafe { self.device.swapchain_loader.queue_present(*queue, &present_info)? }; - - Ok(()) - } - - pub fn update_resolution(&mut self, width: u32, height: u32) -> anyhow::Result<()> { - match Arc::get_mut(&mut self.swapchain) { - Some(swapchain) => swapchain.update_resolution(width, height)?, - None => log::warn!("Impossible to get mutable swapchain"), - } - - Ok(()) - } - - pub fn exit(&self) { - unsafe { self.device.handle.device_wait_idle().unwrap() } - } - - pub fn init_scene(&self, scene: &mut Box) -> anyhow::Result<()> { - scene.init(&self.device, &self.render_pass) - } - - fn update_swapchain(&mut self) -> anyhow::Result<()> { - match Arc::get_mut(&mut self.swapchain) { - Some(swapchain) => { - swapchain.create_swapchain()?; - - self.framebuffers = self.swapchain - .create_framebuffers(&self.render_pass) - .ok_or_else(|| anyhow::anyhow!("Failed to get framebuffers"))?; - } - None => log::warn!("Impossible to get mutable swapchain"), - } - - Ok(()) - } -} diff --git a/src/renderer/vulkan/vk_render_pass.rs b/src/renderer/vulkan/vk_render_pass.rs deleted file mode 100644 index e9819fe..0000000 --- a/src/renderer/vulkan/vk_render_pass.rs +++ /dev/null @@ -1,56 +0,0 @@ -use super::{VkDevice, VkSwapchain}; -use ash::prelude::VkResult; -use ash::vk; -use std::sync::Arc; - -pub struct VkRenderPass { - device: Arc, - - pub handle: vk::RenderPass, -} - -impl VkRenderPass { - pub fn new(device: &Arc, swapchain: &Arc) -> VkResult { - let color_attachment = vk::AttachmentDescription::default() - .format(swapchain.surface_format.format) - .samples(vk::SampleCountFlags::TYPE_1) - .load_op(vk::AttachmentLoadOp::CLEAR) - .store_op(vk::AttachmentStoreOp::STORE) - .stencil_load_op(vk::AttachmentLoadOp::DONT_CARE) - .stencil_store_op(vk::AttachmentStoreOp::DONT_CARE) - .initial_layout(vk::ImageLayout::UNDEFINED) - .final_layout(vk::ImageLayout::PRESENT_SRC_KHR); - - let color_attachment_ref = vk::AttachmentReference::default() - .attachment(0) - .layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL); - - let color_attachments = [color_attachment_ref]; - let subpass = vk::SubpassDescription::default() - .pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS) - .color_attachments(&color_attachments); - - let attachments = [color_attachment]; - let subpasses = [subpass]; - let render_pass_info = vk::RenderPassCreateInfo::default() - .attachments(&attachments) - .subpasses(&subpasses); - - let render_pass = unsafe { device.handle.create_render_pass(&render_pass_info, None)? }; - log::debug!("Render pass created ({render_pass:?})"); - - Ok(Self { - device: device.clone(), - handle: render_pass, - }) - } -} - -impl Drop for VkRenderPass { - fn drop(&mut self) { - unsafe { - self.device.handle.destroy_render_pass(self.handle, None); - log::debug!("Render pass destroyed ({:?})", self.handle); - } - } -} diff --git a/src/renderer/vulkan/vk_semaphore.rs b/src/renderer/vulkan/vk_semaphore.rs deleted file mode 100644 index facaf4e..0000000 --- a/src/renderer/vulkan/vk_semaphore.rs +++ /dev/null @@ -1,29 +0,0 @@ -use super::VkDevice; -use ash::vk; -use std::sync::Arc; - -pub struct VkSemaphore { - device: Arc, - - pub handle: vk::Semaphore, -} - -impl VkSemaphore { - pub fn new(device: &Arc) -> anyhow::Result { - let semaphore_info = vk::SemaphoreCreateInfo::default(); - let semaphore = unsafe { device.handle.create_semaphore(&semaphore_info, None)? }; - log::debug!("Semaphore created ({semaphore:?})"); - - Ok(Self { - device: device.clone(), - handle: semaphore, - }) - } -} - -impl Drop for VkSemaphore { - fn drop(&mut self) { - unsafe { self.device.handle.destroy_semaphore(self.handle, None) }; - log::debug!("Semaphore destroyed ({:?})", self.handle); - } -} \ No newline at end of file diff --git a/src/renderer/vulkan/vk_shader_module.rs b/src/renderer/vulkan/vk_shader_module.rs deleted file mode 100644 index 96ddcc5..0000000 --- a/src/renderer/vulkan/vk_shader_module.rs +++ /dev/null @@ -1,42 +0,0 @@ -use super::VkDevice; -use ash::vk; -use std::path::Path; -use std::sync::Arc; - -pub struct VkShaderModule { - device: Arc, - - pub handle: vk::ShaderModule, -} - -impl VkShaderModule { - pub fn from_spv_file>(device: &Arc, path: P) -> anyhow::Result { - let mut file = std::fs::File::open(&path)?; - let frag_shader_str = ash::util::read_spv(&mut file)?; - - let shader_create_info = vk::ShaderModuleCreateInfo::default().code(&frag_shader_str); - let shader_module = unsafe { - device - .handle - .create_shader_module(&shader_create_info, None)? - }; - log::debug!( - "Shader module created ({shader_module:?}) from {:?}", - path.as_ref() - ); - - Ok(Self { - device: device.clone(), - handle: shader_module, - }) - } -} - -impl Drop for VkShaderModule { - fn drop(&mut self) { - unsafe { - self.device.handle.destroy_shader_module(self.handle, None); - log::debug!("Shader module destroyed ({:?})", self.handle); - } - } -} diff --git a/src/renderer/vulkan/vk_surface.rs b/src/renderer/vulkan/vk_surface.rs deleted file mode 100644 index 9aace7c..0000000 --- a/src/renderer/vulkan/vk_surface.rs +++ /dev/null @@ -1,94 +0,0 @@ -use super::{VkInstance, VkPhysicalDevice}; -use ash::prelude::VkResult; -use ash::vk; -use std::sync::Arc; -use winit::raw_window_handle::{HasDisplayHandle, HasWindowHandle}; - -pub struct SwapchainSupportDetails( - pub Vec, - pub vk::SurfaceCapabilitiesKHR, - pub Vec, -); - -pub struct VkSurface { - instance: Arc, - - pub handle: vk::SurfaceKHR, -} - -impl VkSurface { - pub fn new(window: &crate::display::Window, instance: Arc) -> anyhow::Result { - let window_handle = window - .handle() - .ok_or_else(|| anyhow::anyhow!("Window handle is not available."))?; - - let surface = unsafe { - ash_window::create_surface( - &instance.entry, - &instance.handle, - window_handle.display_handle()?.as_raw(), - window_handle.window_handle()?.as_raw(), - None, - )? - }; - - log::debug!("Surface created ({:?})", surface); - - Ok(Self { instance, handle: surface }) - } - - pub fn physical_device_queue_supported( - &self, - physical_device: &VkPhysicalDevice, - queue_index: u32, - ) -> VkResult { - unsafe { - self.instance - .surface_loader - .get_physical_device_surface_support( - physical_device.handle, - queue_index, - self.handle, - ) - } - } - - pub fn get_physical_device_swapchain_support_details( - &self, - physical_device: &VkPhysicalDevice, - ) -> VkResult { - unsafe { - let formats = self - .instance - .surface_loader - .get_physical_device_surface_formats(physical_device.handle, self.handle)?; - - let capabilities = self - .instance - .surface_loader - .get_physical_device_surface_capabilities(physical_device.handle, self.handle)?; - - let present_modes = self - .instance - .surface_loader - .get_physical_device_surface_present_modes(physical_device.handle, self.handle)?; - - Ok(SwapchainSupportDetails( - formats, - capabilities, - present_modes, - )) - } - } -} - -impl Drop for VkSurface { - fn drop(&mut self) { - unsafe { - self.instance - .surface_loader - .destroy_surface(self.handle, None); - } - log::debug!("Surface destroyed ({:?})", self.handle); - } -} diff --git a/src/renderer/vulkan/vk_swapchain.rs b/src/renderer/vulkan/vk_swapchain.rs deleted file mode 100644 index 758574a..0000000 --- a/src/renderer/vulkan/vk_swapchain.rs +++ /dev/null @@ -1,297 +0,0 @@ -use super::{SwapchainSupportDetails, VkDevice, VkFramebuffer, VkPhysicalDevice, VkRenderPass, VkSemaphore, VkSurface}; -use crate::display::Window; -use ash::prelude::VkResult; -use ash::vk; -use std::sync::Arc; - -pub struct VkSwapchain { - surface: Arc, - device: Arc, - - pub handle: Option, - swapchain_support_details: SwapchainSupportDetails, - - pub desired_image_count: u32, - pub surface_format: vk::SurfaceFormatKHR, - pub surface_resolution: vk::Extent2D, - pub new_requested_surface_resolution: Option, - pub present_mode: vk::PresentModeKHR, - pub pre_transform: vk::SurfaceTransformFlagsKHR, - - pub present_images: Option>, - pub present_image_views: Option>>, -} - -impl VkSwapchain { - pub fn new( - window: &Window, - surface: &Arc, - device: &Arc, - physical_device: &VkPhysicalDevice, - ) -> anyhow::Result { - log::debug!("Creating swapchain"); - - let window_size = window - .physical_size::() - .and_then(|size| { - Some(vk::Extent2D { - width: size.width, - height: size.height, - }) - }) - .ok_or_else(|| anyhow::anyhow!("Failed to get swapchain extent"))?; - log::debug!("Window size ({}x{})", window_size.width, window_size.height); - - let swapchain_support_details = - surface.get_physical_device_swapchain_support_details(physical_device)?; - let SwapchainSupportDetails(surface_formats, surface_capabilities, present_modes) = - &swapchain_support_details; - log::debug!("Supported surface formats by physical device: {surface_formats:#?}"); - log::debug!("Surface capabilities: {surface_capabilities:#?}"); - log::debug!("Present modes: {present_modes:#?}"); - - let surface_format = Self::choose_surface_format(surface_formats) - .ok_or_else(|| anyhow::anyhow!("No available surface formats"))?; - let desired_image_count = Self::choose_desired_image_count(surface_capabilities); - let swapchain_extent = Self::choose_swapchain_extent(window_size, surface_capabilities); - let pre_transform = Self::choose_pre_transform(surface_capabilities); - let present_mode = Self::choose_present_mode(present_modes); - - let mut swapchain = Self { - surface: surface.clone(), - device: device.clone(), - - handle: None, - new_requested_surface_resolution: None, - swapchain_support_details, - desired_image_count, - surface_format, - surface_resolution: swapchain_extent, - present_mode, - pre_transform, - present_images: None, - present_image_views: None, - }; - - swapchain.create_swapchain()?; - - Ok(swapchain) - } - - pub fn create_swapchain(&mut self) -> VkResult<()> { - if let Some(new_requested_surface_resolution) = self.new_requested_surface_resolution { - self.surface_resolution = new_requested_surface_resolution; - self.new_requested_surface_resolution = None; - } - - let mut swapchain_create_info = self.create_swapchain_info(&self.surface); - - if let Some(old_swapchain) = self.handle { - swapchain_create_info.old_swapchain = old_swapchain; - } - - let swapchain = unsafe { - self.device - .swapchain_loader - .create_swapchain(&swapchain_create_info, None)? - }; - - let present_images = unsafe { - self.device - .swapchain_loader - .get_swapchain_images(swapchain)? - }; - let present_images_view = present_images - .iter() - .map(|i| { - self.create_present_image_view(*i) - .expect("Failed to create image view") - }) - .map(|i| Arc::new(i)) - .collect::>(); - - if log::log_enabled!(log::Level::Debug) { - let label = match self.handle { - None => "Swapchain created", - Some(_) => "Swapchain updated", - }; - log::debug!("{label} ({swapchain:?}) : {swapchain_create_info:#?}"); - } - - self.handle = Some(swapchain); - self.present_image_views = Some(present_images_view); - self.present_images = Some(present_images); - - Ok(()) - } - - pub fn create_framebuffers( - &self, - render_pass: &Arc, - ) -> Option>> { - let present_image_views = self.present_image_views.as_ref()?; - - Some( - present_image_views - .iter() - .map(|image_view| { - VkFramebuffer::from_swapchain_image_view( - &self.device, - &render_pass, - &image_view, - &self, - ) - .unwrap() - }) - .map(|framebuffer| Arc::new(framebuffer)) - .collect::>(), - ) - } - - pub fn update_resolution(&mut self, width: u32, height: u32) -> VkResult<()> { - log::debug!("New resolution requested ({width}x{height})"); - - let chosen_extent = Self::choose_swapchain_extent( - vk::Extent2D { width, height }, - &self.swapchain_support_details.1, - ); - if chosen_extent.width != self.surface_resolution.width - || chosen_extent.height != self.surface_resolution.height - { - self.new_requested_surface_resolution = Some(chosen_extent); - log::debug!( - "New resolution submitted ({}x{})", - chosen_extent.width, - chosen_extent.height - ); - } else { - log::debug!("New resolution skipped ({width}x{height}) : Same resolution"); - } - - Ok(()) - } - - pub fn acquire_next_image(&self, semaphore: &VkSemaphore) -> VkResult<(u32, bool)> { - unsafe { - self.device.swapchain_loader.acquire_next_image( - self.handle.unwrap(), - u64::MAX, - semaphore.handle, - vk::Fence::null(), - ) - } - } - - pub fn is_dirty(&self) -> bool { - self.new_requested_surface_resolution.is_some() - } - - fn create_swapchain_info(&self, surface: &VkSurface) -> vk::SwapchainCreateInfoKHR { - vk::SwapchainCreateInfoKHR::default() - .surface(surface.handle) - .min_image_count(self.desired_image_count) - .image_color_space(self.surface_format.color_space) - .image_format(self.surface_format.format) - .image_extent(self.surface_resolution) - .image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT) - .image_sharing_mode(vk::SharingMode::EXCLUSIVE) - .pre_transform(self.pre_transform) - .composite_alpha(vk::CompositeAlphaFlagsKHR::OPAQUE) - .present_mode(self.present_mode) - .clipped(true) - .image_array_layers(1) - } - - fn choose_swapchain_extent( - window_size: vk::Extent2D, - surface_capabilities: &vk::SurfaceCapabilitiesKHR, - ) -> vk::Extent2D { - vk::Extent2D { - width: window_size - .width - .max(surface_capabilities.min_image_extent.width) - .min(surface_capabilities.max_image_extent.width), - height: window_size - .height - .max(surface_capabilities.min_image_extent.height) - .min(surface_capabilities.max_image_extent.height), - } - } - - fn choose_surface_format( - surface_formats: &Vec, - ) -> Option { - surface_formats.first().and_then(|f| Some(*f)) - } - - fn choose_desired_image_count(surface_capabilities: &vk::SurfaceCapabilitiesKHR) -> u32 { - let mut desired_image_count = surface_capabilities.min_image_count + 1; - if surface_capabilities.max_image_count > 0 - && desired_image_count > surface_capabilities.max_image_count - { - desired_image_count = surface_capabilities.max_image_count; - } - desired_image_count - } - - fn choose_pre_transform( - surface_capabilities: &vk::SurfaceCapabilitiesKHR, - ) -> vk::SurfaceTransformFlagsKHR { - if surface_capabilities - .supported_transforms - .contains(vk::SurfaceTransformFlagsKHR::IDENTITY) - { - vk::SurfaceTransformFlagsKHR::IDENTITY - } else { - surface_capabilities.current_transform - } - } - - fn choose_present_mode(present_modes: &Vec) -> vk::PresentModeKHR { - present_modes - .iter() - .cloned() - .find(|&mode| mode == vk::PresentModeKHR::MAILBOX) - .unwrap_or(vk::PresentModeKHR::FIFO) - } - - fn create_present_image_view(&self, image: vk::Image) -> VkResult { - let create_view_info = vk::ImageViewCreateInfo::default() - .view_type(vk::ImageViewType::TYPE_2D) - .format(self.surface_format.format) - .components(vk::ComponentMapping { - r: vk::ComponentSwizzle::IDENTITY, - g: vk::ComponentSwizzle::IDENTITY, - b: vk::ComponentSwizzle::IDENTITY, - a: vk::ComponentSwizzle::IDENTITY, - }) - .subresource_range(vk::ImageSubresourceRange { - aspect_mask: vk::ImageAspectFlags::COLOR, - base_mip_level: 0, - level_count: 1, - base_array_layer: 0, - layer_count: 1, - }) - .image(image); - - unsafe { - self.device - .handle - .create_image_view(&create_view_info, None) - } - } -} - -impl Drop for VkSwapchain { - fn drop(&mut self) { - if let Some(swapchain) = self.handle { - unsafe { - self.device - .swapchain_loader - .destroy_swapchain(swapchain, None); - } - self.handle = None; - log::debug!("Swapchain destroyed ({swapchain:?})"); - } - } -} diff --git a/src/scene/mod.rs b/src/scene/mod.rs deleted file mode 100644 index 46be2e9..0000000 --- a/src/scene/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -mod triangle; -mod vertex; - -pub use triangle::TriangleScene; diff --git a/src/scene/triangle.rs b/src/scene/triangle.rs deleted file mode 100644 index f699930..0000000 --- a/src/scene/triangle.rs +++ /dev/null @@ -1,49 +0,0 @@ -use crate::renderer::vulkan::{VkDevice, VkGraphicsPipeline, VkRenderPass, VkSwapchain}; -use crate::renderer::Renderable; -use ash::vk; -use ash::vk::CommandBuffer; -use std::sync::Arc; - -pub struct TriangleScene { - pipeline: Option, -} - -impl TriangleScene { - pub fn new() -> Self { - Self { pipeline: None } - } -} - -impl Renderable for TriangleScene { - fn init(&mut self, device: &Arc, render_pass: &Arc) -> anyhow::Result<()> { - let pipeline = VkGraphicsPipeline::new(&device, &render_pass)?; - self.pipeline = Some(pipeline); - - Ok(()) - } - - fn render(&self, device: &VkDevice, swapchain: &VkSwapchain, command_buffer: &CommandBuffer) -> anyhow::Result<()> { - unsafe { - device.handle.cmd_bind_pipeline( - *command_buffer, - vk::PipelineBindPoint::GRAPHICS, - self.pipeline.as_ref().unwrap().pipeline, - ) - }; - - let viewport = vk::Viewport::default() - .width(swapchain.surface_resolution.width as f32) - .height(swapchain.surface_resolution.height as f32) - .max_depth(1.0); - - unsafe { device.handle.cmd_set_viewport(*command_buffer, 0, &[viewport]) } - - let scissor = swapchain.surface_resolution.into(); - - unsafe { device.handle.cmd_set_scissor(*command_buffer, 0, &[scissor]) } - - unsafe { device.handle.cmd_draw(*command_buffer, 3, 1, 0, 0) }; - - Ok(()) - } -} \ No newline at end of file diff --git a/src/scene/vertex.rs b/src/scene/vertex.rs deleted file mode 100644 index 0384d0c..0000000 --- a/src/scene/vertex.rs +++ /dev/null @@ -1,39 +0,0 @@ -use std::sync::Arc; -use ash::prelude::VkResult; -use ash::vk; -use crate::renderer::vulkan::{Vertex, VkBuffer, VkDevice}; - -#[derive(Default)] -struct VertexScene { - vertices: Vec, - - vertices_buffer: Option, -} - -impl VertexScene { - pub fn new() -> Self { - let vertices = vec![ - Vertex::new([0.0, -0.5], [1.0, 0.0, 0.0]), - Vertex::new([0.5, 0.5], [0.0, 1.0, 0.0]), - Vertex::new([-0.5, 0.5], [0.0, 0.0, 1.0]), - ]; - - Self { - vertices, - ..Default::default() - } - } - - - fn create_buffer(&mut self, device: &Arc) -> VkResult<()> { - let buffer_info = vk::BufferCreateInfo::default() - .usage(vk::BufferUsageFlags::VERTEX_BUFFER) - .sharing_mode(vk::SharingMode::EXCLUSIVE) - .size(self.vertices.len() as u64 * size_of::() as u64); - - let buffer = VkBuffer::new(device, &buffer_info)?; - self.vertices_buffer = Some(buffer); - - Ok(()) - } -} \ No newline at end of file From 9256da20944e3413dbc72bd9aeee08e4b9426af7 Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Sun, 8 Dec 2024 18:20:36 +0100 Subject: [PATCH 02/41] Use rwh_06 with winit --- Cargo.lock | 14 +++----------- Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7092bb5..d457b93 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -662,8 +662,7 @@ dependencies = [ "log", "ndk-sys", "num_enum", - "raw-window-handle 0.5.2", - "raw-window-handle 0.6.2", + "raw-window-handle", "thiserror", ] @@ -1052,12 +1051,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "raw-window-handle" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" - [[package]] name = "raw-window-handle" version = "0.6.2" @@ -1472,7 +1465,7 @@ dependencies = [ "parking_lot", "proc-macro2", "quote", - "raw-window-handle 0.6.2", + "raw-window-handle", "raw-window-metal", "serde", "serde_json", @@ -1966,8 +1959,7 @@ dependencies = [ "orbclient", "percent-encoding", "pin-project", - "raw-window-handle 0.5.2", - "raw-window-handle 0.6.2", + "raw-window-handle", "redox_syscall 0.4.1", "rustix", "sctk-adwaita", diff --git a/Cargo.toml b/Cargo.toml index 3cf3338..9ad5563 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ publish = false [dependencies] anyhow = "1.0" -winit = { version = "0.30", features = ["rwh_05"] } +winit = { version = "0.30", features = ["rwh_06"] } vulkano = { git = "https://github.com/vulkano-rs/vulkano.git", branch = "master" } vulkano-shaders = { git = "https://github.com/vulkano-rs/vulkano.git", branch = "master" } From e58a3573816e1af6a9637e126bc84e144f6d1630 Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Sun, 8 Dec 2024 18:45:49 +0100 Subject: [PATCH 03/41] Add 4 triangle --- src/renderer/app.rs | 2 +- src/renderer/render_context.rs | 5 +-- src/renderer/scene.rs | 60 ++++++++++++++++++++++++++++++---- 3 files changed, 55 insertions(+), 12 deletions(-) diff --git a/src/renderer/app.rs b/src/renderer/app.rs index 438f946..55c6a31 100644 --- a/src/renderer/app.rs +++ b/src/renderer/app.rs @@ -12,7 +12,7 @@ use vulkano::sync::GpuFuture; use winit::application::ApplicationHandler; use winit::event::WindowEvent; use winit::event_loop::{ActiveEventLoop, EventLoop}; -use winit::window::{Window, WindowId}; +use winit::window::WindowId; use crate::renderer::render_context::RenderContext; use crate::renderer::{window_size_dependent_setup, Scene}; diff --git a/src/renderer/render_context.rs b/src/renderer/render_context.rs index cd2bc24..6ae9301 100644 --- a/src/renderer/render_context.rs +++ b/src/renderer/render_context.rs @@ -1,11 +1,8 @@ use std::sync::Arc; use vulkano::device::Device; -use vulkano::image::{Image, ImageUsage}; +use vulkano::image::ImageUsage; use vulkano::image::view::ImageView; -use vulkano::pipeline::graphics::subpass::PipelineRenderingCreateInfo; use vulkano::pipeline::graphics::viewport::Viewport; -use vulkano::pipeline::GraphicsPipeline; -use vulkano::render_pass::{Framebuffer, RenderPass}; use vulkano::swapchain::{Surface, Swapchain, SwapchainCreateInfo}; use vulkano::sync; use vulkano::sync::GpuFuture; diff --git a/src/renderer/scene.rs b/src/renderer/scene.rs index 174ba7e..f982963 100644 --- a/src/renderer/scene.rs +++ b/src/renderer/scene.rs @@ -164,17 +164,60 @@ impl Scene { // We now create a buffer that will store the shape of our triangle. let vertices = [ + // Triangle en haut à gauche MyVertex { - position: [-0.5, -0.25], - color: [1.0, 0.0, 0.0], + position: [-0.5, -0.75], // Coin supérieur gauche + color: [1.0, 0.0, 0.0], // Couleur rouge }, MyVertex { - position: [0.0, 0.5], - color: [0.0, 1.0, 0.0], + position: [-0.75, -0.25], // Coin supérieur + color: [0.0, 1.0, 0.0], // Couleur verte }, MyVertex { - position: [0.25, -0.1], - color: [0.0, 0.0, 1.0], + position: [-0.25, -0.25], // Coin supérieur droit + color: [0.0, 0.0, 1.0], // Couleur bleue + }, + + // Triangle en bas à gauche + MyVertex { + position: [-0.5, 0.25], // Coin inférieur gauche + color: [0.5, 0.5, 0.5], // Couleur gris + }, + MyVertex { + position: [-0.75, 0.75], // Coin inférieur + color: [0.2, 0.8, 0.2], // Couleur vert clair + }, + MyVertex { + position: [-0.25, 0.75], // Coin inférieur droit + color: [0.8, 0.2, 0.2], // Couleur rouge clair + }, + + // Triangle en haut à droite + MyVertex { + position: [0.5, -0.75], // Coin gauche supérieur + color: [1.0, 1.0, 0.0], // Couleur jaune + }, + MyVertex { + position: [0.25, -0.25], // Coin gauche + color: [0.0, 1.0, 1.0], // Couleur cyan + }, + MyVertex { + position: [0.75, -0.25], // Coin gauche inférieur + color: [1.0, 0.0, 1.0], // Couleur magenta + }, + + // Triangle en bas à droite + MyVertex { + position: [0.5, 0.25], // Coin droit supérieur + color: [0.1, 0.5, 0.8], // Couleur bleu clair + }, + MyVertex { + position: [0.25, 0.75], // Coin droit + color: [0.8, 0.6, 0.1], // Couleur or + }, + MyVertex { + position: [0.75, 0.75], // Coin droit inférieur + color: [0.3, 0.4, 0.6], // Couleur bleu foncé }, ]; let vertex_buffer = Buffer::from_iter( @@ -205,6 +248,9 @@ impl Scene { .unwrap(); // We add a draw command. - unsafe { builder.draw(self.vertex_buffer.len() as u32, 1, 0, 0) }.unwrap(); + let vertex_count = self.vertex_buffer.len() as u32; + let instance_count = vertex_count / 3; + + unsafe { builder.draw(vertex_count, instance_count, 0, 0) }.unwrap(); } } \ No newline at end of file From 6743fe8fddf02cc09ec4aad33dd59070fdb91d03 Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Wed, 11 Dec 2024 14:03:40 +0100 Subject: [PATCH 04/41] Remove comment --- src/renderer/app.rs | 141 --------------------------------- src/renderer/render_context.rs | 55 +------------ src/renderer/scene.rs | 64 --------------- 3 files changed, 1 insertion(+), 259 deletions(-) diff --git a/src/renderer/app.rs b/src/renderer/app.rs index 55c6a31..fdf3ce2 100644 --- a/src/renderer/app.rs +++ b/src/renderer/app.rs @@ -30,16 +30,8 @@ impl App { pub fn new(event_loop: &EventLoop<()>) -> Self { let library = VulkanLibrary::new().unwrap(); - // The first step of any Vulkan program is to create an instance. - // - // When we create an instance, we have to pass a list of extensions that we want to enable. - // - // All the window-drawing functionalities are part of non-core extensions that we need to - // enable manually. To do so, we ask `Surface` for the list of extensions required to draw - // to a window. let required_extensions = Surface::required_extensions(event_loop).unwrap(); - // Now creating the instance. let instance = Instance::new( library, InstanceCreateInfo { @@ -57,69 +49,31 @@ impl App { ) .unwrap(); - // Choose device extensions that we're going to use. In order to present images to a - // surface, we need a `Swapchain`, which is provided by the `khr_swapchain` extension. let mut device_extensions = DeviceExtensions { khr_swapchain: true, ..DeviceExtensions::empty() }; - // We then choose which physical device to use. First, we enumerate all the available - // physical devices, then apply filters to narrow them down to those that can support our - // needs. let (physical_device, queue_family_index) = instance .enumerate_physical_devices() .unwrap() .filter(|p| { - // For this example, we require at least Vulkan 1.3, or a device that has the - // `khr_dynamic_rendering` extension available. p.api_version() >= Version::V1_3 || p.supported_extensions().khr_dynamic_rendering }) .filter(|p| { - // Some devices may not support the extensions or features that your application, - // or report properties and limits that are not sufficient for your application. - // These should be filtered out here. p.supported_extensions().contains(&device_extensions) }) .filter_map(|p| { - // For each physical device, we try to find a suitable queue family that will - // execute our draw commands. - // - // Devices can provide multiple queues to run commands in parallel (for example a - // draw queue and a compute queue), similar to CPU threads. This is something you - // have to have to manage manually in Vulkan. Queues of the same type belong to the - // same queue family. - // - // Here, we look for a single queue family that is suitable for our purposes. In a - // real-world application, you may want to use a separate dedicated transfer queue - // to handle data transfers in parallel with graphics operations. You may also need - // a separate queue for compute operations, if your application uses those. p.queue_family_properties() .iter() .enumerate() .position(|(i, q)| { - // We select a queue family that supports graphics operations. When drawing - // to a window surface, as we do in this example, we also need to check - // that queues in this queue family are capable of presenting images to the - // surface. q.queue_flags.intersects(QueueFlags::GRAPHICS) && p.presentation_support(i as u32, event_loop).unwrap() }) - // The code here searches for the first queue family that is suitable. If none - // is found, `None` is returned to `filter_map`, which disqualifies this - // physical device. .map(|i| (p, i as u32)) }) - // All the physical devices that pass the filters above are suitable for the - // application. However, not every device is equal, some are preferred over others. - // Now, we assign each physical device a score, and pick the device with the lowest - // ("best") score. - // - // In this example, we simply select the best-scoring device to use in the application. - // In a real-world setting, you may want to use the best-scoring device only as a - // "default" or "recommended" device, and let the user choose the device themself. .min_by_key(|(p, _)| { - // We assign a lower score to device types that are likely to be faster/better. match p.properties().device_type { PhysicalDeviceType::DiscreteGpu => 0, PhysicalDeviceType::IntegratedGpu => 1, @@ -131,68 +85,36 @@ impl App { }) .expect("no suitable physical device found"); - // Some little debug infos. println!( "Using device: {} (type: {:?})", physical_device.properties().device_name, physical_device.properties().device_type, ); - // If the selected device doesn't have Vulkan 1.3 available, then we need to enable the - // `khr_dynamic_rendering` extension manually. This extension became a core part of Vulkan - // in version 1.3 and later, so it's always available then and it does not need to be - // enabled. We can be sure that this extension will be available on the selected physical - // device, because we filtered out unsuitable devices in the device selection code above. if physical_device.api_version() < Version::V1_3 { device_extensions.khr_dynamic_rendering = true; } - // Now initializing the device. This is probably the most important object of Vulkan. - // - // An iterator of created queues is returned by the function alongside the device. let (device, mut queues) = Device::new( - // Which physical device to connect to. physical_device, DeviceCreateInfo { - // The list of queues that we are going to use. Here we only use one queue, from - // the previously chosen queue family. queue_create_infos: vec![QueueCreateInfo { queue_family_index, ..Default::default() }], - - // A list of optional features and extensions that our program needs to work - // correctly. Some parts of the Vulkan specs are optional and must be enabled - // manually at device creation. In this example the only things we are going to - // need are the `khr_swapchain` extension that allows us to draw to a window, and - // `khr_dynamic_rendering` if we don't have Vulkan 1.3 available. enabled_extensions: device_extensions, - - // In order to render with Vulkan 1.3's dynamic rendering, we need to enable it - // here. Otherwise, we are only allowed to render with a render pass object, as in - // the standard triangle example. The feature is required to be supported by the - // device if it supports Vulkan 1.3 and higher, or if the `khr_dynamic_rendering` - // extension is available, so we don't need to check for support. enabled_features: DeviceFeatures { dynamic_rendering: true, ..DeviceFeatures::empty() }, - ..Default::default() }, ) .unwrap(); - // Since we can request multiple queues, the `queues` variable is in fact an iterator. We - // only use one queue in this example, so we just retrieve the first and only element of - // the iterator. let queue = queues.next().unwrap(); - let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device.clone())); - // Before we can start creating and recording command buffers, we need a way of allocating - // them. Vulkano provides a command buffer allocator, which manages raw Vulkan command - // pools underneath and provides a safe interface for them. let command_buffer_allocator = Arc::new(StandardCommandBufferAllocator::new( device.clone(), Default::default(), @@ -245,21 +167,12 @@ impl ApplicationHandler for App { WindowEvent::RedrawRequested => { let window_size = rcx.window.inner_size(); - // Do not draw the frame when the screen size is zero. On Windows, this can occur - // when minimizing the application. if window_size.width == 0 || window_size.height == 0 { return; } - // It is important to call this function from time to time, otherwise resources - // will keep accumulating and you will eventually reach an out of memory error. - // Calling this function polls various fences in order to determine what the GPU - // has already processed, and frees the resources that are no longer needed. rcx.previous_frame_end.as_mut().unwrap().cleanup_finished(); - // Whenever the window resizes we need to recreate everything dependent on the - // window size. In this example that includes the swapchain, the framebuffers and - // the dynamic state viewport. if rcx.recreate_swapchain { let (new_swapchain, new_images) = rcx .swapchain @@ -270,23 +183,11 @@ impl ApplicationHandler for App { .expect("failed to recreate swapchain"); rcx.swapchain = new_swapchain; - - // Now that we have new swapchain images, we must create new image views from - // them as well. rcx.attachment_image_views = window_size_dependent_setup(&new_images); - rcx.viewport.extent = window_size.into(); - rcx.recreate_swapchain = false; } - // Before we can draw on the output, we have to *acquire* an image from the - // swapchain. If no image is available (which happens if you submit draw commands - // too quickly), then the function will block. This operation returns the index of - // the image that we are allowed to draw upon. - // - // This function can block if no image is available. The parameter is an optional - // timeout after which the function call will return an error. let (image_index, suboptimal, acquire_future) = match acquire_next_image( rcx.swapchain.clone(), None, @@ -301,23 +202,10 @@ impl ApplicationHandler for App { Err(e) => panic!("failed to acquire next image: {e}"), }; - // `acquire_next_image` can be successful, but suboptimal. This means that the - // swapchain image will still work, but it may not display correctly. With some - // drivers this can be when the window resizes, but it may not cause the swapchain - // to become out of date. if suboptimal { rcx.recreate_swapchain = true; } - // In order to draw, we have to record a *command buffer*. The command buffer - // object holds the list of commands that are going to be executed. - // - // Recording a command buffer is an expensive operation (usually a few hundred - // microseconds), but it is known to be a hot path in the driver and is expected to - // be optimized. - // - // Note that we have to pass a queue family when we create the command buffer. The - // command buffer will only be executable on that given queue family. let mut builder = AutoCommandBufferBuilder::primary( self.command_buffer_allocator.clone(), self.queue.queue_family_index(), @@ -326,37 +214,18 @@ impl ApplicationHandler for App { .unwrap(); builder - // Before we can draw, we have to *enter a render pass*. We specify which - // attachments we are going to use for rendering here, which needs to match - // what was previously specified when creating the pipeline. .begin_rendering(RenderingInfo { - // As before, we specify one color attachment, but now we specify the image - // view to use as well as how it should be used. color_attachments: vec![Some(RenderingAttachmentInfo { - // `Clear` means that we ask the GPU to clear the content of this - // attachment at the start of rendering. load_op: AttachmentLoadOp::Clear, - // `Store` means that we ask the GPU to store the rendered output in - // the attachment image. We could also ask it to discard the result. store_op: AttachmentStoreOp::Store, - // The value to clear the attachment with. Here we clear it with a blue - // color. - // - // Only attachments that have `AttachmentLoadOp::Clear` are provided - // with clear values, any others should use `None` as the clear value. clear_value: Some([0.0, 0.0, 0.0, 1.0].into()), ..RenderingAttachmentInfo::image_view( - // We specify image view corresponding to the currently acquired - // swapchain image, to use for this attachment. rcx.attachment_image_views[image_index as usize].clone(), ) })], ..Default::default() }) .unwrap() - // We are now inside the first subpass of the render pass. - // - // TODO: Document state setting and how it affects subsequent draw commands. .set_viewport(0, [rcx.viewport.clone()].into_iter().collect()) .unwrap(); @@ -365,11 +234,9 @@ impl ApplicationHandler for App { } builder - // We leave the render pass. .end_rendering() .unwrap(); - // Finish recording the command buffer by calling `end`. let command_buffer = builder.build().unwrap(); let future = rcx @@ -379,14 +246,6 @@ impl ApplicationHandler for App { .join(acquire_future) .then_execute(self.queue.clone(), command_buffer) .unwrap() - // The color output is now expected to contain our triangle. But in order to - // show it on the screen, we have to *present* the image by calling - // `then_swapchain_present`. - // - // This function does not actually present the image immediately. Instead it - // submits a present command at the end of the queue. This means that it will - // only be presented once the GPU has finished executing the command buffer - // that draws the triangle. .then_swapchain_present( self.queue.clone(), SwapchainPresentInfo::swapchain_image_index( diff --git a/src/renderer/render_context.rs b/src/renderer/render_context.rs index 6ae9301..097479e 100644 --- a/src/renderer/render_context.rs +++ b/src/renderer/render_context.rs @@ -22,56 +22,26 @@ impl RenderContext { pub fn new(window: Arc, surface: Arc, device: &Arc) -> Self { let window_size = window.inner_size(); - - // Before we can draw on the surface, we have to create what is called a swapchain. - // Creating a swapchain allocates the color buffers that will contain the image that will - // ultimately be visible on the screen. These images are returned alongside the swapchain. let (swapchain, images) = { - // Querying the capabilities of the surface. When we create the swapchain we can only - // pass values that are allowed by the capabilities. let surface_capabilities = device .physical_device() .surface_capabilities(&surface, Default::default()) .unwrap(); - // Choosing the internal format that the images will have. let (image_format, _) = device .physical_device() .surface_formats(&surface, Default::default()) .unwrap()[0]; - // Please take a look at the docs for the meaning of the parameters we didn't mention. Swapchain::new( device.clone(), surface, SwapchainCreateInfo { - // Some drivers report an `min_image_count` of 1, but fullscreen mode requires - // at least 2. Therefore we must ensure the count is at least 2, otherwise the - // program would crash when entering fullscreen mode on those drivers. + // 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, - - // The size of the window, only used to initially setup the swapchain. - // - // NOTE: - // On some drivers the swapchain extent is specified by - // `surface_capabilities.current_extent` and the swapchain size must use this - // extent. This extent is always the same as the window size. - // - // However, other drivers don't specify a value, i.e. - // `surface_capabilities.current_extent` is `None`. These drivers will allow - // anything, but the only sensible value is the window size. - // - // Both of these cases need the swapchain to use the window size, so we just - // use that. image_extent: window_size.into(), - image_usage: ImageUsage::COLOR_ATTACHMENT, - - // The alpha mode indicates how the alpha value of the final image will behave. - // For example, you can choose whether the window will be opaque or - // transparent. composite_alpha: surface_capabilities .supported_composite_alpha .into_iter() @@ -84,38 +54,15 @@ impl RenderContext { .unwrap() }; - // When creating the swapchain, we only created plain images. To use them as an attachment - // for rendering, we must wrap then in an image view. - // - // Since we need to draw to multiple images, we are going to create a different image view - // for each image. let attachment_image_views = window_size_dependent_setup(&images); - // Dynamic viewports allow us to recreate just the viewport when the window is resized. - // Otherwise we would have to recreate the whole pipeline. let viewport = Viewport { offset: [0.0, 0.0], extent: window_size.into(), depth_range: 0.0..=1.0, }; - // In some situations, the swapchain will become invalid by itself. This includes for - // example when the window is resized (as the images of the swapchain will no longer match - // the window's) or, on Android, when the application went to the background and goes back - // to the foreground. - // - // In this situation, acquiring a swapchain image or presenting it will return an error. - // Rendering to an image of that swapchain will not produce any error, but may or may not - // work. To continue rendering, we need to recreate the swapchain by creating a new - // swapchain. Here, we remember that we need to do this for the next loop iteration. let recreate_swapchain = false; - - // In the loop below we are going to submit commands to the GPU. Submitting a command - // produces an object that implements the `GpuFuture` trait, which holds the resources for - // as long as they are in use by the GPU. - // - // Destroying the `GpuFuture` blocks until the GPU is finished executing it. In order to - // avoid that, we store the submission of the previous frame here. let previous_frame_end = Some(sync::now(device.clone()).boxed()); Self { diff --git a/src/renderer/scene.rs b/src/renderer/scene.rs index f982963..5b76973 100644 --- a/src/renderer/scene.rs +++ b/src/renderer/scene.rs @@ -34,21 +34,6 @@ pub struct Scene { impl Scene { pub fn initialize(device: &Arc, swapchain: &Arc, memory_allocator: &Arc) -> Scene { - // The next step is to create the shaders. - // - // The raw shader creation API provided by the vulkano library is unsafe for various - // reasons, so The `shader!` macro provides a way to generate a Rust module from GLSL - // source - in the example below, the source is provided as a string input directly to the - // shader, but a path to a source file can be provided as well. Note that the user must - // specify the type of shader (e.g. "vertex", "fragment", etc.) using the `ty` option of - // the macro. - // - // The items generated by the `shader!` macro include a `load` function which loads the - // shader using an input logical device. The module also includes type definitions for - // layout structures defined in the shader source, for example uniforms and push constants. - // - // A more detailed overview of what the `shader!` macro generates can be found in the - // vulkano-shaders crate docs. You can view them at https://docs.rs/vulkano-shaders/ mod vs { vulkano_shaders::shader! { ty: "vertex", @@ -63,16 +48,7 @@ impl Scene { } } - // Before we draw, we have to create what is called a **pipeline**. A pipeline describes - // how a GPU operation is to be performed. It is similar to an OpenGL program, but it also - // contains many settings for customization, all baked into a single object. For drawing, - // we create a **graphics** pipeline, but there are also other types of pipeline. let pipeline = { - // First, we load the shaders that the pipeline will use: the vertex shader and the - // fragment shader. - // - // A Vulkan shader can in theory contain multiple entry points, so we have to specify - // which one. let vs = vs::load(device.clone()) .unwrap() .entry_point("main") @@ -82,78 +58,40 @@ impl Scene { .entry_point("main") .unwrap(); - // Automatically generate a vertex input state from the vertex shader's input - // interface, that takes a single vertex buffer containing `Vertex` structs. let vertex_input_state = MyVertex::per_vertex().definition(&vs).unwrap(); - // Make a list of the shader stages that the pipeline will have. let stages = [ PipelineShaderStageCreateInfo::new(vs), PipelineShaderStageCreateInfo::new(fs), ]; - // We must now create a **pipeline layout** object, which describes the locations and - // types of descriptor sets and push constants used by the shaders in the pipeline. - // - // Multiple pipelines can share a common layout object, which is more efficient. The - // shaders in a pipeline must use a subset of the resources described in its pipeline - // layout, but the pipeline layout is allowed to contain resources that are not present - // in the shaders; they can be used by shaders in other pipelines that share the same - // layout. Thus, it is a good idea to design shaders so that many pipelines have common - // resource locations, which allows them to share pipeline layouts. let layout = PipelineLayout::new( device.clone(), - // Since we only have one pipeline in this example, and thus one pipeline layout, - // we automatically generate the creation info for it from the resources used in - // the shaders. In a real application, you would specify this information manually - // so that you can re-use one layout in multiple pipelines. PipelineDescriptorSetLayoutCreateInfo::from_stages(&stages) .into_pipeline_layout_create_info(device.clone()) .unwrap(), ) .unwrap(); - // We describe the formats of attachment images where the colors, depth and/or stencil - // information will be written. The pipeline will only be usable with this particular - // configuration of the attachment images. let subpass = PipelineRenderingCreateInfo { - // We specify a single color attachment that will be rendered to. When we begin - // rendering, we will specify a swapchain image to be used as this attachment, so - // here we set its format to be the same format as the swapchain. color_attachment_formats: vec![Some(swapchain.image_format())], ..Default::default() }; - // Finally, create the pipeline. GraphicsPipeline::new( device.clone(), None, GraphicsPipelineCreateInfo { stages: stages.into_iter().collect(), - // How vertex data is read from the vertex buffers into the vertex shader. vertex_input_state: Some(vertex_input_state), - // How vertices are arranged into primitive shapes. The default primitive shape - // is a triangle. input_assembly_state: Some(InputAssemblyState::default()), - // How primitives are transformed and clipped to fit the framebuffer. We use a - // resizable viewport, set to draw over the entire window. viewport_state: Some(ViewportState::default()), - // How polygons are culled and converted into a raster of pixels. The default - // value does not perform any culling. rasterization_state: Some(RasterizationState::default()), - // How multiple fragment shader samples are converted to a single pixel value. - // The default value does not perform any multisampling. multisample_state: Some(MultisampleState::default()), - // How pixel values are combined with the values already present in the - // framebuffer. The default value overwrites the old value with the new one, - // without any blending. color_blend_state: Some(ColorBlendState::with_attachment_states( subpass.color_attachment_formats.len() as u32, ColorBlendAttachmentState::default(), )), - // Dynamic states allows us to specify parts of the pipeline settings when - // recording the command buffer, before we perform drawing. Here, we specify - // that the viewport should be dynamic. dynamic_state: [DynamicState::Viewport].into_iter().collect(), subpass: Some(subpass.into()), ..GraphicsPipelineCreateInfo::layout(layout) @@ -162,7 +100,6 @@ impl Scene { .unwrap() }; - // We now create a buffer that will store the shape of our triangle. let vertices = [ // Triangle en haut à gauche MyVertex { @@ -247,7 +184,6 @@ impl Scene { .bind_vertex_buffers(0, self.vertex_buffer.clone()) .unwrap(); - // We add a draw command. let vertex_count = self.vertex_buffer.len() as u32; let instance_count = vertex_count / 3; From f65f45fc9aac6db09922994f7677bd2979053b75 Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Wed, 11 Dec 2024 19:30:36 +0100 Subject: [PATCH 05/41] Add configuration for vscode --- .vscode/extensions.json | 7 +++++++ .vscode/launch.json | 45 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 .vscode/extensions.json create mode 100644 .vscode/launch.json diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..a6bd770 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + "recommendations": [ + "pinage404.rust-extension-pack", + "vadimcn.vscode-lldb", + "jnoortheen.nix-ide" + ] +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..c0caf03 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,45 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "lldb", + "request": "launch", + "name": "Debug executable 'rust_vulkan_test'", + "cargo": { + "args": [ + "build", + "--bin=rust_vulkan_test", + "--package=rust_vulkan_test" + ], + "filter": { + "name": "rust_vulkan_test", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "Debug unit tests in executable 'rust_vulkan_test'", + "cargo": { + "args": [ + "test", + "--no-run", + "--bin=rust_vulkan_test", + "--package=rust_vulkan_test" + ], + "filter": { + "name": "rust_vulkan_test", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + } + ] +} \ No newline at end of file From 1169c76b41698a9cba263700f784fcb8b16302ba Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Wed, 11 Dec 2024 20:16:38 +0100 Subject: [PATCH 06/41] Refactorisation de la gestion des pipelines --- src/renderer/mod.rs | 5 +- src/renderer/pipelines/mod.rs | 2 + src/renderer/pipelines/triangle_pipeline.rs | 85 +++++++++ src/renderer/scene.rs | 188 +++++--------------- src/renderer/vertex.rs | 18 ++ 5 files changed, 155 insertions(+), 143 deletions(-) create mode 100644 src/renderer/pipelines/mod.rs create mode 100644 src/renderer/pipelines/triangle_pipeline.rs create mode 100644 src/renderer/vertex.rs diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index e72d412..d056eb7 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -1,15 +1,18 @@ mod render_context; mod app; +mod vertex; +mod pipelines; pub use app::App; +pub use pipelines::create_triangle_pipeline; mod scene; pub use scene::Scene; +pub use vertex::Vertex2D; use std::sync::Arc; use vulkano::image::Image; use vulkano::image::view::ImageView; - /// This function is called once during initialization, then again whenever the window is resized. fn window_size_dependent_setup(images: &[Arc]) -> Vec> { images diff --git a/src/renderer/pipelines/mod.rs b/src/renderer/pipelines/mod.rs new file mode 100644 index 0000000..db588d1 --- /dev/null +++ b/src/renderer/pipelines/mod.rs @@ -0,0 +1,2 @@ +mod triangle_pipeline; +pub use triangle_pipeline::create_triangle_pipeline; \ No newline at end of file diff --git a/src/renderer/pipelines/triangle_pipeline.rs b/src/renderer/pipelines/triangle_pipeline.rs new file mode 100644 index 0000000..e9de828 --- /dev/null +++ b/src/renderer/pipelines/triangle_pipeline.rs @@ -0,0 +1,85 @@ +use std::sync::Arc; +use vulkano::device::Device; +use vulkano::pipeline::graphics::vertex_input::{Vertex, VertexDefinition}; +use vulkano::pipeline::{DynamicState, GraphicsPipeline, PipelineLayout, PipelineShaderStageCreateInfo}; +use vulkano::pipeline::graphics::color_blend::{ColorBlendAttachmentState, ColorBlendState}; +use vulkano::pipeline::graphics::GraphicsPipelineCreateInfo; +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::viewport::ViewportState; +use vulkano::pipeline::layout::PipelineDescriptorSetLayoutCreateInfo; +use vulkano::swapchain::Swapchain; + +use crate::renderer::Vertex2D; + +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) -> Arc { + let vs = shaders::vs::load(device.clone()) + .unwrap() + .entry_point("main") + .unwrap(); + let fs = shaders::fs::load(device.clone()) + .unwrap() + .entry_point("main") + .unwrap(); + + let vertex_input_state = Vertex2D::per_vertex() + .definition(&vs) + .unwrap(); + + let stages = [ + PipelineShaderStageCreateInfo::new(vs), + PipelineShaderStageCreateInfo::new(fs), + ]; + + let layout = PipelineLayout::new( + device.clone(), + PipelineDescriptorSetLayoutCreateInfo::from_stages(&stages) + .into_pipeline_layout_create_info(device.clone()) + .unwrap(), + ) + .unwrap(); + + let subpass = PipelineRenderingCreateInfo { + color_attachment_formats: vec![Some(swapchain.image_format())], + ..Default::default() + }; + + 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) + }, + ) + .unwrap() +} diff --git a/src/renderer/scene.rs b/src/renderer/scene.rs index 5b76973..f8fe8aa 100644 --- a/src/renderer/scene.rs +++ b/src/renderer/scene.rs @@ -1,163 +1,57 @@ use std::sync::Arc; -use vulkano::buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage, Subbuffer}; +use vulkano::buffer::{Buffer, BufferCreateInfo, BufferUsage, Subbuffer}; use vulkano::command_buffer::{AutoCommandBufferBuilder, PrimaryAutoCommandBuffer}; use vulkano::device::Device; use vulkano::memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator}; -use vulkano::pipeline::graphics::vertex_input::{Vertex, VertexDefinition}; -use vulkano::pipeline::{DynamicState, GraphicsPipeline, PipelineLayout, PipelineShaderStageCreateInfo}; -use vulkano::pipeline::graphics::color_blend::{ColorBlendAttachmentState, ColorBlendState}; -use vulkano::pipeline::graphics::GraphicsPipelineCreateInfo; -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::viewport::ViewportState; -use vulkano::pipeline::layout::PipelineDescriptorSetLayoutCreateInfo; +use vulkano::pipeline::GraphicsPipeline; use vulkano::swapchain::Swapchain; -// We use `#[repr(C)]` here to force rustc to use a defined layout for our data, as the default -// representation has *no guarantees*. -#[derive(BufferContents, Vertex)] -#[repr(C)] -struct MyVertex { - #[format(R32G32_SFLOAT)] - position: [f32; 2], - - #[format(R32G32B32_SFLOAT)] - color: [f32; 3], -} +use crate::renderer::{Vertex2D, create_triangle_pipeline}; pub struct Scene { pipeline: Arc, - vertex_buffer: Subbuffer<[MyVertex]>, + vertex_buffer: Subbuffer<[Vertex2D]>, } impl Scene { - pub fn initialize(device: &Arc, swapchain: &Arc, memory_allocator: &Arc) -> Scene { - mod vs { - vulkano_shaders::shader! { - ty: "vertex", - path: r"res/shaders/vertex.vert", - } - } - - mod fs { - vulkano_shaders::shader! { - ty: "fragment", - path: r"res/shaders/vertex.frag", - } - } - - let pipeline = { - let vs = vs::load(device.clone()) - .unwrap() - .entry_point("main") - .unwrap(); - let fs = fs::load(device.clone()) - .unwrap() - .entry_point("main") - .unwrap(); - - let vertex_input_state = MyVertex::per_vertex().definition(&vs).unwrap(); - - let stages = [ - PipelineShaderStageCreateInfo::new(vs), - PipelineShaderStageCreateInfo::new(fs), - ]; - - let layout = PipelineLayout::new( - device.clone(), - PipelineDescriptorSetLayoutCreateInfo::from_stages(&stages) - .into_pipeline_layout_create_info(device.clone()) - .unwrap(), - ) - .unwrap(); - - let subpass = PipelineRenderingCreateInfo { - color_attachment_formats: vec![Some(swapchain.image_format())], - ..Default::default() - }; - - 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) - }, - ) - .unwrap() - }; - + fn create_vertex_buffer( + memory_allocator: &Arc, + ) -> Subbuffer<[Vertex2D]> { let vertices = [ // Triangle en haut à gauche - MyVertex { - position: [-0.5, -0.75], // Coin supérieur gauche - color: [1.0, 0.0, 0.0], // Couleur rouge - }, - MyVertex { - position: [-0.75, -0.25], // Coin supérieur - color: [0.0, 1.0, 0.0], // Couleur verte - }, - MyVertex { - position: [-0.25, -0.25], // Coin supérieur droit - color: [0.0, 0.0, 1.0], // Couleur bleue - }, + Vertex2D::new([-0.5, -0.75], // Coin supérieur gauche + [1.0, 0.0, 0.0]), // Couleur rouge + Vertex2D::new([-0.75, -0.25], // Coin supérieur + [0.0, 1.0, 0.0]), // Couleur verte + Vertex2D::new([-0.25, -0.25], // Coin supérieur droit + [0.0, 0.0, 1.0]), // Couleur bleue // Triangle en bas à gauche - MyVertex { - position: [-0.5, 0.25], // Coin inférieur gauche - color: [0.5, 0.5, 0.5], // Couleur gris - }, - MyVertex { - position: [-0.75, 0.75], // Coin inférieur - color: [0.2, 0.8, 0.2], // Couleur vert clair - }, - MyVertex { - position: [-0.25, 0.75], // Coin inférieur droit - color: [0.8, 0.2, 0.2], // Couleur rouge clair - }, + Vertex2D::new([-0.5, 0.25], // Coin inférieur gauche + [0.5, 0.5, 0.5]), // Couleur gris + Vertex2D::new([-0.75, 0.75], // Coin inférieur + [0.2, 0.8, 0.2]), // Couleur vert clair + Vertex2D::new([-0.25, 0.75], // Coin inférieur droit + [0.8, 0.2, 0.2]), // Couleur rouge clair // Triangle en haut à droite - MyVertex { - position: [0.5, -0.75], // Coin gauche supérieur - color: [1.0, 1.0, 0.0], // Couleur jaune - }, - MyVertex { - position: [0.25, -0.25], // Coin gauche - color: [0.0, 1.0, 1.0], // Couleur cyan - }, - MyVertex { - position: [0.75, -0.25], // Coin gauche inférieur - color: [1.0, 0.0, 1.0], // Couleur magenta - }, + Vertex2D::new([0.5, -0.75], // Coin gauche supérieur + [1.0, 1.0, 0.0]), // Couleur jaune + Vertex2D::new([0.25, -0.25], // Coin gauche + [0.0, 1.0, 1.0]), // Couleur cyan + Vertex2D::new([0.75, -0.25], // Coin gauche inférieur + [1.0, 0.0, 1.0]), // Couleur magenta // Triangle en bas à droite - MyVertex { - position: [0.5, 0.25], // Coin droit supérieur - color: [0.1, 0.5, 0.8], // Couleur bleu clair - }, - MyVertex { - position: [0.25, 0.75], // Coin droit - color: [0.8, 0.6, 0.1], // Couleur or - }, - MyVertex { - position: [0.75, 0.75], // Coin droit inférieur - color: [0.3, 0.4, 0.6], // Couleur bleu foncé - }, + Vertex2D::new([0.5, 0.25], // Coin droit supérieur + [0.1, 0.5, 0.8]), // Couleur bleu clair + Vertex2D::new([0.25, 0.75], // Coin droit + [0.8, 0.6, 0.1]), // Couleur or + Vertex2D::new([0.75, 0.75], // Coin droit inférieur + [0.3, 0.4, 0.6]), // Couleur bleu foncé ]; - let vertex_buffer = Buffer::from_iter( + + Buffer::from_iter( memory_allocator.clone(), BufferCreateInfo { usage: BufferUsage::VERTEX_BUFFER, @@ -170,16 +64,26 @@ impl Scene { }, vertices, ) - .unwrap(); + .unwrap() + } - Self { + pub fn initialize( + device: &Arc, + swapchain: &Arc, + memory_allocator: &Arc, + ) -> Scene { + let pipeline = create_triangle_pipeline(device, swapchain); + let vertex_buffer = Self::create_vertex_buffer(memory_allocator); + + Scene { pipeline, vertex_buffer, } } pub fn render(&self, builder: &mut AutoCommandBufferBuilder) { - builder.bind_pipeline_graphics(self.pipeline.clone()) + builder + .bind_pipeline_graphics(self.pipeline.clone()) .unwrap() .bind_vertex_buffers(0, self.vertex_buffer.clone()) .unwrap(); diff --git a/src/renderer/vertex.rs b/src/renderer/vertex.rs new file mode 100644 index 0000000..8eb4ff5 --- /dev/null +++ b/src/renderer/vertex.rs @@ -0,0 +1,18 @@ +use vulkano::buffer::BufferContents; +use vulkano::pipeline::graphics::vertex_input::Vertex; + +#[derive(BufferContents, Vertex)] +#[repr(C)] +pub struct Vertex2D { + #[format(R32G32_SFLOAT)] + pub position: [f32; 2], + + #[format(R32G32B32_SFLOAT)] + pub color: [f32; 3], +} + +impl Vertex2D { + pub fn new(position: [f32; 2], color: [f32; 3]) -> Self { + Self { position, color } + } +} From 11a5083513fa23c25d72da7ed3b29b2eae1989bc Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Wed, 11 Dec 2024 20:41:04 +0100 Subject: [PATCH 07/41] Refactor vertex buffer creations --- src/renderer/app.rs | 60 +++++----- src/renderer/mod.rs | 6 +- src/renderer/pipelines/mod.rs | 2 +- src/renderer/pipelines/triangle_pipeline.rs | 21 ++-- src/renderer/render_context.rs | 6 +- src/renderer/scene.rs | 119 ++++++++++---------- src/renderer/vertex.rs | 26 ++++- 7 files changed, 132 insertions(+), 108 deletions(-) diff --git a/src/renderer/app.rs b/src/renderer/app.rs index fdf3ce2..784e6ce 100644 --- a/src/renderer/app.rs +++ b/src/renderer/app.rs @@ -1,20 +1,24 @@ +use crate::renderer::render_context::RenderContext; +use crate::renderer::{window_size_dependent_setup, Scene}; use std::sync::Arc; use vulkano::command_buffer::allocator::StandardCommandBufferAllocator; -use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, DeviceFeatures, Queue, QueueCreateInfo, QueueFlags}; +use vulkano::command_buffer::{ + AutoCommandBufferBuilder, CommandBufferUsage, RenderingAttachmentInfo, RenderingInfo, +}; use vulkano::device::physical::PhysicalDeviceType; +use vulkano::device::{ + Device, DeviceCreateInfo, DeviceExtensions, DeviceFeatures, Queue, QueueCreateInfo, QueueFlags, +}; use vulkano::instance::{Instance, InstanceCreateFlags, InstanceCreateInfo}; use vulkano::memory::allocator::StandardMemoryAllocator; -use vulkano::swapchain::{acquire_next_image, Surface, SwapchainCreateInfo, SwapchainPresentInfo}; -use vulkano::{sync, Validated, Version, VulkanError, VulkanLibrary}; -use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, RenderingAttachmentInfo, RenderingInfo}; use vulkano::render_pass::{AttachmentLoadOp, AttachmentStoreOp}; +use vulkano::swapchain::{acquire_next_image, Surface, SwapchainCreateInfo, SwapchainPresentInfo}; use vulkano::sync::GpuFuture; +use vulkano::{sync, Validated, Version, VulkanError, VulkanLibrary}; use winit::application::ApplicationHandler; use winit::event::WindowEvent; use winit::event_loop::{ActiveEventLoop, EventLoop}; use winit::window::WindowId; -use crate::renderer::render_context::RenderContext; -use crate::renderer::{window_size_dependent_setup, Scene}; pub struct App { instance: Arc, @@ -47,7 +51,7 @@ impl App { ..Default::default() }, ) - .unwrap(); + .unwrap(); let mut device_extensions = DeviceExtensions { khr_swapchain: true, @@ -60,9 +64,7 @@ impl App { .filter(|p| { p.api_version() >= Version::V1_3 || p.supported_extensions().khr_dynamic_rendering }) - .filter(|p| { - p.supported_extensions().contains(&device_extensions) - }) + .filter(|p| p.supported_extensions().contains(&device_extensions)) .filter_map(|p| { p.queue_family_properties() .iter() @@ -73,15 +75,13 @@ impl App { }) .map(|i| (p, i as u32)) }) - .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, - } + .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, }) .expect("no suitable physical device found"); @@ -110,7 +110,7 @@ impl App { ..Default::default() }, ) - .unwrap(); + .unwrap(); let queue = queues.next().unwrap(); let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device.clone())); @@ -141,16 +141,16 @@ impl ApplicationHandler for App { f64::from(600), )); - let window = Arc::new( - event_loop - .create_window(window_attributes) - .unwrap(), - ); + let window = Arc::new(event_loop.create_window(window_attributes).unwrap()); let surface = Surface::from_window(self.instance.clone(), window.clone()).unwrap(); self.rcx = Some(RenderContext::new(window, surface, &self.device)); - self.scene = Some(Scene::initialize(&self.device, &self.rcx.as_ref().unwrap().swapchain, &self.memory_allocator)); + self.scene = Some(Scene::initialize( + &self.device, + &self.rcx.as_ref().unwrap().swapchain, + &self.memory_allocator, + )); } fn window_event(&mut self, event_loop: &ActiveEventLoop, _id: WindowId, event: WindowEvent) { @@ -192,7 +192,7 @@ impl ApplicationHandler for App { rcx.swapchain.clone(), None, ) - .map_err(Validated::unwrap) + .map_err(Validated::unwrap) { Ok(r) => r, Err(VulkanError::OutOfDate) => { @@ -211,7 +211,7 @@ impl ApplicationHandler for App { self.queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) - .unwrap(); + .unwrap(); builder .begin_rendering(RenderingInfo { @@ -233,9 +233,7 @@ impl ApplicationHandler for App { scene.render(&mut builder); } - builder - .end_rendering() - .unwrap(); + builder.end_rendering().unwrap(); let command_buffer = builder.build().unwrap(); diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index d056eb7..21def04 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -1,7 +1,7 @@ -mod render_context; mod app; -mod vertex; mod pipelines; +mod render_context; +mod vertex; pub use app::App; pub use pipelines::create_triangle_pipeline; @@ -10,8 +10,8 @@ pub use scene::Scene; pub use vertex::Vertex2D; use std::sync::Arc; -use vulkano::image::Image; use vulkano::image::view::ImageView; +use vulkano::image::Image; /// This function is called once during initialization, then again whenever the window is resized. fn window_size_dependent_setup(images: &[Arc]) -> Vec> { diff --git a/src/renderer/pipelines/mod.rs b/src/renderer/pipelines/mod.rs index db588d1..670717a 100644 --- a/src/renderer/pipelines/mod.rs +++ b/src/renderer/pipelines/mod.rs @@ -1,2 +1,2 @@ mod triangle_pipeline; -pub use triangle_pipeline::create_triangle_pipeline; \ No newline at end of file +pub use triangle_pipeline::create_triangle_pipeline; diff --git a/src/renderer/pipelines/triangle_pipeline.rs b/src/renderer/pipelines/triangle_pipeline.rs index e9de828..b5858e2 100644 --- a/src/renderer/pipelines/triangle_pipeline.rs +++ b/src/renderer/pipelines/triangle_pipeline.rs @@ -1,15 +1,17 @@ use std::sync::Arc; use vulkano::device::Device; -use vulkano::pipeline::graphics::vertex_input::{Vertex, VertexDefinition}; -use vulkano::pipeline::{DynamicState, GraphicsPipeline, PipelineLayout, PipelineShaderStageCreateInfo}; use vulkano::pipeline::graphics::color_blend::{ColorBlendAttachmentState, ColorBlendState}; -use vulkano::pipeline::graphics::GraphicsPipelineCreateInfo; 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::graphics::GraphicsPipelineCreateInfo; use vulkano::pipeline::layout::PipelineDescriptorSetLayoutCreateInfo; +use vulkano::pipeline::{ + DynamicState, GraphicsPipeline, PipelineLayout, PipelineShaderStageCreateInfo, +}; use vulkano::swapchain::Swapchain; use crate::renderer::Vertex2D; @@ -30,7 +32,10 @@ mod shaders { } } -pub fn create_triangle_pipeline(device: &Arc, swapchain: &Arc) -> Arc { +pub fn create_triangle_pipeline( + device: &Arc, + swapchain: &Arc, +) -> Arc { let vs = shaders::vs::load(device.clone()) .unwrap() .entry_point("main") @@ -40,9 +45,7 @@ pub fn create_triangle_pipeline(device: &Arc, swapchain: &Arc .entry_point("main") .unwrap(); - let vertex_input_state = Vertex2D::per_vertex() - .definition(&vs) - .unwrap(); + let vertex_input_state = Vertex2D::per_vertex().definition(&vs).unwrap(); let stages = [ PipelineShaderStageCreateInfo::new(vs), @@ -55,7 +58,7 @@ pub fn create_triangle_pipeline(device: &Arc, swapchain: &Arc .into_pipeline_layout_create_info(device.clone()) .unwrap(), ) - .unwrap(); + .unwrap(); let subpass = PipelineRenderingCreateInfo { color_attachment_formats: vec![Some(swapchain.image_format())], @@ -81,5 +84,5 @@ pub fn create_triangle_pipeline(device: &Arc, swapchain: &Arc ..GraphicsPipelineCreateInfo::layout(layout) }, ) - .unwrap() + .unwrap() } diff --git a/src/renderer/render_context.rs b/src/renderer/render_context.rs index 097479e..2248be3 100644 --- a/src/renderer/render_context.rs +++ b/src/renderer/render_context.rs @@ -1,13 +1,13 @@ +use crate::renderer::window_size_dependent_setup; use std::sync::Arc; use vulkano::device::Device; -use vulkano::image::ImageUsage; use vulkano::image::view::ImageView; +use vulkano::image::ImageUsage; use vulkano::pipeline::graphics::viewport::Viewport; use vulkano::swapchain::{Surface, Swapchain, SwapchainCreateInfo}; use vulkano::sync; use vulkano::sync::GpuFuture; use winit::window::Window; -use crate::renderer::window_size_dependent_setup; pub struct RenderContext { pub(super) window: Arc, @@ -51,7 +51,7 @@ impl RenderContext { ..Default::default() }, ) - .unwrap() + .unwrap() }; let attachment_image_views = window_size_dependent_setup(&images); diff --git a/src/renderer/scene.rs b/src/renderer/scene.rs index f8fe8aa..e327f05 100644 --- a/src/renderer/scene.rs +++ b/src/renderer/scene.rs @@ -1,12 +1,67 @@ use std::sync::Arc; -use vulkano::buffer::{Buffer, BufferCreateInfo, BufferUsage, Subbuffer}; +use vulkano::buffer::Subbuffer; use vulkano::command_buffer::{AutoCommandBufferBuilder, PrimaryAutoCommandBuffer}; use vulkano::device::Device; -use vulkano::memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator}; +use vulkano::memory::allocator::StandardMemoryAllocator; use vulkano::pipeline::GraphicsPipeline; use vulkano::swapchain::Swapchain; -use crate::renderer::{Vertex2D, create_triangle_pipeline}; +use crate::renderer::{create_triangle_pipeline, Vertex2D}; + +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, @@ -14,66 +69,14 @@ pub struct Scene { } impl Scene { - fn create_vertex_buffer( - memory_allocator: &Arc, - ) -> Subbuffer<[Vertex2D]> { - let vertices = [ - // Triangle en haut à gauche - Vertex2D::new([-0.5, -0.75], // Coin supérieur gauche - [1.0, 0.0, 0.0]), // Couleur rouge - Vertex2D::new([-0.75, -0.25], // Coin supérieur - [0.0, 1.0, 0.0]), // Couleur verte - Vertex2D::new([-0.25, -0.25], // Coin supérieur droit - [0.0, 0.0, 1.0]), // Couleur bleue - - // Triangle en bas à gauche - Vertex2D::new([-0.5, 0.25], // Coin inférieur gauche - [0.5, 0.5, 0.5]), // Couleur gris - Vertex2D::new([-0.75, 0.75], // Coin inférieur - [0.2, 0.8, 0.2]), // Couleur vert clair - Vertex2D::new([-0.25, 0.75], // Coin inférieur droit - [0.8, 0.2, 0.2]), // Couleur rouge clair - - // Triangle en haut à droite - Vertex2D::new([0.5, -0.75], // Coin gauche supérieur - [1.0, 1.0, 0.0]), // Couleur jaune - Vertex2D::new([0.25, -0.25], // Coin gauche - [0.0, 1.0, 1.0]), // Couleur cyan - Vertex2D::new([0.75, -0.25], // Coin gauche inférieur - [1.0, 0.0, 1.0]), // Couleur magenta - - // Triangle en bas à droite - Vertex2D::new([0.5, 0.25], // Coin droit supérieur - [0.1, 0.5, 0.8]), // Couleur bleu clair - Vertex2D::new([0.25, 0.75], // Coin droit - [0.8, 0.6, 0.1]), // Couleur or - Vertex2D::new([0.75, 0.75], // Coin droit inférieur - [0.3, 0.4, 0.6]), // Couleur bleu foncé - ]; - - 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, - ) - .unwrap() - } - pub fn initialize( device: &Arc, swapchain: &Arc, memory_allocator: &Arc, ) -> Scene { let pipeline = create_triangle_pipeline(device, swapchain); - let vertex_buffer = Self::create_vertex_buffer(memory_allocator); + let vertex_buffer = + Vertex2D::create_buffer(Vec::from_iter(VERTICES), memory_allocator).unwrap(); Scene { pipeline, @@ -93,4 +96,4 @@ impl Scene { unsafe { builder.draw(vertex_count, instance_count, 0, 0) }.unwrap(); } -} \ No newline at end of file +} diff --git a/src/renderer/vertex.rs b/src/renderer/vertex.rs index 8eb4ff5..fc2ee21 100644 --- a/src/renderer/vertex.rs +++ b/src/renderer/vertex.rs @@ -1,5 +1,10 @@ -use vulkano::buffer::BufferContents; +use std::sync::Arc; +use vulkano::buffer::{ + AllocateBufferError, Buffer, BufferContents, BufferCreateInfo, BufferUsage, Subbuffer, +}; +use vulkano::memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator}; use vulkano::pipeline::graphics::vertex_input::Vertex; +use vulkano::Validated; #[derive(BufferContents, Vertex)] #[repr(C)] @@ -12,7 +17,22 @@ pub struct Vertex2D { } impl Vertex2D { - pub fn new(position: [f32; 2], color: [f32; 3]) -> Self { - Self { position, color } + 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, + ) } } From d9f70caec0f604ebf833a6adf93db3b2f5439745 Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Wed, 11 Dec 2024 20:43:10 +0100 Subject: [PATCH 08/41] vscode: Add format on save --- .vscode/settings.json | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..61e637e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "editor.formatOnSave": true, + "[rust]": { + "editor.defaultFormatter": "rust-lang.rust-analyzer", + }, + "files.insertFinalNewline": true, + "files.trimTrailingWhitespace": true +} From 7cbc78588896cdd4d7e98fee9a34dfc796587f21 Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Wed, 11 Dec 2024 21:07:47 +0100 Subject: [PATCH 09/41] Scene: manage error --- src/renderer/app.rs | 15 ++++--- src/renderer/pipelines/triangle_pipeline.rs | 46 +++++++++++---------- src/renderer/scene.rs | 34 ++++++++------- 3 files changed, 53 insertions(+), 42 deletions(-) diff --git a/src/renderer/app.rs b/src/renderer/app.rs index 784e6ce..8651372 100644 --- a/src/renderer/app.rs +++ b/src/renderer/app.rs @@ -146,11 +146,14 @@ impl ApplicationHandler for App { let surface = Surface::from_window(self.instance.clone(), window.clone()).unwrap(); self.rcx = Some(RenderContext::new(window, surface, &self.device)); - self.scene = Some(Scene::initialize( - &self.device, - &self.rcx.as_ref().unwrap().swapchain, - &self.memory_allocator, - )); + self.scene = Some( + Scene::load( + &self.device, + &self.rcx.as_ref().unwrap().swapchain, + &self.memory_allocator, + ) + .unwrap(), + ); } fn window_event(&mut self, event_loop: &ActiveEventLoop, _id: WindowId, event: WindowEvent) { @@ -230,7 +233,7 @@ impl ApplicationHandler for App { .unwrap(); if let Some(scene) = self.scene.as_ref() { - scene.render(&mut builder); + scene.render(&mut builder).unwrap(); } builder.end_rendering().unwrap(); diff --git a/src/renderer/pipelines/triangle_pipeline.rs b/src/renderer/pipelines/triangle_pipeline.rs index b5858e2..77d1092 100644 --- a/src/renderer/pipelines/triangle_pipeline.rs +++ b/src/renderer/pipelines/triangle_pipeline.rs @@ -1,3 +1,4 @@ +use std::error::Error; use std::sync::Arc; use vulkano::device::Device; use vulkano::pipeline::graphics::color_blend::{ColorBlendAttachmentState, ColorBlendState}; @@ -12,6 +13,7 @@ use vulkano::pipeline::layout::PipelineDescriptorSetLayoutCreateInfo; use vulkano::pipeline::{ DynamicState, GraphicsPipeline, PipelineLayout, PipelineShaderStageCreateInfo, }; +use vulkano::shader::EntryPoint; use vulkano::swapchain::Swapchain; use crate::renderer::Vertex2D; @@ -35,37 +37,26 @@ mod shaders { pub fn create_triangle_pipeline( device: &Arc, swapchain: &Arc, -) -> Arc { - let vs = shaders::vs::load(device.clone()) - .unwrap() - .entry_point("main") - .unwrap(); - let fs = shaders::fs::load(device.clone()) - .unwrap() - .entry_point("main") - .unwrap(); - - let vertex_input_state = Vertex2D::per_vertex().definition(&vs).unwrap(); +) -> 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 layout = PipelineLayout::new( - device.clone(), - PipelineDescriptorSetLayoutCreateInfo::from_stages(&stages) - .into_pipeline_layout_create_info(device.clone()) - .unwrap(), - ) - .unwrap(); + let create_info = PipelineDescriptorSetLayoutCreateInfo::from_stages(&stages) + .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() }; - GraphicsPipeline::new( + let pipeline = GraphicsPipeline::new( device.clone(), None, GraphicsPipelineCreateInfo { @@ -83,6 +74,19 @@ pub fn create_triangle_pipeline( subpass: Some(subpass.into()), ..GraphicsPipelineCreateInfo::layout(layout) }, - ) - .unwrap() + )?; + + Ok(pipeline) +} + +fn load_shaders(device: &Arc) -> Result<(EntryPoint, EntryPoint), Box> { + let vs = shaders::vs::load(device.clone())? + .entry_point("main") + .ok_or(format!("Failed find main entry point of vertex shader"))?; + + let fs = shaders::fs::load(device.clone())? + .entry_point("main") + .ok_or(format!("Failed find main entry point of fragment shader"))?; + + Ok((vs, fs)) } diff --git a/src/renderer/scene.rs b/src/renderer/scene.rs index e327f05..c820380 100644 --- a/src/renderer/scene.rs +++ b/src/renderer/scene.rs @@ -1,3 +1,4 @@ +use std::error::Error; use std::sync::Arc; use vulkano::buffer::Subbuffer; use vulkano::command_buffer::{AutoCommandBufferBuilder, PrimaryAutoCommandBuffer}; @@ -69,31 +70,34 @@ pub struct Scene { } impl Scene { - pub fn initialize( + pub fn load( device: &Arc, swapchain: &Arc, memory_allocator: &Arc, - ) -> Scene { - let pipeline = create_triangle_pipeline(device, swapchain); - let vertex_buffer = - Vertex2D::create_buffer(Vec::from_iter(VERTICES), memory_allocator).unwrap(); + ) -> Result> { + let pipeline = create_triangle_pipeline(device, swapchain)?; + let vertex_buffer = Vertex2D::create_buffer(Vec::from_iter(VERTICES), memory_allocator)?; - Scene { + Ok(Scene { pipeline, vertex_buffer, - } + }) } - pub fn render(&self, builder: &mut AutoCommandBufferBuilder) { - builder - .bind_pipeline_graphics(self.pipeline.clone()) - .unwrap() - .bind_vertex_buffers(0, self.vertex_buffer.clone()) - .unwrap(); - + pub fn render( + &self, + builder: &mut AutoCommandBufferBuilder, + ) -> Result<(), Box> { let vertex_count = self.vertex_buffer.len() as u32; let instance_count = vertex_count / 3; - unsafe { builder.draw(vertex_count, instance_count, 0, 0) }.unwrap(); + unsafe { + builder + .bind_pipeline_graphics(self.pipeline.clone())? + .bind_vertex_buffers(0, self.vertex_buffer.clone())? + .draw(vertex_count, instance_count, 0, 0)?; + } + + Ok(()) } } From 2b9c3ab25a7ac1b99c3f60714d01c20d6403cd59 Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Wed, 11 Dec 2024 21:08:28 +0100 Subject: [PATCH 10/41] vscode: Organize imports --- .vscode/settings.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index 61e637e..875f10e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,8 @@ { "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.organizeImports": "always", + }, "[rust]": { "editor.defaultFormatter": "rust-lang.rust-analyzer", }, From 864c558db70e94cc79bb00fbe32a2b590e0abbf5 Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Tue, 17 Dec 2024 19:01:30 +0100 Subject: [PATCH 11/41] Update deps --- Cargo.lock | 143 ++++++++++++++++++++++++++++------------------------- 1 file changed, 75 insertions(+), 68 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d457b93..cbd0e43 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -118,9 +118,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.93" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" +checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" [[package]] name = "arrayref" @@ -190,9 +190,9 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytemuck" -version = "1.19.0" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" +checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" dependencies = [ "bytemuck_derive", ] @@ -210,9 +210,9 @@ dependencies = [ [[package]] name = "bytes" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "calloop" @@ -242,9 +242,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.1" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" +checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf" dependencies = [ "jobserver", "libc", @@ -345,18 +345,18 @@ dependencies = [ [[package]] name = "crossbeam-queue" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" @@ -428,14 +428,20 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] +[[package]] +name = "foldhash" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" + [[package]] name = "foreign-types" version = "0.5.0" @@ -497,9 +503,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.1" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "heck" @@ -521,9 +527,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "indexmap" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", "hashbrown", @@ -574,24 +580,25 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.72" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" dependencies = [ + "once_cell", "wasm-bindgen", ] [[package]] name = "libc" -version = "0.2.164" +version = "0.2.168" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" +checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" [[package]] name = "libloading" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", "windows-targets 0.52.6", @@ -605,7 +612,7 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.6.0", "libc", - "redox_syscall 0.5.7", + "redox_syscall 0.5.8", ] [[package]] @@ -957,7 +964,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.7", + "redox_syscall 0.5.8", "smallvec", "windows-targets 0.52.6", ] @@ -1026,9 +1033,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.89" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -1079,9 +1086,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ "bitflags 2.6.0", ] @@ -1138,15 +1145,15 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.40" +version = "0.38.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0" +checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" dependencies = [ "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1191,18 +1198,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", @@ -1311,9 +1318,9 @@ checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" [[package]] name = "syn" -version = "2.0.87" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -1394,9 +1401,9 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "pin-project-lite", "tracing-core", @@ -1404,21 +1411,21 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" [[package]] name = "ttf-parser" -version = "0.25.0" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5902c5d130972a0000f60860bfbf46f7ca3db5391eddfedd1b8728bd9dc96c0e" +checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-segmentation" @@ -1450,12 +1457,12 @@ dependencies = [ [[package]] name = "vulkano" version = "0.34.0" -source = "git+https://github.com/vulkano-rs/vulkano.git?branch=master#23606f05825adf5212f104ead9e95f9d325db1aa" +source = "git+https://github.com/vulkano-rs/vulkano.git?branch=master#ea30f65280360b1e1bc907cd42d4eb355fed3c9d" dependencies = [ - "ahash", "ash", "bytemuck", "crossbeam-queue", + "foldhash", "half", "heck", "indexmap", @@ -1481,7 +1488,7 @@ dependencies = [ [[package]] name = "vulkano-macros" version = "0.34.0" -source = "git+https://github.com/vulkano-rs/vulkano.git?branch=master#23606f05825adf5212f104ead9e95f9d325db1aa" +source = "git+https://github.com/vulkano-rs/vulkano.git?branch=master#ea30f65280360b1e1bc907cd42d4eb355fed3c9d" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -1492,9 +1499,9 @@ dependencies = [ [[package]] name = "vulkano-shaders" version = "0.34.0" -source = "git+https://github.com/vulkano-rs/vulkano.git?branch=master#23606f05825adf5212f104ead9e95f9d325db1aa" +source = "git+https://github.com/vulkano-rs/vulkano.git?branch=master#ea30f65280360b1e1bc907cd42d4eb355fed3c9d" dependencies = [ - "ahash", + "foldhash", "heck", "proc-macro2", "quote", @@ -1521,9 +1528,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" dependencies = [ "cfg-if", "once_cell", @@ -1532,13 +1539,12 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", "syn", @@ -1547,21 +1553,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.45" +version = "0.4.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" +checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1569,9 +1576,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", @@ -1582,9 +1589,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" [[package]] name = "wayland-backend" @@ -1697,9 +1704,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.72" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" dependencies = [ "js-sys", "wasm-bindgen", From ec6e0c28bee6178537599e50f289261abf7dc64f Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Tue, 17 Dec 2024 23:41:33 +0100 Subject: [PATCH 12/41] Begin work on uniform data --- res/shaders/vertex.vert | 2 +- src/renderer/pipelines/triangle_pipeline.rs | 31 +++++++++++++++++---- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/res/shaders/vertex.vert b/res/shaders/vertex.vert index 3adb319..ec483f7 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; void main() { gl_Position = vec4(position, 0.0, 1.0); fragColor = color; } \ No newline at end of file +#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 MVP_Data { mat4 model; mat4 view; mat4 projection; } uniforms; void main() { gl_Position = vec4(position, 0.0, 1.0); fragColor = color; } \ No newline at end of file diff --git a/src/renderer/pipelines/triangle_pipeline.rs b/src/renderer/pipelines/triangle_pipeline.rs index 77d1092..1423b8f 100644 --- a/src/renderer/pipelines/triangle_pipeline.rs +++ b/src/renderer/pipelines/triangle_pipeline.rs @@ -1,5 +1,9 @@ +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::color_blend::{ColorBlendAttachmentState, ColorBlendState}; use vulkano::pipeline::graphics::input_assembly::InputAssemblyState; @@ -9,11 +13,11 @@ use vulkano::pipeline::graphics::subpass::PipelineRenderingCreateInfo; use vulkano::pipeline::graphics::vertex_input::{Vertex, VertexDefinition}; use vulkano::pipeline::graphics::viewport::ViewportState; use vulkano::pipeline::graphics::GraphicsPipelineCreateInfo; -use vulkano::pipeline::layout::PipelineDescriptorSetLayoutCreateInfo; +use vulkano::pipeline::layout::{PipelineDescriptorSetLayoutCreateInfo, PipelineLayoutCreateFlags}; use vulkano::pipeline::{ DynamicState, GraphicsPipeline, PipelineLayout, PipelineShaderStageCreateInfo, }; -use vulkano::shader::EntryPoint; +use vulkano::shader::{EntryPoint, ShaderStages}; use vulkano::swapchain::Swapchain; use crate::renderer::Vertex2D; @@ -46,8 +50,23 @@ pub fn create_triangle_pipeline( PipelineShaderStageCreateInfo::new(fs), ]; - let create_info = PipelineDescriptorSetLayoutCreateInfo::from_stages(&stages) - .into_pipeline_layout_create_info(device.clone())?; + let mut bindings = BTreeMap::::new(); + let mut descriptor_set_layout_binding = + DescriptorSetLayoutBinding::descriptor_type(DescriptorType::UniformBufferDynamic); + 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)?; @@ -82,11 +101,11 @@ pub fn create_triangle_pipeline( fn load_shaders(device: &Arc) -> Result<(EntryPoint, EntryPoint), Box> { let vs = shaders::vs::load(device.clone())? .entry_point("main") - .ok_or(format!("Failed find main entry point of vertex shader"))?; + .ok_or("Failed find main entry point of vertex shader".to_string())?; let fs = shaders::fs::load(device.clone())? .entry_point("main") - .ok_or(format!("Failed find main entry point of fragment shader"))?; + .ok_or("Failed find main entry point of fragment shader".to_string())?; Ok((vs, fs)) } From 784e5b90beb3f462aec722f081166ea120d251e1 Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Wed, 18 Dec 2024 21:47:11 +0100 Subject: [PATCH 13/41] Add first working rotation --- Cargo.lock | 7 ++ Cargo.toml | 3 + res/shaders/vertex.vert | 2 +- src/renderer/mod.rs | 1 - src/renderer/pipelines/mod.rs | 3 +- src/renderer/pipelines/triangle_pipeline.rs | 4 +- src/renderer/scene.rs | 84 ++++++++++++++++++++- 7 files changed, 94 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cbd0e43..78fdb0b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -490,6 +490,12 @@ dependencies = [ "wasi", ] +[[package]] +name = "glam" +version = "0.29.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc46dd3ec48fdd8e693a98d2b8bafae273a2d54c1de02a2a7e3d57d501f39677" + [[package]] name = "half" version = "2.4.1" @@ -1137,6 +1143,7 @@ version = "0.1.0" dependencies = [ "anyhow", "env_logger", + "glam", "log", "vulkano", "vulkano-shaders", diff --git a/Cargo.toml b/Cargo.toml index 9ad5563..62dde55 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,9 @@ winit = { version = "0.30", features = ["rwh_06"] } vulkano = { git = "https://github.com/vulkano-rs/vulkano.git", branch = "master" } vulkano-shaders = { git = "https://github.com/vulkano-rs/vulkano.git", branch = "master" } +# Math +glam = { version = "0.29" } + # Log and tracing log = "0.4" env_logger = "0.11.5" diff --git a/res/shaders/vertex.vert b/res/shaders/vertex.vert index ec483f7..65b0acf 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 MVP_Data { mat4 model; mat4 view; mat4 projection; } uniforms; void main() { gl_Position = vec4(position, 0.0, 1.0); fragColor = color; } \ No newline at end of file +#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 diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 21def04..01187d5 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -3,7 +3,6 @@ mod pipelines; mod render_context; mod vertex; pub use app::App; -pub use pipelines::create_triangle_pipeline; mod scene; pub use scene::Scene; diff --git a/src/renderer/pipelines/mod.rs b/src/renderer/pipelines/mod.rs index 670717a..e5f30a7 100644 --- a/src/renderer/pipelines/mod.rs +++ b/src/renderer/pipelines/mod.rs @@ -1,2 +1 @@ -mod triangle_pipeline; -pub use triangle_pipeline::create_triangle_pipeline; +pub mod triangle_pipeline; diff --git a/src/renderer/pipelines/triangle_pipeline.rs b/src/renderer/pipelines/triangle_pipeline.rs index 1423b8f..f6001f7 100644 --- a/src/renderer/pipelines/triangle_pipeline.rs +++ b/src/renderer/pipelines/triangle_pipeline.rs @@ -22,7 +22,7 @@ use vulkano::swapchain::Swapchain; use crate::renderer::Vertex2D; -mod shaders { +pub mod shaders { pub mod vs { vulkano_shaders::shader! { ty: "vertex", @@ -52,7 +52,7 @@ pub fn create_triangle_pipeline( let mut bindings = BTreeMap::::new(); let mut descriptor_set_layout_binding = - DescriptorSetLayoutBinding::descriptor_type(DescriptorType::UniformBufferDynamic); + DescriptorSetLayoutBinding::descriptor_type(DescriptorType::UniformBuffer); descriptor_set_layout_binding.stages = ShaderStages::VERTEX; bindings.insert(0, descriptor_set_layout_binding); diff --git a/src/renderer/scene.rs b/src/renderer/scene.rs index c820380..266a7a8 100644 --- a/src/renderer/scene.rs +++ b/src/renderer/scene.rs @@ -1,13 +1,19 @@ +use crate::renderer::pipelines::triangle_pipeline::shaders::vs; +use glam::{Mat3, Mat4, Vec3}; use std::error::Error; use std::sync::Arc; -use vulkano::buffer::Subbuffer; +use std::time::Instant; +use vulkano::buffer::allocator::{SubbufferAllocator, SubbufferAllocatorCreateInfo}; +use vulkano::buffer::{BufferUsage, Subbuffer}; use vulkano::command_buffer::{AutoCommandBufferBuilder, PrimaryAutoCommandBuffer}; +use vulkano::descriptor_set::allocator::StandardDescriptorSetAllocator; +use vulkano::descriptor_set::{DescriptorSet, WriteDescriptorSet}; use vulkano::device::Device; -use vulkano::memory::allocator::StandardMemoryAllocator; -use vulkano::pipeline::GraphicsPipeline; +use vulkano::memory::allocator::{MemoryTypeFilter, StandardMemoryAllocator}; +use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint}; use vulkano::swapchain::Swapchain; -use crate::renderer::{create_triangle_pipeline, Vertex2D}; +use crate::renderer::{pipelines::triangle_pipeline::create_triangle_pipeline, Vertex2D}; const VERTICES: [Vertex2D; 12] = [ // Triangle en haut à gauche @@ -67,6 +73,11 @@ const VERTICES: [Vertex2D; 12] = [ pub struct Scene { pipeline: Arc, vertex_buffer: Subbuffer<[Vertex2D]>, + + uniform_buffer_allocator: SubbufferAllocator, + rotation_start: Instant, + swapchain: Arc, + descriptor_set_allocator: Arc, } impl Scene { @@ -78,9 +89,28 @@ impl Scene { let pipeline = create_triangle_pipeline(device, swapchain)?; let vertex_buffer = Vertex2D::create_buffer(Vec::from_iter(VERTICES), memory_allocator)?; + let uniform_buffer_allocator = SubbufferAllocator::new( + memory_allocator.clone(), + SubbufferAllocatorCreateInfo { + buffer_usage: BufferUsage::UNIFORM_BUFFER, + memory_type_filter: MemoryTypeFilter::PREFER_DEVICE + | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, + ..Default::default() + }, + ); + + let descriptor_set_allocator = Arc::new(StandardDescriptorSetAllocator::new( + device.clone(), + Default::default(), + )); + Ok(Scene { pipeline, vertex_buffer, + uniform_buffer_allocator, + rotation_start: Instant::now(), + swapchain: swapchain.clone(), + descriptor_set_allocator, }) } @@ -91,13 +121,59 @@ impl Scene { let vertex_count = self.vertex_buffer.len() as u32; let instance_count = vertex_count / 3; + let uniform_buffer = self.get_uniform_buffer(); + let layout = &self.pipeline.layout().set_layouts()[0]; + let descriptor_set = DescriptorSet::new( + self.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) -> Subbuffer { + 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 = + self.swapchain.image_extent()[0] as f32 / self.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(), + }; + + let buffer = self.uniform_buffer_allocator.allocate_sized().unwrap(); + *buffer.write().unwrap() = uniform_data; + + buffer + } } From f7a3d883c64669e03369eec58e36f6c5fc305fb5 Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Thu, 19 Dec 2024 21:44:49 +0100 Subject: [PATCH 14/41] Move allocator to App --- src/renderer/app.rs | 206 +++++++++++++++++---------------- src/renderer/mod.rs | 12 -- src/renderer/render_context.rs | 31 ++++- src/renderer/scene.rs | 54 +++------ 4 files changed, 150 insertions(+), 153 deletions(-) diff --git a/src/renderer/app.rs b/src/renderer/app.rs index 8651372..9788aa2 100644 --- a/src/renderer/app.rs +++ b/src/renderer/app.rs @@ -1,18 +1,21 @@ use crate::renderer::render_context::RenderContext; -use crate::renderer::{window_size_dependent_setup, Scene}; +use crate::renderer::Scene; use std::sync::Arc; +use vulkano::buffer::allocator::{SubbufferAllocator, SubbufferAllocatorCreateInfo}; +use vulkano::buffer::BufferUsage; use vulkano::command_buffer::allocator::StandardCommandBufferAllocator; use vulkano::command_buffer::{ AutoCommandBufferBuilder, CommandBufferUsage, RenderingAttachmentInfo, RenderingInfo, }; +use vulkano::descriptor_set::allocator::StandardDescriptorSetAllocator; use vulkano::device::physical::PhysicalDeviceType; use vulkano::device::{ Device, DeviceCreateInfo, DeviceExtensions, DeviceFeatures, Queue, QueueCreateInfo, QueueFlags, }; use vulkano::instance::{Instance, InstanceCreateFlags, InstanceCreateInfo}; -use vulkano::memory::allocator::StandardMemoryAllocator; +use vulkano::memory::allocator::{MemoryTypeFilter, StandardMemoryAllocator}; use vulkano::render_pass::{AttachmentLoadOp, AttachmentStoreOp}; -use vulkano::swapchain::{acquire_next_image, Surface, SwapchainCreateInfo, SwapchainPresentInfo}; +use vulkano::swapchain::{acquire_next_image, Surface, SwapchainPresentInfo}; use vulkano::sync::GpuFuture; use vulkano::{sync, Validated, Version, VulkanError, VulkanLibrary}; use winit::application::ApplicationHandler; @@ -21,12 +24,16 @@ use winit::event_loop::{ActiveEventLoop, EventLoop}; use winit::window::WindowId; pub struct App { - instance: Arc, - device: Arc, - queue: Arc, - memory_allocator: Arc, - command_buffer_allocator: Arc, - rcx: Option, + pub instance: Arc, + pub device: Arc, + pub queue: Arc, + + pub memory_allocator: Arc, + pub command_buffer_allocator: Arc, + pub uniform_buffer_allocator: SubbufferAllocator, + pub descriptor_set_allocator: Arc, + + pub rcx: Option, scene: Option, } @@ -120,12 +127,29 @@ impl App { Default::default(), )); + let uniform_buffer_allocator = SubbufferAllocator::new( + memory_allocator.clone(), + SubbufferAllocatorCreateInfo { + buffer_usage: BufferUsage::UNIFORM_BUFFER, + memory_type_filter: MemoryTypeFilter::PREFER_DEVICE + | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, + ..Default::default() + }, + ); + + let descriptor_set_allocator = Arc::new(StandardDescriptorSetAllocator::new( + device.clone(), + Default::default(), + )); + Self { instance, device, queue, memory_allocator, command_buffer_allocator, + uniform_buffer_allocator, + descriptor_set_allocator, rcx: None, scene: None, } @@ -146,68 +170,49 @@ impl ApplicationHandler for App { let surface = Surface::from_window(self.instance.clone(), window.clone()).unwrap(); self.rcx = Some(RenderContext::new(window, surface, &self.device)); - self.scene = Some( - Scene::load( - &self.device, - &self.rcx.as_ref().unwrap().swapchain, - &self.memory_allocator, - ) - .unwrap(), - ); + self.scene = Some(Scene::load(&self).unwrap()); } fn window_event(&mut self, event_loop: &ActiveEventLoop, _id: WindowId, event: WindowEvent) { - let rcx = self.rcx.as_mut().unwrap(); - match event { WindowEvent::CloseRequested => { log::debug!("The close button was pressed; stopping"); event_loop.exit(); } WindowEvent::Resized(_) => { + let rcx = self.rcx.as_mut().unwrap(); rcx.recreate_swapchain = true; } WindowEvent::RedrawRequested => { - let window_size = rcx.window.inner_size(); + let (image_index, acquire_future) = { + let rcx = self.rcx.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(); - - if rcx.recreate_swapchain { - let (new_swapchain, new_images) = rcx - .swapchain - .recreate(SwapchainCreateInfo { - image_extent: window_size.into(), - ..rcx.swapchain.create_info() - }) - .expect("failed to recreate swapchain"); - - rcx.swapchain = new_swapchain; - rcx.attachment_image_views = window_size_dependent_setup(&new_images); - rcx.viewport.extent = window_size.into(); - rcx.recreate_swapchain = false; - } - - 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; + if window_size.width == 0 || window_size.height == 0 { return; } - Err(e) => panic!("failed to acquire next image: {e}"), - }; - if suboptimal { - rcx.recreate_swapchain = true; - } + 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 = AutoCommandBufferBuilder::primary( self.command_buffer_allocator.clone(), @@ -216,57 +221,64 @@ impl ApplicationHandler for App { ) .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(); + { + let rcx = self.rcx.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(&mut builder).unwrap(); + scene.render(&self, &mut builder).unwrap(); } builder.end_rendering().unwrap(); let command_buffer = builder.build().unwrap(); - let future = rcx - .previous_frame_end - .take() - .unwrap() - .join(acquire_future) - .then_execute(self.queue.clone(), command_buffer) - .unwrap() - .then_swapchain_present( - self.queue.clone(), - SwapchainPresentInfo::swapchain_image_index( - rcx.swapchain.clone(), - image_index, - ), - ) - .then_signal_fence_and_flush(); + { + let rcx = self.rcx.as_mut().unwrap(); - 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.device.clone()).boxed()); - } - Err(e) => { - println!("failed to flush future: {e}"); - rcx.previous_frame_end = Some(sync::now(self.device.clone()).boxed()); + let future = rcx + .previous_frame_end + .take() + .unwrap() + .join(acquire_future) + .then_execute(self.queue.clone(), command_buffer) + .unwrap() + .then_swapchain_present( + self.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.device.clone()).boxed()); + } + Err(e) => { + println!("failed to flush future: {e}"); + rcx.previous_frame_end = Some(sync::now(self.device.clone()).boxed()); + } } } } diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 01187d5..bbcff9a 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -7,15 +7,3 @@ pub use app::App; mod scene; pub use scene::Scene; pub use vertex::Vertex2D; - -use std::sync::Arc; -use vulkano::image::view::ImageView; -use vulkano::image::Image; - -/// This function is called once during initialization, then again whenever the window is resized. -fn window_size_dependent_setup(images: &[Arc]) -> Vec> { - images - .iter() - .map(|image| ImageView::new_default(image.clone()).unwrap()) - .collect::>() -} diff --git a/src/renderer/render_context.rs b/src/renderer/render_context.rs index 2248be3..dd7e840 100644 --- a/src/renderer/render_context.rs +++ b/src/renderer/render_context.rs @@ -1,12 +1,11 @@ -use crate::renderer::window_size_dependent_setup; use std::sync::Arc; use vulkano::device::Device; use vulkano::image::view::ImageView; -use vulkano::image::ImageUsage; +use vulkano::image::{Image, ImageUsage}; use vulkano::pipeline::graphics::viewport::Viewport; use vulkano::swapchain::{Surface, Swapchain, SwapchainCreateInfo}; -use vulkano::sync; use vulkano::sync::GpuFuture; +use vulkano::{sync, Validated, VulkanError}; use winit::window::Window; pub struct RenderContext { @@ -74,4 +73,30 @@ impl RenderContext { 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/scene.rs b/src/renderer/scene.rs index 266a7a8..e3c6b58 100644 --- a/src/renderer/scene.rs +++ b/src/renderer/scene.rs @@ -3,17 +3,12 @@ use glam::{Mat3, Mat4, Vec3}; use std::error::Error; use std::sync::Arc; use std::time::Instant; -use vulkano::buffer::allocator::{SubbufferAllocator, SubbufferAllocatorCreateInfo}; -use vulkano::buffer::{BufferUsage, Subbuffer}; +use vulkano::buffer::Subbuffer; use vulkano::command_buffer::{AutoCommandBufferBuilder, PrimaryAutoCommandBuffer}; -use vulkano::descriptor_set::allocator::StandardDescriptorSetAllocator; use vulkano::descriptor_set::{DescriptorSet, WriteDescriptorSet}; -use vulkano::device::Device; -use vulkano::memory::allocator::{MemoryTypeFilter, StandardMemoryAllocator}; use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint}; -use vulkano::swapchain::Swapchain; -use crate::renderer::{pipelines::triangle_pipeline::create_triangle_pipeline, Vertex2D}; +use crate::renderer::{pipelines::triangle_pipeline::create_triangle_pipeline, App, Vertex2D}; const VERTICES: [Vertex2D; 12] = [ // Triangle en haut à gauche @@ -74,57 +69,34 @@ pub struct Scene { pipeline: Arc, vertex_buffer: Subbuffer<[Vertex2D]>, - uniform_buffer_allocator: SubbufferAllocator, rotation_start: Instant, - swapchain: Arc, - descriptor_set_allocator: Arc, } impl Scene { - pub fn load( - device: &Arc, - swapchain: &Arc, - memory_allocator: &Arc, - ) -> Result> { - let pipeline = create_triangle_pipeline(device, swapchain)?; - let vertex_buffer = Vertex2D::create_buffer(Vec::from_iter(VERTICES), memory_allocator)?; - - let uniform_buffer_allocator = SubbufferAllocator::new( - memory_allocator.clone(), - SubbufferAllocatorCreateInfo { - buffer_usage: BufferUsage::UNIFORM_BUFFER, - memory_type_filter: MemoryTypeFilter::PREFER_DEVICE - | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, - ..Default::default() - }, - ); - - let descriptor_set_allocator = Arc::new(StandardDescriptorSetAllocator::new( - device.clone(), - Default::default(), - )); + pub fn load(app: &App) -> Result> { + let pipeline = create_triangle_pipeline(&app.device, &app.rcx.as_ref().unwrap().swapchain)?; + let vertex_buffer = + Vertex2D::create_buffer(Vec::from_iter(VERTICES), &app.memory_allocator)?; Ok(Scene { pipeline, vertex_buffer, - uniform_buffer_allocator, rotation_start: Instant::now(), - swapchain: swapchain.clone(), - descriptor_set_allocator, }) } pub fn render( &self, + app: &App, 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(); + let uniform_buffer = self.get_uniform_buffer(app); let layout = &self.pipeline.layout().set_layouts()[0]; let descriptor_set = DescriptorSet::new( - self.descriptor_set_allocator.clone(), + app.descriptor_set_allocator.clone(), layout.clone(), [WriteDescriptorSet::buffer(0, uniform_buffer)], [], @@ -147,15 +119,15 @@ impl Scene { Ok(()) } - fn get_uniform_buffer(&self) -> Subbuffer { + fn get_uniform_buffer(&self, app: &App) -> Subbuffer { + let swapchain = &app.rcx.as_ref().unwrap().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 = - self.swapchain.image_extent()[0] as f32 / self.swapchain.image_extent()[1] as f32; + 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( @@ -171,7 +143,7 @@ impl Scene { projection: proj.to_cols_array_2d(), }; - let buffer = self.uniform_buffer_allocator.allocate_sized().unwrap(); + let buffer = app.uniform_buffer_allocator.allocate_sized().unwrap(); *buffer.write().unwrap() = uniform_data; buffer From 3208f62b4a727e6bf4380b6e386ad3926092998f Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Sun, 22 Dec 2024 23:35:39 +0100 Subject: [PATCH 15/41] Fix flake.nix for nixos --- .envrc | 2 +- flake.nix | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/.envrc b/.envrc index 2f8e1d3..3550a30 100644 --- a/.envrc +++ b/.envrc @@ -1 +1 @@ -use flake --impure +use flake diff --git a/flake.nix b/flake.nix index 624590d..8386939 100644 --- a/flake.nix +++ b/flake.nix @@ -30,6 +30,13 @@ cargo = rust; }); + nativeBuildInputs = with pkgs; [ + (rust.override { extensions = ["rust-src" "rust-analyzer"]; }) + pkg-config + cmake + python312 + ]; + 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 ]); @@ -37,10 +44,15 @@ { devShells = { default = pkgs.mkShell { - nativeBuildInputs = with pkgs; [ - (rust.override { extensions = ["rust-src" "rust-analyzer"]; }) - pkg-config - ]; + inherit nativeBuildInputs; + + buildInputs = libs; + + LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath (with pkgs; [ libxkbcommon wayland libGL ]); + }; + + with_compatibility = pkgs.mkShell { + inherit nativeBuildInputs; buildInputs = libs ++ [ pkgs.nixgl.auto.nixVulkanNvidia pkgs.nixgl.nixVulkanIntel From 7ed254f1839cfd2eb7a0970518dc9285a98257bb Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Wed, 8 Jan 2025 23:12:09 +0100 Subject: [PATCH 16/41] Fix NixOS not running --- .envrc | 2 +- flake.nix | 41 +++++++++++++++++++---------------------- src/renderer/app.rs | 2 -- 3 files changed, 20 insertions(+), 25 deletions(-) diff --git a/.envrc b/.envrc index 3550a30..2f8e1d3 100644 --- a/.envrc +++ b/.envrc @@ -1 +1 @@ -use flake +use flake --impure diff --git a/flake.nix b/flake.nix index 8386939..687120b 100644 --- a/flake.nix +++ b/flake.nix @@ -30,36 +30,34 @@ cargo = rust; }); + buildInputs = 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; [ - (rust.override { extensions = ["rust-src" "rust-analyzer"]; }) pkg-config cmake python312 ]; - 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 ]); + mkRustVulkanShell = { nixGLSupport ? true }: pkgs.mkShell { + nativeBuildInputs = with pkgs; [ + (rust.override { extensions = ["rust-src" "rust-analyzer"]; }) + ] ++ nativeBuildInputs; + + buildInputs = buildInputs + ++ pkgs.lib.optionals nixGLSupport [ pkgs.nixgl.auto.nixVulkanNvidia pkgs.nixgl.nixVulkanIntel ]; + + LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath buildInputs; + VK_LAYER_PATH = "${pkgs.vulkan-validation-layers}/share/vulkan/explicit_layer.d"; + }; in { devShells = { - default = pkgs.mkShell { - inherit nativeBuildInputs; + default = mkRustVulkanShell {}; - buildInputs = libs; - - LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath (with pkgs; [ libxkbcommon wayland libGL ]); - }; - - with_compatibility = pkgs.mkShell { - inherit nativeBuildInputs; - - buildInputs = libs ++ [ - pkgs.nixgl.auto.nixVulkanNvidia pkgs.nixgl.nixVulkanIntel - ]; - - LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath (with pkgs; [ libxkbcommon wayland libGL ]); - }; + # Crash with error: cannot coerce null to a string: null + nixos = mkRustVulkanShell { nixGLSupport = false; }; }; packages = { @@ -69,8 +67,7 @@ src = self; - nativeBuildInputs = with pkgs; [ pkg-config shaderc ]; - buildInputs = libs; + inherit nativeBuildInputs buildInputs; cargoLock = { lockFile = ./Cargo.lock; diff --git a/src/renderer/app.rs b/src/renderer/app.rs index 9788aa2..0c562fd 100644 --- a/src/renderer/app.rs +++ b/src/renderer/app.rs @@ -52,8 +52,6 @@ impl App { enabled_extensions: required_extensions, enabled_layers: vec![ String::from("VK_LAYER_KHRONOS_validation"), - String::from("VK_LAYER_MANGOHUD_overlay_x86_64"), - String::from("VK_LAYER_NV_optimus"), ], ..Default::default() }, From 34ec2894df4b5da47f337efaedf962dbe83a7f8c Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Thu, 9 Jan 2025 15:33:33 +0100 Subject: [PATCH 17/41] Use nixGl auto detection fork to fix NixOS (open source NVIDIA) --- flake.lock | 11 ++++++----- flake.nix | 29 +++++++++++++---------------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/flake.lock b/flake.lock index 9ff2d00..2a584fa 100644 --- a/flake.lock +++ b/flake.lock @@ -28,15 +28,16 @@ ] }, "locked": { - "lastModified": 1713543440, - "narHash": "sha256-lnzZQYG0+EXl/6NkGpyIz+FEOc/DSEG57AP1VsdeNrM=", - "owner": "nix-community", + "lastModified": 1735283791, + "narHash": "sha256-JlT4VFs8aVlW+l151HZIZumfFsccZXcO/k5WpbYF09Y=", + "owner": "phirsch", "repo": "nixGL", - "rev": "310f8e49a149e4c9ea52f1adf70cdc768ec53f8a", + "rev": "ea8baea3b9d854bf9cf5c834a805c50948dd2603", "type": "github" }, "original": { - "owner": "nix-community", + "owner": "phirsch", + "ref": "fix-versionMatch", "repo": "nixGL", "type": "github" } diff --git a/flake.nix b/flake.nix index 687120b..1b38c42 100644 --- a/flake.nix +++ b/flake.nix @@ -9,7 +9,8 @@ inputs.nixpkgs.follows = "nixpkgs"; }; nixgl = { - url = "github:nix-community/nixGL"; + # Revert this to community version when https://github.com/nix-community/nixGL/pull/187 is merged + url = "github:phirsch/nixGL/fix-versionMatch"; inputs.nixpkgs.follows = "nixpkgs"; inputs.flake-utils.follows = "flake-utils"; }; @@ -39,25 +40,21 @@ cmake python312 ]; - - mkRustVulkanShell = { nixGLSupport ? true }: pkgs.mkShell { - nativeBuildInputs = with pkgs; [ - (rust.override { extensions = ["rust-src" "rust-analyzer"]; }) - ] ++ nativeBuildInputs; - - buildInputs = buildInputs - ++ pkgs.lib.optionals nixGLSupport [ pkgs.nixgl.auto.nixVulkanNvidia pkgs.nixgl.nixVulkanIntel ]; - - LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath buildInputs; - VK_LAYER_PATH = "${pkgs.vulkan-validation-layers}/share/vulkan/explicit_layer.d"; - }; in { devShells = { - default = mkRustVulkanShell {}; + default = pkgs.mkShell { + nativeBuildInputs = with pkgs; [ + (rust.override { extensions = [ "rust-src" "rust-analyzer" ]; }) + ] ++ nativeBuildInputs; - # Crash with error: cannot coerce null to a string: null - nixos = mkRustVulkanShell { nixGLSupport = false; }; + buildInputs = buildInputs + ++ [ pkgs.nixgl.auto.nixVulkanNvidia pkgs.nixgl.nixVulkanMesa ]; + + LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath buildInputs; + VK_LAYER_PATH = "${pkgs.vulkan-validation-layers}/share/vulkan/explicit_layer.d"; + RUST_LOG = "info,rust_vulkan_test=trace"; + }; }; packages = { From 7d6b6ea3709827f4cdeb8aa005309b5504a6e407 Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Wed, 19 Feb 2025 12:48:36 +0100 Subject: [PATCH 18/41] Update vulkan crates --- Cargo.lock | 202 ++++++++++++++++++++++++++++------------------------- Cargo.toml | 4 +- 2 files changed, 110 insertions(+), 96 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 78fdb0b..4e01f8e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -47,7 +47,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" dependencies = [ "android-properties", - "bitflags 2.6.0", + "bitflags 2.8.0", "cc", "cesu8", "jni", @@ -108,19 +108,20 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "3.0.6" +version = "3.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" dependencies = [ "anstyle", + "once_cell", "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" [[package]] name = "arrayref" @@ -169,9 +170,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" [[package]] name = "block2" @@ -190,18 +191,18 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytemuck" -version = "1.20.0" +version = "1.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" +checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec" +checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a" dependencies = [ "proc-macro2", "quote", @@ -220,7 +221,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "log", "polling", "rustix", @@ -242,9 +243,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.4" +version = "1.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf" +checksum = "c8293772165d9345bdaaa39b45b2109591e63fe5e6fbc23c6ff930a048aa310b" dependencies = [ "jobserver", "libc", @@ -399,9 +400,9 @@ checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" [[package]] name = "env_filter" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" dependencies = [ "log", "regex", @@ -409,9 +410,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0" dependencies = [ "anstream", "anstyle", @@ -438,9 +439,9 @@ dependencies = [ [[package]] name = "foldhash" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" +checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" [[package]] name = "foreign-types" @@ -586,9 +587,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.76" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ "once_cell", "wasm-bindgen", @@ -596,9 +597,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.168" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "libloading" @@ -616,16 +617,16 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "libc", "redox_syscall 0.5.8", ] [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "lock_api" @@ -639,9 +640,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.22" +version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" [[package]] name = "memchr" @@ -670,7 +671,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "jni-sys", "log", "ndk-sys", @@ -747,7 +748,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "block2", "libc", "objc2", @@ -763,7 +764,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "block2", "objc2", "objc2-core-location", @@ -787,7 +788,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "block2", "objc2", "objc2-foundation", @@ -829,7 +830,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "block2", "dispatch", "libc", @@ -854,7 +855,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "block2", "objc2", "objc2-foundation", @@ -866,7 +867,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "block2", "objc2", "objc2-foundation", @@ -889,7 +890,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "block2", "objc2", "objc2-cloud-kit", @@ -921,7 +922,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "block2", "objc2", "objc2-core-location", @@ -983,18 +984,18 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" +checksum = "1e2ec53ad785f4d35dac0adea7f7dc6f1bb277ad84a680c7afefeae05d1f5916" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" +checksum = "d56a66c0c55993aa927429d0f8a0abfd74f084e4d9c192cffed01e418d83eefb" dependencies = [ "proc-macro2", "quote", @@ -1003,9 +1004,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pkg-config" @@ -1039,9 +1040,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.92" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] @@ -1057,9 +1058,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -1096,7 +1097,7 @@ version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", ] [[package]] @@ -1152,17 +1153,23 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.42" +version = "0.38.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" +checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "errno", "libc", "linux-raw-sys", "windows-sys 0.59.0", ] +[[package]] +name = "rustversion" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" + [[package]] name = "ryu" version = "1.0.18" @@ -1205,18 +1212,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.216" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.216" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", @@ -1225,9 +1232,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.133" +version = "1.0.135" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9" dependencies = [ "itoa", "memchr", @@ -1289,7 +1296,7 @@ version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "calloop", "calloop-wayland-source", "cursor-icon", @@ -1325,9 +1332,9 @@ checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" [[package]] name = "syn" -version = "2.0.90" +version = "2.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" dependencies = [ "proc-macro2", "quote", @@ -1463,8 +1470,9 @@ dependencies = [ [[package]] name = "vulkano" -version = "0.34.0" -source = "git+https://github.com/vulkano-rs/vulkano.git?branch=master#ea30f65280360b1e1bc907cd42d4eb355fed3c9d" +version = "0.35.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08840c2b51759a6f88f26f5ea378bc8b5c199a5b4760ddda292304be087249c4" dependencies = [ "ash", "bytemuck", @@ -1494,8 +1502,9 @@ dependencies = [ [[package]] name = "vulkano-macros" -version = "0.34.0" -source = "git+https://github.com/vulkano-rs/vulkano.git?branch=master#ea30f65280360b1e1bc907cd42d4eb355fed3c9d" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dc929c42c9336fd082079ac3ea30126e4a0dfe36fd2e2b3581303f7d140d20f" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -1505,8 +1514,9 @@ dependencies = [ [[package]] name = "vulkano-shaders" -version = "0.34.0" -source = "git+https://github.com/vulkano-rs/vulkano.git?branch=master#ea30f65280360b1e1bc907cd42d4eb355fed3c9d" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bf501461be7cef2893c0e62c50945add9763cc482051d29053f6157089d5ea9" dependencies = [ "foldhash", "heck", @@ -1535,20 +1545,21 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", @@ -1560,9 +1571,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.49" +version = "0.4.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" dependencies = [ "cfg-if", "js-sys", @@ -1573,9 +1584,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1583,9 +1594,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", @@ -1596,9 +1607,12 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] name = "wayland-backend" @@ -1620,7 +1634,7 @@ version = "0.31.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b66249d3fc69f76fd74c82cc319300faa554e9d865dab1f7cd66cc20db10b280" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "rustix", "wayland-backend", "wayland-scanner", @@ -1632,7 +1646,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "cursor-icon", "wayland-backend", ] @@ -1654,7 +1668,7 @@ version = "0.32.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7cd0ade57c4e6e9a8952741325c30bf82f4246885dca8bf561898b86d0c1f58e" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "wayland-backend", "wayland-client", "wayland-scanner", @@ -1666,7 +1680,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b31cab548ee68c7eb155517f2212049dc151f7cd7910c2b66abfd31c3ee12bd" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "wayland-backend", "wayland-client", "wayland-protocols", @@ -1679,7 +1693,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "782e12f6cd923c3c316130d56205ebab53f55d6666b7faddfad36cecaeeb4022" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "wayland-backend", "wayland-client", "wayland-protocols", @@ -1711,9 +1725,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.76" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" dependencies = [ "js-sys", "wasm-bindgen", @@ -1945,14 +1959,14 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winit" -version = "0.30.5" +version = "0.30.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0be9e76a1f1077e04a411f0b989cbd3c93339e1771cb41e71ac4aee95bfd2c67" +checksum = "f5d74280aabb958072864bff6cfbcf9025cf8bfacdde5e32b5e12920ef703b0f" dependencies = [ "ahash", "android-activity", "atomic-waker", - "bitflags 2.6.0", + "bitflags 2.8.0", "block2", "bytemuck", "calloop", @@ -1997,9 +2011,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.20" +version = "0.6.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" dependencies = [ "memchr", ] @@ -2048,7 +2062,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "dlib", "log", "once_cell", @@ -2063,9 +2077,9 @@ checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" [[package]] name = "xml-rs" -version = "0.8.24" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea8b391c9a790b496184c29f7f93b9ed5b16abb306c05415b68bcc16e4d06432" +checksum = "c5b940ebc25896e71dd073bad2dbaa2abfe97b0a391415e22ad1326d9c54e3c4" [[package]] name = "xmlparser" diff --git a/Cargo.toml b/Cargo.toml index 62dde55..e1de2ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,8 +9,8 @@ publish = false anyhow = "1.0" winit = { version = "0.30", features = ["rwh_06"] } -vulkano = { git = "https://github.com/vulkano-rs/vulkano.git", branch = "master" } -vulkano-shaders = { git = "https://github.com/vulkano-rs/vulkano.git", branch = "master" } +vulkano = "0.35" +vulkano-shaders = "0.35" # Math glam = { version = "0.29" } From 011b4c27c1b6eefd5e4dcba8d38cb404d87d9530 Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Wed, 19 Feb 2025 12:57:02 +0100 Subject: [PATCH 19/41] Update rust version to 1.84.1 --- flake.lock | 18 +++++++++--------- rust-toolchain.toml | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/flake.lock b/flake.lock index 2a584fa..6484a8a 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1726560853, - "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", "owner": "numtide", "repo": "flake-utils", - "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", "type": "github" }, "original": { @@ -44,11 +44,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1730831018, - "narHash": "sha256-2S0HwIFRxYp+afuoFORcZA9TjryAf512GmE0MTfEOPU=", + "lastModified": 1739863612, + "narHash": "sha256-UbtgxplOhFcyjBcNbTVO8+HUHAl/WXFDOb6LvqShiZo=", "owner": "nixos", "repo": "nixpkgs", - "rev": "8c4dc69b9732f6bbe826b5fbb32184987520ff26", + "rev": "632f04521e847173c54fa72973ec6c39a371211c", "type": "github" }, "original": { @@ -73,11 +73,11 @@ ] }, "locked": { - "lastModified": 1730860036, - "narHash": "sha256-u0sfA4B65Q9cRO3xpIkQ4nldB8isfdIb3rWtsnRZ+Iw=", + "lastModified": 1739932111, + "narHash": "sha256-WkayjH0vuGw0hx2gmjTUGFRvMKpM17gKcpL/U8EUUw0=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "b8eb3aeb21629cbe14968a5e3b1cbaefb0d1b260", + "rev": "75b2271c5c087d830684cd5462d4410219acc367", "type": "github" }, "original": { diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 2e2b8c8..fcb78ec 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "1.82.0" +channel = "1.84.1" From 752f5ab2b1626b1def0812a2cfd45ba6dcf02cb8 Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Fri, 14 Mar 2025 13:08:24 +0100 Subject: [PATCH 20/41] Update rust version to 1.85.0 --- rust-toolchain.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index fcb78ec..c1bc0a6 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "1.84.1" +channel = "1.85.0" From e267be066ad4c505d3a97b67c3b8f713844d737a Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Fri, 14 Mar 2025 13:08:54 +0100 Subject: [PATCH 21/41] Update cargo lock --- Cargo.lock | 416 ++++++++++++++++++++++++++++++++--------------------- flake.lock | 12 +- 2 files changed, 258 insertions(+), 170 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4e01f8e..38d2f44 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "ab_glyph" @@ -47,7 +47,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" dependencies = [ "android-properties", - "bitflags 2.8.0", + "bitflags 2.9.0", "cc", "cesu8", "jni", @@ -119,9 +119,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.95" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" +checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" [[package]] name = "arrayref" @@ -170,9 +170,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" [[package]] name = "block2" @@ -180,20 +180,20 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" dependencies = [ - "objc2", + "objc2 0.5.2", ] [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "bytemuck" -version = "1.21.0" +version = "1.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" +checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540" dependencies = [ "bytemuck_derive", ] @@ -211,9 +211,9 @@ dependencies = [ [[package]] name = "bytes" -version = "1.9.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "calloop" @@ -221,7 +221,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "log", "polling", "rustix", @@ -243,9 +243,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.9" +version = "1.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8293772165d9345bdaaa39b45b2109591e63fe5e6fbc23c6ff930a048aa310b" +checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" dependencies = [ "jobserver", "libc", @@ -272,9 +272,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "cmake" -version = "0.1.52" +version = "0.1.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c682c223677e0e5b6b7f63a64b9351844c3f1b1678a68b7ee617e30fb082620e" +checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" dependencies = [ "cc", ] @@ -361,9 +361,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" [[package]] name = "cursor-icon" @@ -410,22 +410,22 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.6" +version = "0.11.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0" +checksum = "c3716d7a920fb4fac5d84e9d4bce8ceb321e9414b4409da61b07b75c1e3d0697" dependencies = [ "anstream", "anstyle", "env_filter", - "humantime", + "jiff", "log", ] [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" @@ -499,9 +499,9 @@ checksum = "dc46dd3ec48fdd8e693a98d2b8bafae273a2d54c1de02a2a7e3d57d501f39677" [[package]] name = "half" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +checksum = "7db2ff139bba50379da6aa0766b52fdcb62cb5b263009b09ed58ba604e14bbd1" dependencies = [ "bytemuck", "cfg-if", @@ -526,17 +526,11 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - [[package]] name = "indexmap" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" dependencies = [ "equivalent", "hashbrown", @@ -550,9 +544,33 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itoa" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "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" @@ -597,9 +615,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.169" +version = "0.2.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" [[package]] name = "libloading" @@ -617,9 +635,9 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "libc", - "redox_syscall 0.5.8", + "redox_syscall 0.5.10", ] [[package]] @@ -640,9 +658,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.25" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" +checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" [[package]] name = "memchr" @@ -671,7 +689,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "jni-sys", "log", "ndk-sys", @@ -742,20 +760,29 @@ 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.8.0", + "bitflags 2.9.0", "block2", "libc", - "objc2", + "objc2 0.5.2", "objc2-core-data", "objc2-core-image", - "objc2-foundation", - "objc2-quartz-core", + "objc2-foundation 0.2.2", + "objc2-quartz-core 0.2.2", ] [[package]] @@ -764,11 +791,11 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "block2", - "objc2", + "objc2 0.5.2", "objc2-core-location", - "objc2-foundation", + "objc2-foundation 0.2.2", ] [[package]] @@ -778,8 +805,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" dependencies = [ "block2", - "objc2", - "objc2-foundation", + "objc2 0.5.2", + "objc2-foundation 0.2.2", ] [[package]] @@ -788,10 +815,20 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "block2", - "objc2", - "objc2-foundation", + "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", ] [[package]] @@ -801,9 +838,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" dependencies = [ "block2", - "objc2", - "objc2-foundation", - "objc2-metal", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "objc2-metal 0.2.2", ] [[package]] @@ -813,16 +850,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" dependencies = [ "block2", - "objc2", + "objc2 0.5.2", "objc2-contacts", - "objc2-foundation", + "objc2-foundation 0.2.2", ] [[package]] name = "objc2-encode" -version = "4.0.3" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7891e71393cd1f227313c9379a26a584ff3d7e6e7159e988851f0934c993f0f8" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" [[package]] name = "objc2-foundation" @@ -830,11 +867,22 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "block2", "dispatch", "libc", - "objc2", + "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", ] [[package]] @@ -844,9 +892,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" dependencies = [ "block2", - "objc2", + "objc2 0.5.2", "objc2-app-kit", - "objc2-foundation", + "objc2-foundation 0.2.2", ] [[package]] @@ -855,10 +903,21 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "block2", - "objc2", - "objc2-foundation", + "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", ] [[package]] @@ -867,11 +926,24 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "block2", - "objc2", - "objc2-foundation", - "objc2-metal", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "objc2-metal 0.2.2", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.3.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", ] [[package]] @@ -880,8 +952,8 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc" dependencies = [ - "objc2", - "objc2-foundation", + "objc2 0.5.2", + "objc2-foundation 0.2.2", ] [[package]] @@ -890,16 +962,16 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "block2", - "objc2", + "objc2 0.5.2", "objc2-cloud-kit", "objc2-core-data", "objc2-core-image", "objc2-core-location", - "objc2-foundation", + "objc2-foundation 0.2.2", "objc2-link-presentation", - "objc2-quartz-core", + "objc2-quartz-core 0.2.2", "objc2-symbols", "objc2-uniform-type-identifiers", "objc2-user-notifications", @@ -912,8 +984,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" dependencies = [ "block2", - "objc2", - "objc2-foundation", + "objc2 0.5.2", + "objc2-foundation 0.2.2", ] [[package]] @@ -922,18 +994,18 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "block2", - "objc2", + "objc2 0.5.2", "objc2-core-location", - "objc2-foundation", + "objc2-foundation 0.2.2", ] [[package]] name = "once_cell" -version = "1.20.2" +version = "1.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc" [[package]] name = "orbclient" @@ -971,7 +1043,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.8", + "redox_syscall 0.5.10", "smallvec", "windows-targets 0.52.6", ] @@ -984,18 +1056,18 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project" -version = "1.1.8" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e2ec53ad785f4d35dac0adea7f7dc6f1bb277ad84a680c7afefeae05d1f5916" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.8" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56a66c0c55993aa927429d0f8a0abfd74f084e4d9c192cffed01e418d83eefb" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", @@ -1010,9 +1082,9 @@ checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pkg-config" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "polling" @@ -1030,37 +1102,52 @@ dependencies = [ ] [[package]] -name = "proc-macro-crate" -version = "3.2.0" +name = "portable-atomic" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "proc-macro-crate" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" dependencies = [ "toml_edit", ] [[package]] name = "proc-macro2" -version = "1.0.93" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" dependencies = [ "unicode-ident", ] [[package]] name = "quick-xml" -version = "0.36.2" +version = "0.37.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe" +checksum = "165859e9e55f79d67b96c5d96f4e88b6f2695a1972849c15a6a3f5c59fc2c003" dependencies = [ "memchr", ] [[package]] name = "quote" -version = "1.0.38" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] @@ -1073,13 +1160,14 @@ checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" [[package]] name = "raw-window-metal" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2000e45d7daa9b6d946e88dfa1d7ae330424a81918a6545741821c989eb80a9" +checksum = "40d213455a5f1dc59214213c7330e074ddf8114c9a42411eb890c767357ce135" dependencies = [ - "objc2", - "objc2-foundation", - "objc2-quartz-core", + "objc2 0.6.0", + "objc2-core-foundation", + "objc2-foundation 0.3.0", + "objc2-quartz-core 0.3.0", ] [[package]] @@ -1093,11 +1181,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.8" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" +checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", ] [[package]] @@ -1153,11 +1241,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.43" +version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "errno", "libc", "linux-raw-sys", @@ -1166,15 +1254,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "same-file" @@ -1212,18 +1300,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.217" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.217" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", @@ -1232,9 +1320,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.135" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa", "memchr", @@ -1280,15 +1368,15 @@ dependencies = [ [[package]] name = "slabbin" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd33b7a607dbd960b5e78bb4740d1f86e84250eb03a12960ee1482c2a256063" +checksum = "9db491c0d4152a069911a0fbdaca959691bf0b9d7110d98a7ed1c8e59b79ab30" [[package]] name = "smallvec" -version = "1.13.2" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" [[package]] name = "smithay-client-toolkit" @@ -1296,7 +1384,7 @@ version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "calloop", "calloop-wayland-source", "cursor-icon", @@ -1332,9 +1420,9 @@ checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" [[package]] name = "syn" -version = "2.0.96" +version = "2.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" dependencies = [ "proc-macro2", "quote", @@ -1404,9 +1492,9 @@ checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" [[package]] name = "toml_edit" -version = "0.22.22" +version = "0.22.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" dependencies = [ "indexmap", "toml_datetime", @@ -1437,9 +1525,9 @@ checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" [[package]] name = "unicode-ident" -version = "1.0.14" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-segmentation" @@ -1616,9 +1704,9 @@ dependencies = [ [[package]] name = "wayland-backend" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "056535ced7a150d45159d3a8dc30f91a2e2d588ca0b23f70e56033622b8016f6" +checksum = "b7208998eaa3870dad37ec8836979581506e0c5c64c20c9e79e9d2a10d6f47bf" dependencies = [ "cc", "downcast-rs", @@ -1630,11 +1718,11 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.31.7" +version = "0.31.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66249d3fc69f76fd74c82cc319300faa554e9d865dab1f7cd66cc20db10b280" +checksum = "c2120de3d33638aaef5b9f4472bff75f07c56379cf76ea320bd3a3d65ecaf73f" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "rustix", "wayland-backend", "wayland-scanner", @@ -1646,16 +1734,16 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "cursor-icon", "wayland-backend", ] [[package]] name = "wayland-cursor" -version = "0.31.7" +version = "0.31.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b08bc3aafdb0035e7fe0fdf17ba0c09c268732707dca4ae098f60cb28c9e4c" +checksum = "a93029cbb6650748881a00e4922b076092a6a08c11e7fbdb923f064b23968c5d" dependencies = [ "rustix", "wayland-client", @@ -1664,11 +1752,11 @@ dependencies = [ [[package]] name = "wayland-protocols" -version = "0.32.5" +version = "0.32.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd0ade57c4e6e9a8952741325c30bf82f4246885dca8bf561898b86d0c1f58e" +checksum = "0781cf46869b37e36928f7b432273c0995aa8aed9552c556fb18754420541efc" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "wayland-backend", "wayland-client", "wayland-scanner", @@ -1676,11 +1764,11 @@ dependencies = [ [[package]] name = "wayland-protocols-plasma" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b31cab548ee68c7eb155517f2212049dc151f7cd7910c2b66abfd31c3ee12bd" +checksum = "7ccaacc76703fefd6763022ac565b590fcade92202492381c95b2edfdf7d46b3" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "wayland-backend", "wayland-client", "wayland-protocols", @@ -1689,11 +1777,11 @@ dependencies = [ [[package]] name = "wayland-protocols-wlr" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "782e12f6cd923c3c316130d56205ebab53f55d6666b7faddfad36cecaeeb4022" +checksum = "248a02e6f595aad796561fa82d25601bd2c8c3b145b1c7453fc8f94c1a58f8b2" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "wayland-backend", "wayland-client", "wayland-protocols", @@ -1702,9 +1790,9 @@ dependencies = [ [[package]] name = "wayland-scanner" -version = "0.31.5" +version = "0.31.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597f2001b2e5fc1121e3d5b9791d3e78f05ba6bfa4641053846248e3a13661c3" +checksum = "896fdafd5d28145fce7958917d69f2fd44469b1d4e861cb5961bcbeebc6d1484" dependencies = [ "proc-macro2", "quick-xml", @@ -1713,9 +1801,9 @@ dependencies = [ [[package]] name = "wayland-sys" -version = "0.31.5" +version = "0.31.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efa8ac0d8e8ed3e3b5c9fc92c7881406a268e11555abe36493efabe649a29e09" +checksum = "dbcebb399c77d5aa9fa5db874806ee7b4eba4e73650948e8f93963f128896615" dependencies = [ "dlib", "log", @@ -1959,14 +2047,14 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winit" -version = "0.30.8" +version = "0.30.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5d74280aabb958072864bff6cfbcf9025cf8bfacdde5e32b5e12920ef703b0f" +checksum = "a809eacf18c8eca8b6635091543f02a5a06ddf3dad846398795460e6e0ae3cc0" dependencies = [ "ahash", "android-activity", "atomic-waker", - "bitflags 2.8.0", + "bitflags 2.9.0", "block2", "bytemuck", "calloop", @@ -1980,9 +2068,9 @@ dependencies = [ "libc", "memmap2", "ndk", - "objc2", + "objc2 0.5.2", "objc2-app-kit", - "objc2-foundation", + "objc2-foundation 0.2.2", "objc2-ui-kit", "orbclient", "percent-encoding", @@ -2011,9 +2099,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.24" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" +checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36" dependencies = [ "memchr", ] @@ -2062,7 +2150,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.9.0", "dlib", "log", "once_cell", diff --git a/flake.lock b/flake.lock index 6484a8a..6b2b086 100644 --- a/flake.lock +++ b/flake.lock @@ -44,11 +44,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1739863612, - "narHash": "sha256-UbtgxplOhFcyjBcNbTVO8+HUHAl/WXFDOb6LvqShiZo=", + "lastModified": 1741865919, + "narHash": "sha256-4thdbnP6dlbdq+qZWTsm4ffAwoS8Tiq1YResB+RP6WE=", "owner": "nixos", "repo": "nixpkgs", - "rev": "632f04521e847173c54fa72973ec6c39a371211c", + "rev": "573c650e8a14b2faa0041645ab18aed7e60f0c9a", "type": "github" }, "original": { @@ -73,11 +73,11 @@ ] }, "locked": { - "lastModified": 1739932111, - "narHash": "sha256-WkayjH0vuGw0hx2gmjTUGFRvMKpM17gKcpL/U8EUUw0=", + "lastModified": 1741919466, + "narHash": "sha256-xto0Oq+WItjDZvafo6ZVI4TZa6/2oxJHb0tkcSGVUJI=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "75b2271c5c087d830684cd5462d4410219acc367", + "rev": "8b137260b776525542d47d3a4dbac753df478a42", "type": "github" }, "original": { From 6b6534df763f4ebb12b2904e5f214b974ba051e1 Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Fri, 14 Mar 2025 17:03:59 +0100 Subject: [PATCH 22/41] Add apecs + update glam --- Cargo.lock | 254 ++++++++++++++++++++++++++++++++++++++++++++++++++--- Cargo.toml | 5 +- 2 files changed, 244 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 38d2f44..e69aec8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -117,12 +117,48 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "any_vec" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6ac04794a7749710e3c7f3c93222e3d04692993b69876d69393efd2565401a" + [[package]] name = "anyhow" version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" +[[package]] +name = "apecs" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6df7760d4baebb17003dcf99134d8e3a63f487e146d58911f0bcd27afb185d1c" +dependencies = [ + "any_vec", + "apecs-derive", + "async-channel", + "itertools", + "log", + "moongraph", + "parking_lot", + "rayon", + "smallvec", + "snafu 0.8.5", +] + +[[package]] +name = "apecs-derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc0f3ddfd31fd5276fb8039b75dc4d284c21213757a969e480c6ef8fde494f3b" +dependencies = [ + "moongraph-macros-syntax", + "proc-macro2", + "quote", + "syn 2.0.100", +] + [[package]] name = "arrayref" version = "0.3.9" @@ -150,6 +186,17 @@ dependencies = [ "libloading", ] +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -183,6 +230,17 @@ dependencies = [ "objc2 0.5.2", ] +[[package]] +name = "broomdog" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ec65645d8167b03c07e049f114a878a11ab889f20c071d6f7b30bf88fbe5af" +dependencies = [ + "log", + "rustc-hash", + "snafu 0.8.5", +] + [[package]] name = "bumpalo" version = "3.17.0" @@ -206,7 +264,7 @@ checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.100", ] [[package]] @@ -344,6 +402,25 @@ dependencies = [ "libc", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-queue" version = "0.3.12" @@ -371,6 +448,17 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" +[[package]] +name = "dagga" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04cf0d7dcd307c9c5d81277737c35d1faf08af9e2cb262966a01c91021686b68" +dependencies = [ + "log", + "rustc-hash", + "snafu 0.7.5", +] + [[package]] name = "dispatch" version = "0.2.0" @@ -386,6 +474,12 @@ dependencies = [ "libloading", ] +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + [[package]] name = "downcast-rs" version = "1.2.1" @@ -398,6 +492,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + [[package]] name = "env_filter" version = "0.1.3" @@ -437,6 +537,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + [[package]] name = "foldhash" version = "0.1.4" @@ -461,7 +567,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.100", ] [[package]] @@ -470,6 +576,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + [[package]] name = "gethostname" version = "0.4.3" @@ -493,9 +605,9 @@ dependencies = [ [[package]] name = "glam" -version = "0.29.2" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc46dd3ec48fdd8e693a98d2b8bafae273a2d54c1de02a2a7e3d57d501f39677" +checksum = "17fcdf9683c406c2fc4d124afd29c0d595e22210d633cbdb8695ba9935ab1dc6" [[package]] name = "half" @@ -542,6 +654,15 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.15" @@ -569,7 +690,7 @@ checksum = "8d16e75759ee0aa64c57a56acbf43916987b20c77373cb7e808979e02b93c9f9" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.100", ] [[package]] @@ -683,6 +804,30 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "moongraph" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5a4b09eb96a84205062b48ec5469c8c35c128167e838aa73dc620c4411af598" +dependencies = [ + "broomdog", + "dagga", + "log", + "rayon", + "snafu 0.8.5", +] + +[[package]] +name = "moongraph-macros-syntax" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08112087acc92cc28fb5d8f7bda1307123ecc9a275ed4835f1c03f1a8dd02c1d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + [[package]] name = "ndk" version = "0.9.0" @@ -741,7 +886,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 2.0.100", ] [[package]] @@ -1071,7 +1216,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.100", ] [[package]] @@ -1170,6 +1315,26 @@ dependencies = [ "objc2-quartz-core 0.3.0", ] +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "redox_syscall" version = "0.4.1" @@ -1231,6 +1396,7 @@ name = "rust_vulkan_test" version = "0.1.0" dependencies = [ "anyhow", + "apecs", "env_logger", "glam", "log", @@ -1239,6 +1405,12 @@ dependencies = [ "winit", ] +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustix" version = "0.38.44" @@ -1315,7 +1487,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.100", ] [[package]] @@ -1412,12 +1584,66 @@ dependencies = [ "serde", ] +[[package]] +name = "snafu" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4de37ad025c587a29e8f3f5605c00f70b98715ef90b9061a815b9e59e9042d6" +dependencies = [ + "doc-comment", + "snafu-derive 0.7.5", +] + +[[package]] +name = "snafu" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "223891c85e2a29c3fe8fb900c1fae5e69c2e42415e3177752e8718475efa5019" +dependencies = [ + "snafu-derive 0.8.5", +] + +[[package]] +name = "snafu-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990079665f075b699031e9c08fd3ab99be5029b96f3b78dc0709e8f77e4efebf" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "snafu-derive" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c3c6b7927ffe7ecaa769ee0e3994da3b8cafc8f444578982c83ecb161af917" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.100", +] + [[package]] name = "strict-num" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.100" @@ -1446,7 +1672,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.100", ] [[package]] @@ -1597,7 +1823,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn", + "syn 2.0.100", ] [[package]] @@ -1611,7 +1837,7 @@ dependencies = [ "proc-macro2", "quote", "shaderc", - "syn", + "syn 2.0.100", "vulkano", ] @@ -1653,7 +1879,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn", + "syn 2.0.100", "wasm-bindgen-shared", ] @@ -1688,7 +1914,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.100", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2192,5 +2418,5 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.100", ] diff --git a/Cargo.toml b/Cargo.toml index e1de2ee..11b5243 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,10 @@ vulkano = "0.35" vulkano-shaders = "0.35" # Math -glam = { version = "0.29" } +glam = { version = "0.30" } + +# ECS +apecs = "0.8" # Log and tracing log = "0.4" From 1d0ef32f60f349599fb3c27543d558a072735e44 Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Fri, 21 Mar 2025 17:13:27 +0100 Subject: [PATCH 23/41] Try add renderdoc vulkan layer --- flake.nix | 5 +++-- src/renderer/app.rs | 9 ++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/flake.nix b/flake.nix index 1b38c42..981454a 100644 --- a/flake.nix +++ b/flake.nix @@ -31,7 +31,7 @@ cargo = rust; }); - buildInputs = with pkgs; [ vulkan-headers vulkan-loader vulkan-validation-layers ] + buildInputs = with pkgs; [ vulkan-headers vulkan-loader vulkan-validation-layers renderdoc ] ++ 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 ]); @@ -45,6 +45,7 @@ devShells = { default = pkgs.mkShell { nativeBuildInputs = with pkgs; [ + renderdoc (rust.override { extensions = [ "rust-src" "rust-analyzer" ]; }) ] ++ nativeBuildInputs; @@ -52,7 +53,7 @@ ++ [ pkgs.nixgl.auto.nixVulkanNvidia pkgs.nixgl.nixVulkanMesa ]; LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath buildInputs; - VK_LAYER_PATH = "${pkgs.vulkan-validation-layers}/share/vulkan/explicit_layer.d"; + VK_LAYER_PATH = "${pkgs.vulkan-validation-layers}/share/vulkan/explicit_layer.d:${pkgs.renderdoc}/share/vulkan/implicit_layer.d"; RUST_LOG = "info,rust_vulkan_test=trace"; }; }; diff --git a/src/renderer/app.rs b/src/renderer/app.rs index 0c562fd..3287f7d 100644 --- a/src/renderer/app.rs +++ b/src/renderer/app.rs @@ -41,6 +41,10 @@ impl App { pub fn new(event_loop: &EventLoop<()>) -> Self { let library = VulkanLibrary::new().unwrap(); + for layer in library.layer_properties().unwrap() { + log::debug!("Available layer: {}", layer.name()); + } + let required_extensions = Surface::required_extensions(event_loop).unwrap(); let instance = Instance::new( @@ -52,6 +56,7 @@ impl App { enabled_extensions: required_extensions, enabled_layers: vec![ String::from("VK_LAYER_KHRONOS_validation"), + String::from("VK_LAYER_RENDERDOC_Capture"), ], ..Default::default() }, @@ -90,7 +95,7 @@ impl App { }) .expect("no suitable physical device found"); - println!( + log::debug!( "Using device: {} (type: {:?})", physical_device.properties().device_name, physical_device.properties().device_type, @@ -100,6 +105,8 @@ impl App { device_extensions.khr_dynamic_rendering = true; } + log::debug!("Using device extensions: {:#?}", device_extensions); + let (device, mut queues) = Device::new( physical_device, DeviceCreateInfo { From 30721773c890f58fe65095a437ff12d9fa53585b Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Sat, 22 Mar 2025 21:51:21 +0100 Subject: [PATCH 24/41] First renderdoc run without wayland --- Cargo.toml | 2 +- flake.lock | 12 ++++++------ flake.nix | 40 ++++++++++++++++++++++++++-------------- rust-toolchain.toml | 2 +- src/renderer/app.rs | 5 +---- 5 files changed, 35 insertions(+), 26 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 11b5243..ba7eb9d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rust_vulkan_test" version = "0.1.0" -edition = "2021" +edition = "2024" authors = ["Florian RICHER "] publish = false diff --git a/flake.lock b/flake.lock index 6b2b086..2853bb7 100644 --- a/flake.lock +++ b/flake.lock @@ -44,11 +44,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1741865919, - "narHash": "sha256-4thdbnP6dlbdq+qZWTsm4ffAwoS8Tiq1YResB+RP6WE=", + "lastModified": 1742546557, + "narHash": "sha256-QyhimDBaDBtMfRc7kyL28vo+HTwXRPq3hz+BgSJDotw=", "owner": "nixos", "repo": "nixpkgs", - "rev": "573c650e8a14b2faa0041645ab18aed7e60f0c9a", + "rev": "bfa9810ff7104a17555ab68ebdeafb6705f129b1", "type": "github" }, "original": { @@ -73,11 +73,11 @@ ] }, "locked": { - "lastModified": 1741919466, - "narHash": "sha256-xto0Oq+WItjDZvafo6ZVI4TZa6/2oxJHb0tkcSGVUJI=", + "lastModified": 1742524367, + "narHash": "sha256-KzTwk/5ETJavJZYV1DEWdCx05M4duFCxCpRbQSKWpng=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "8b137260b776525542d47d3a4dbac753df478a42", + "rev": "70bf752d176b2ce07417e346d85486acea9040ef", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 981454a..e1a71d6 100644 --- a/flake.nix +++ b/flake.nix @@ -31,8 +31,17 @@ 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; [ libxkbcommon wayland libGL ]) + ++ pkgs.lib.optionals pkgs.stdenv.hostPlatform.isLinux (with pkgs; [ + libxkbcommon wayland libGL # Wayland + xorg.libX11 xorg.libXcursor xorg.libXi xorg.libxcb xorg.libxshmfence # Xorg + ]) ++ pkgs.lib.optionals pkgs.stdenv.hostPlatform.isDarwin (with pkgs; [ darwin.apple_sdk.frameworks.SystemConfiguration ]); nativeBuildInputs = with pkgs; [ @@ -40,22 +49,25 @@ cmake python312 ]; + + mkCustomShell = { packages ? [] }: pkgs.mkShell { + nativeBuildInputs = with pkgs; [ + renderdoc + (rust.override { extensions = [ "rust-src" "rust-analyzer" ]; }) + ] ++ nativeBuildInputs; + + buildInputs = buildInputs + ++ packages; + + LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath buildInputs; + VK_LAYER_PATH = "${pkgs.vulkan-validation-layers}/share/vulkan/explicit_layer.d:${renderdoc}/share/vulkan/implicit_layer.d"; + RUST_LOG = "info,rust_vulkan_test=trace"; + }; in { devShells = { - default = pkgs.mkShell { - nativeBuildInputs = with pkgs; [ - renderdoc - (rust.override { extensions = [ "rust-src" "rust-analyzer" ]; }) - ] ++ nativeBuildInputs; - - buildInputs = buildInputs - ++ [ pkgs.nixgl.auto.nixVulkanNvidia pkgs.nixgl.nixVulkanMesa ]; - - LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath buildInputs; - VK_LAYER_PATH = "${pkgs.vulkan-validation-layers}/share/vulkan/explicit_layer.d:${pkgs.renderdoc}/share/vulkan/implicit_layer.d"; - RUST_LOG = "info,rust_vulkan_test=trace"; - }; + default = mkCustomShell { packages = [ pkgs.nixgl.auto.nixVulkanNvidia pkgs.nixgl.nixVulkanMesa ]; }; + nixos = mkCustomShell { }; }; packages = { diff --git a/rust-toolchain.toml b/rust-toolchain.toml index c1bc0a6..00822fd 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "1.85.0" +channel = "1.85.1" diff --git a/src/renderer/app.rs b/src/renderer/app.rs index 3287f7d..f791616 100644 --- a/src/renderer/app.rs +++ b/src/renderer/app.rs @@ -54,10 +54,7 @@ impl App { // (e.g. MoltenVK) flags: InstanceCreateFlags::ENUMERATE_PORTABILITY, enabled_extensions: required_extensions, - enabled_layers: vec![ - String::from("VK_LAYER_KHRONOS_validation"), - String::from("VK_LAYER_RENDERDOC_Capture"), - ], + enabled_layers: vec![String::from("VK_LAYER_KHRONOS_validation")], ..Default::default() }, ) From 1c24a05200761c44b2997282d83fb632ec9f3c72 Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Tue, 25 Mar 2025 12:45:30 +0100 Subject: [PATCH 25/41] Update flake.nix --- flake.nix | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/flake.nix b/flake.nix index e1a71d6..565976b 100644 --- a/flake.nix +++ b/flake.nix @@ -31,7 +31,7 @@ cargo = rust; }); - renderdoc = pkgs.renderdoc.overrideAttrs(oldAttrs: { + renderdoc = pkgs.renderdoc.overrideAttrs (oldAttrs: { cmakeFlags = oldAttrs.cmakeFlags ++ [ (pkgs.lib.cmakeBool "ENABLE_UNSUPPORTED_EXPERIMENTAL_POSSIBLY_BROKEN_WAYLAND" true) ]; @@ -39,9 +39,17 @@ buildInputs = with pkgs; [ vulkan-headers vulkan-loader vulkan-validation-layers renderdoc ] ++ pkgs.lib.optionals pkgs.stdenv.hostPlatform.isLinux (with pkgs; [ - libxkbcommon wayland libGL # Wayland - xorg.libX11 xorg.libXcursor xorg.libXi xorg.libxcb xorg.libxshmfence # Xorg - ]) + # Wayland + libxkbcommon + wayland + libGL + # Xorg + xorg.libX11 + xorg.libXcursor + xorg.libXi + xorg.libxcb + xorg.libxshmfence + ]) ++ pkgs.lib.optionals pkgs.stdenv.hostPlatform.isDarwin (with pkgs; [ darwin.apple_sdk.frameworks.SystemConfiguration ]); nativeBuildInputs = with pkgs; [ @@ -50,8 +58,8 @@ python312 ]; - mkCustomShell = { packages ? [] }: pkgs.mkShell { - nativeBuildInputs = with pkgs; [ + mkCustomShell = { packages ? [ ] }: pkgs.mkShell { + nativeBuildInputs = [ renderdoc (rust.override { extensions = [ "rust-src" "rust-analyzer" ]; }) ] ++ nativeBuildInputs; From 63f16975b9d210a15d42bcb7ef856d0a051a9f1d Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Tue, 25 Mar 2025 13:45:34 +0100 Subject: [PATCH 26/41] Begin rework vulkano model structure --- src/main.rs | 1 + src/vulkano/context.rs | 12 ++++++++++++ src/vulkano/mod.rs | 3 +++ src/vulkano/queues.rs | 8 ++++++++ src/vulkano/renderer.rs | 0 5 files changed, 24 insertions(+) create mode 100644 src/vulkano/context.rs create mode 100644 src/vulkano/mod.rs create mode 100644 src/vulkano/queues.rs create mode 100644 src/vulkano/renderer.rs diff --git a/src/main.rs b/src/main.rs index 6c01c40..4c3f414 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ use std::error::Error; use winit::event_loop::{ControlFlow, EventLoop}; mod renderer; +mod vulkano; fn main() -> Result<(), impl Error> { env_logger::init(); diff --git a/src/vulkano/context.rs b/src/vulkano/context.rs new file mode 100644 index 0000000..b4b5753 --- /dev/null +++ b/src/vulkano/context.rs @@ -0,0 +1,12 @@ +use crate::vulkano::queues::Queues; +use std::sync::Arc; +use vulkano::device::Device; +use vulkano::instance::Instance; +use vulkano::memory::allocator::StandardMemoryAllocator; + +struct Context { + instance: Arc, + device: Arc, + queues: Queues, + memory_allocator: Arc, +} diff --git a/src/vulkano/mod.rs b/src/vulkano/mod.rs new file mode 100644 index 0000000..3d6d8f1 --- /dev/null +++ b/src/vulkano/mod.rs @@ -0,0 +1,3 @@ +pub mod context; +pub mod queues; +mod renderer; diff --git a/src/vulkano/queues.rs b/src/vulkano/queues.rs new file mode 100644 index 0000000..c602a2a --- /dev/null +++ b/src/vulkano/queues.rs @@ -0,0 +1,8 @@ +use std::sync::Arc; +use vulkano::device::Queue; + +pub struct Queues { + graphics_queue: Arc, + compute_queue: Arc, + transfer_queue: Option>, +} diff --git a/src/vulkano/renderer.rs b/src/vulkano/renderer.rs new file mode 100644 index 0000000..e69de29 From 62275f20d9953cacd179b98990341530625c9e8f Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Tue, 1 Apr 2025 20:58:31 +0200 Subject: [PATCH 27/41] Revert begin rework vulkan --- src/main.rs | 1 - src/vulkano/context.rs | 12 ------------ src/vulkano/mod.rs | 3 --- src/vulkano/queues.rs | 8 -------- src/vulkano/renderer.rs | 0 5 files changed, 24 deletions(-) delete mode 100644 src/vulkano/context.rs delete mode 100644 src/vulkano/mod.rs delete mode 100644 src/vulkano/queues.rs delete mode 100644 src/vulkano/renderer.rs diff --git a/src/main.rs b/src/main.rs index 4c3f414..6c01c40 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,6 @@ use std::error::Error; use winit::event_loop::{ControlFlow, EventLoop}; mod renderer; -mod vulkano; fn main() -> Result<(), impl Error> { env_logger::init(); diff --git a/src/vulkano/context.rs b/src/vulkano/context.rs deleted file mode 100644 index b4b5753..0000000 --- a/src/vulkano/context.rs +++ /dev/null @@ -1,12 +0,0 @@ -use crate::vulkano::queues::Queues; -use std::sync::Arc; -use vulkano::device::Device; -use vulkano::instance::Instance; -use vulkano::memory::allocator::StandardMemoryAllocator; - -struct Context { - instance: Arc, - device: Arc, - queues: Queues, - memory_allocator: Arc, -} diff --git a/src/vulkano/mod.rs b/src/vulkano/mod.rs deleted file mode 100644 index 3d6d8f1..0000000 --- a/src/vulkano/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod context; -pub mod queues; -mod renderer; diff --git a/src/vulkano/queues.rs b/src/vulkano/queues.rs deleted file mode 100644 index c602a2a..0000000 --- a/src/vulkano/queues.rs +++ /dev/null @@ -1,8 +0,0 @@ -use std::sync::Arc; -use vulkano::device::Queue; - -pub struct Queues { - graphics_queue: Arc, - compute_queue: Arc, - transfer_queue: Option>, -} diff --git a/src/vulkano/renderer.rs b/src/vulkano/renderer.rs deleted file mode 100644 index e69de29..0000000 From 6bc3dbd53df570995c9145bd4daaa9773e56d76f Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Tue, 1 Apr 2025 23:49:40 +0200 Subject: [PATCH 28/41] Migrate to bevy_ecs for more up to date ECS crates --- Cargo.lock | 550 ++++++++++++++++++++++++++++++++--------------------- Cargo.toml | 2 +- 2 files changed, 331 insertions(+), 221 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e69aec8..e35561c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -25,6 +25,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", + "const-random", "getrandom", "once_cell", "version_check", @@ -40,6 +41,12 @@ 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" @@ -117,48 +124,12 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "any_vec" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6ac04794a7749710e3c7f3c93222e3d04692993b69876d69393efd2565401a" - [[package]] name = "anyhow" version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" -[[package]] -name = "apecs" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6df7760d4baebb17003dcf99134d8e3a63f487e146d58911f0bcd27afb185d1c" -dependencies = [ - "any_vec", - "apecs-derive", - "async-channel", - "itertools", - "log", - "moongraph", - "parking_lot", - "rayon", - "smallvec", - "snafu 0.8.5", -] - -[[package]] -name = "apecs-derive" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc0f3ddfd31fd5276fb8039b75dc4d284c21213757a969e480c6ef8fde494f3b" -dependencies = [ - "moongraph-macros-syntax", - "proc-macro2", - "quote", - "syn 2.0.100", -] - [[package]] name = "arrayref" version = "0.3.9" @@ -187,16 +158,35 @@ dependencies = [ ] [[package]] -name = "async-channel" -version = "1.9.0" +name = "assert_type_match" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +checksum = "f548ad2c4031f2902e3edc1f29c29e835829437de49562d8eb5dc5584d3a1043" dependencies = [ - "concurrent-queue", - "event-listener", - "futures-core", + "proc-macro2", + "quote", + "syn", ] +[[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" @@ -209,6 +199,127 @@ 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" @@ -230,17 +341,6 @@ dependencies = [ "objc2 0.5.2", ] -[[package]] -name = "broomdog" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ec65645d8167b03c07e049f114a878a11ab889f20c071d6f7b30bf88fbe5af" -dependencies = [ - "log", - "rustc-hash", - "snafu 0.8.5", -] - [[package]] name = "bumpalo" version = "3.17.0" @@ -264,7 +364,7 @@ checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", ] [[package]] @@ -362,6 +462,26 @@ 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" @@ -402,25 +522,6 @@ dependencies = [ "libc", ] -[[package]] -name = "crossbeam-deque" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "crossbeam-queue" version = "0.3.12" @@ -449,14 +550,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" [[package]] -name = "dagga" -version = "0.2.1" +name = "derive_more" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cf0d7dcd307c9c5d81277737c35d1faf08af9e2cb262966a01c91021686b68" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" dependencies = [ - "log", - "rustc-hash", - "snafu 0.7.5", + "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]] @@ -465,6 +576,12 @@ 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" @@ -474,12 +591,6 @@ dependencies = [ "libloading", ] -[[package]] -name = "doc-comment" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" - [[package]] name = "downcast-rs" version = "1.2.1" @@ -492,12 +603,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - [[package]] name = "env_filter" version = "0.1.3" @@ -527,6 +632,16 @@ version = "1.0.2" 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", +] + [[package]] name = "errno" version = "0.3.10" @@ -538,10 +653,22 @@ dependencies = [ ] [[package]] -name = "event-listener" -version = "2.5.3" +name = "fastrand" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +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" @@ -567,7 +694,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", ] [[package]] @@ -576,12 +703,40 @@ 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" @@ -599,8 +754,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -620,6 +777,17 @@ dependencies = [ "crunchy", ] +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", + "serde", +] + [[package]] name = "hashbrown" version = "0.15.2" @@ -645,7 +813,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.15.2", ] [[package]] @@ -654,15 +822,6 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - [[package]] name = "itoa" version = "1.0.15" @@ -690,7 +849,7 @@ checksum = "8d16e75759ee0aa64c57a56acbf43916987b20c77373cb7e808979e02b93c9f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", ] [[package]] @@ -804,30 +963,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "moongraph" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5a4b09eb96a84205062b48ec5469c8c35c128167e838aa73dc620c4411af598" -dependencies = [ - "broomdog", - "dagga", - "log", - "rayon", - "snafu 0.8.5", -] - -[[package]] -name = "moongraph-macros-syntax" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08112087acc92cc28fb5d8f7bda1307123ecc9a275ed4835f1c03f1a8dd02c1d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - [[package]] name = "ndk" version = "0.9.0" @@ -868,6 +1003,12 @@ dependencies = [ "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" @@ -886,7 +1027,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.100", + "syn", ] [[package]] @@ -1170,6 +1311,12 @@ 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" @@ -1199,6 +1346,16 @@ 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" @@ -1216,7 +1373,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", ] [[package]] @@ -1315,26 +1472,6 @@ dependencies = [ "objc2-quartz-core 0.3.0", ] -[[package]] -name = "rayon" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - [[package]] name = "redox_syscall" version = "0.4.1" @@ -1396,7 +1533,7 @@ name = "rust_vulkan_test" version = "0.1.0" dependencies = [ "anyhow", - "apecs", + "bevy_ecs", "env_logger", "glam", "log", @@ -1405,12 +1542,6 @@ dependencies = [ "winit", ] -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - [[package]] name = "rustix" version = "0.38.44" @@ -1487,7 +1618,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", ] [[package]] @@ -1584,66 +1715,12 @@ dependencies = [ "serde", ] -[[package]] -name = "snafu" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4de37ad025c587a29e8f3f5605c00f70b98715ef90b9061a815b9e59e9042d6" -dependencies = [ - "doc-comment", - "snafu-derive 0.7.5", -] - -[[package]] -name = "snafu" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "223891c85e2a29c3fe8fb900c1fae5e69c2e42415e3177752e8718475efa5019" -dependencies = [ - "snafu-derive 0.8.5", -] - -[[package]] -name = "snafu-derive" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990079665f075b699031e9c08fd3ab99be5029b96f3b78dc0709e8f77e4efebf" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "snafu-derive" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c3c6b7927ffe7ecaa769ee0e3994da3b8cafc8f444578982c83ecb161af917" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 2.0.100", -] - [[package]] name = "strict-num" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - [[package]] name = "syn" version = "2.0.100" @@ -1672,7 +1749,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", ] [[package]] @@ -1685,6 +1762,15 @@ dependencies = [ "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" @@ -1742,6 +1828,9 @@ name = "tracing-core" version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +dependencies = [ + "once_cell", +] [[package]] name = "ttf-parser" @@ -1749,6 +1838,12 @@ version = "0.25.1" 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" + [[package]] name = "unicode-ident" version = "1.0.18" @@ -1761,12 +1856,27 @@ 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" @@ -1823,7 +1933,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.100", + "syn", ] [[package]] @@ -1837,7 +1947,7 @@ dependencies = [ "proc-macro2", "quote", "shaderc", - "syn 2.0.100", + "syn", "vulkano", ] @@ -1879,7 +1989,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.100", + "syn", "wasm-bindgen-shared", ] @@ -1914,7 +2024,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2418,5 +2528,5 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", ] diff --git a/Cargo.toml b/Cargo.toml index ba7eb9d..a6ece63 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ vulkano-shaders = "0.35" glam = { version = "0.30" } # ECS -apecs = "0.8" +bevy_ecs = "0.15.3" # Log and tracing log = "0.4" From f32db721011cf5ddb12f6e444b916fa62d8eaf0a Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Thu, 3 Apr 2025 18:38:17 +0200 Subject: [PATCH 29/41] rename renderer to vulkan --- src/main.rs | 4 ++-- src/{renderer => vulkan}/app.rs | 10 +++++----- src/{renderer => vulkan}/mod.rs | 0 src/{renderer => vulkan}/pipelines/mod.rs | 0 .../pipelines/triangle_pipeline.rs | 4 ++-- src/{renderer => vulkan}/render_context.rs | 0 src/{renderer => vulkan}/scene.rs | 4 ++-- src/{renderer => vulkan}/vertex.rs | 0 8 files changed, 11 insertions(+), 11 deletions(-) rename src/{renderer => vulkan}/app.rs (98%) rename src/{renderer => vulkan}/mod.rs (100%) rename src/{renderer => vulkan}/pipelines/mod.rs (100%) rename src/{renderer => vulkan}/pipelines/triangle_pipeline.rs (99%) rename src/{renderer => vulkan}/render_context.rs (100%) rename src/{renderer => vulkan}/scene.rs (96%) rename src/{renderer => vulkan}/vertex.rs (100%) diff --git a/src/main.rs b/src/main.rs index 6c01c40..e0ab6d4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ use std::error::Error; use winit::event_loop::{ControlFlow, EventLoop}; -mod renderer; +mod vulkan; fn main() -> Result<(), impl Error> { env_logger::init(); @@ -9,7 +9,7 @@ fn main() -> Result<(), impl Error> { let event_loop = EventLoop::new().unwrap(); event_loop.set_control_flow(ControlFlow::Poll); - let mut app = renderer::App::new(&event_loop); + let mut app = vulkan::App::new(&event_loop); event_loop.run_app(&mut app) } diff --git a/src/renderer/app.rs b/src/vulkan/app.rs similarity index 98% rename from src/renderer/app.rs rename to src/vulkan/app.rs index f791616..8a0397e 100644 --- a/src/renderer/app.rs +++ b/src/vulkan/app.rs @@ -1,8 +1,8 @@ -use crate::renderer::render_context::RenderContext; -use crate::renderer::Scene; +use crate::vulkan::Scene; +use crate::vulkan::render_context::RenderContext; use std::sync::Arc; -use vulkano::buffer::allocator::{SubbufferAllocator, SubbufferAllocatorCreateInfo}; use vulkano::buffer::BufferUsage; +use vulkano::buffer::allocator::{SubbufferAllocator, SubbufferAllocatorCreateInfo}; use vulkano::command_buffer::allocator::StandardCommandBufferAllocator; use vulkano::command_buffer::{ AutoCommandBufferBuilder, CommandBufferUsage, RenderingAttachmentInfo, RenderingInfo, @@ -15,9 +15,9 @@ use vulkano::device::{ use vulkano::instance::{Instance, InstanceCreateFlags, InstanceCreateInfo}; use vulkano::memory::allocator::{MemoryTypeFilter, StandardMemoryAllocator}; use vulkano::render_pass::{AttachmentLoadOp, AttachmentStoreOp}; -use vulkano::swapchain::{acquire_next_image, Surface, SwapchainPresentInfo}; +use vulkano::swapchain::{Surface, SwapchainPresentInfo, acquire_next_image}; use vulkano::sync::GpuFuture; -use vulkano::{sync, Validated, Version, VulkanError, VulkanLibrary}; +use vulkano::{Validated, Version, VulkanError, VulkanLibrary, sync}; use winit::application::ApplicationHandler; use winit::event::WindowEvent; use winit::event_loop::{ActiveEventLoop, EventLoop}; diff --git a/src/renderer/mod.rs b/src/vulkan/mod.rs similarity index 100% rename from src/renderer/mod.rs rename to src/vulkan/mod.rs diff --git a/src/renderer/pipelines/mod.rs b/src/vulkan/pipelines/mod.rs similarity index 100% rename from src/renderer/pipelines/mod.rs rename to src/vulkan/pipelines/mod.rs diff --git a/src/renderer/pipelines/triangle_pipeline.rs b/src/vulkan/pipelines/triangle_pipeline.rs similarity index 99% rename from src/renderer/pipelines/triangle_pipeline.rs rename to src/vulkan/pipelines/triangle_pipeline.rs index f6001f7..0c1554d 100644 --- a/src/renderer/pipelines/triangle_pipeline.rs +++ b/src/vulkan/pipelines/triangle_pipeline.rs @@ -5,6 +5,7 @@ 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; @@ -12,7 +13,6 @@ 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::graphics::GraphicsPipelineCreateInfo; use vulkano::pipeline::layout::{PipelineDescriptorSetLayoutCreateInfo, PipelineLayoutCreateFlags}; use vulkano::pipeline::{ DynamicState, GraphicsPipeline, PipelineLayout, PipelineShaderStageCreateInfo, @@ -20,7 +20,7 @@ use vulkano::pipeline::{ use vulkano::shader::{EntryPoint, ShaderStages}; use vulkano::swapchain::Swapchain; -use crate::renderer::Vertex2D; +use crate::vulkan::Vertex2D; pub mod shaders { pub mod vs { diff --git a/src/renderer/render_context.rs b/src/vulkan/render_context.rs similarity index 100% rename from src/renderer/render_context.rs rename to src/vulkan/render_context.rs diff --git a/src/renderer/scene.rs b/src/vulkan/scene.rs similarity index 96% rename from src/renderer/scene.rs rename to src/vulkan/scene.rs index e3c6b58..83863e2 100644 --- a/src/renderer/scene.rs +++ b/src/vulkan/scene.rs @@ -1,4 +1,4 @@ -use crate::renderer::pipelines::triangle_pipeline::shaders::vs; +use crate::vulkan::pipelines::triangle_pipeline::shaders::vs; use glam::{Mat3, Mat4, Vec3}; use std::error::Error; use std::sync::Arc; @@ -8,7 +8,7 @@ use vulkano::command_buffer::{AutoCommandBufferBuilder, PrimaryAutoCommandBuffer use vulkano::descriptor_set::{DescriptorSet, WriteDescriptorSet}; use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint}; -use crate::renderer::{pipelines::triangle_pipeline::create_triangle_pipeline, App, Vertex2D}; +use crate::vulkan::{App, Vertex2D, pipelines::triangle_pipeline::create_triangle_pipeline}; const VERTICES: [Vertex2D; 12] = [ // Triangle en haut à gauche diff --git a/src/renderer/vertex.rs b/src/vulkan/vertex.rs similarity index 100% rename from src/renderer/vertex.rs rename to src/vulkan/vertex.rs From 15c273b93d35b0f0cdc7fc3fac987c159f7362c8 Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Thu, 3 Apr 2025 19:59:10 +0200 Subject: [PATCH 30/41] Split app, window render context and vulkan context --- src/core/app.rs | 178 +++++++++++ src/core/mod.rs | 1 + src/main.rs | 6 +- src/vulkan/app.rs | 295 ------------------ src/vulkan/mod.rs | 13 +- src/vulkan/pipelines/triangle_pipeline.rs | 2 +- src/vulkan/scene.rs | 35 ++- src/vulkan/vulkan_context.rs | 203 ++++++++++++ ...er_context.rs => window_render_context.rs} | 18 +- 9 files changed, 426 insertions(+), 325 deletions(-) create mode 100644 src/core/app.rs create mode 100644 src/core/mod.rs delete mode 100644 src/vulkan/app.rs create mode 100644 src/vulkan/vulkan_context.rs rename src/vulkan/{render_context.rs => window_render_context.rs} (89%) diff --git a/src/core/app.rs b/src/core/app.rs new file mode 100644 index 0000000..93a7d56 --- /dev/null +++ b/src/core/app.rs @@ -0,0 +1,178 @@ +use crate::vulkan::scene::Scene; +use crate::vulkan::vulkan_context::VulkanContext; +use crate::vulkan::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/core/mod.rs b/src/core/mod.rs new file mode 100644 index 0000000..309be62 --- /dev/null +++ b/src/core/mod.rs @@ -0,0 +1 @@ +pub mod app; diff --git a/src/main.rs b/src/main.rs index e0ab6d4..54a1427 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,8 @@ use std::error::Error; use winit::event_loop::{ControlFlow, EventLoop}; -mod vulkan; +pub mod core; +pub mod vulkan; fn main() -> Result<(), impl Error> { env_logger::init(); @@ -9,7 +10,8 @@ fn main() -> Result<(), impl Error> { let event_loop = EventLoop::new().unwrap(); event_loop.set_control_flow(ControlFlow::Poll); - let mut app = vulkan::App::new(&event_loop); + let vulkan_context = vulkan::vulkan_context::VulkanContext::from(&event_loop); + let mut app = core::app::App::from(vulkan_context); event_loop.run_app(&mut app) } diff --git a/src/vulkan/app.rs b/src/vulkan/app.rs deleted file mode 100644 index 8a0397e..0000000 --- a/src/vulkan/app.rs +++ /dev/null @@ -1,295 +0,0 @@ -use crate::vulkan::Scene; -use crate::vulkan::render_context::RenderContext; -use std::sync::Arc; -use vulkano::buffer::BufferUsage; -use vulkano::buffer::allocator::{SubbufferAllocator, SubbufferAllocatorCreateInfo}; -use vulkano::command_buffer::allocator::StandardCommandBufferAllocator; -use vulkano::command_buffer::{ - AutoCommandBufferBuilder, CommandBufferUsage, RenderingAttachmentInfo, RenderingInfo, -}; -use vulkano::descriptor_set::allocator::StandardDescriptorSetAllocator; -use vulkano::device::physical::PhysicalDeviceType; -use vulkano::device::{ - Device, DeviceCreateInfo, DeviceExtensions, DeviceFeatures, Queue, QueueCreateInfo, QueueFlags, -}; -use vulkano::instance::{Instance, InstanceCreateFlags, InstanceCreateInfo}; -use vulkano::memory::allocator::{MemoryTypeFilter, StandardMemoryAllocator}; -use vulkano::render_pass::{AttachmentLoadOp, AttachmentStoreOp}; -use vulkano::swapchain::{Surface, SwapchainPresentInfo, acquire_next_image}; -use vulkano::sync::GpuFuture; -use vulkano::{Validated, Version, VulkanError, VulkanLibrary, sync}; -use winit::application::ApplicationHandler; -use winit::event::WindowEvent; -use winit::event_loop::{ActiveEventLoop, EventLoop}; -use winit::window::WindowId; - -pub struct App { - pub instance: Arc, - pub device: Arc, - pub queue: Arc, - - pub memory_allocator: Arc, - pub command_buffer_allocator: Arc, - pub uniform_buffer_allocator: SubbufferAllocator, - pub descriptor_set_allocator: Arc, - - pub rcx: Option, - scene: Option, -} - -impl App { - pub fn new(event_loop: &EventLoop<()>) -> Self { - let library = VulkanLibrary::new().unwrap(); - - for layer in library.layer_properties().unwrap() { - log::debug!("Available layer: {}", layer.name()); - } - - let required_extensions = Surface::required_extensions(event_loop).unwrap(); - - let instance = 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(); - - let mut device_extensions = DeviceExtensions { - khr_swapchain: true, - ..DeviceExtensions::empty() - }; - - let (physical_device, queue_family_index) = 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| { - p.queue_family_properties() - .iter() - .enumerate() - .position(|(i, q)| { - q.queue_flags.intersects(QueueFlags::GRAPHICS) - && p.presentation_support(i as u32, event_loop).unwrap() - }) - .map(|i| (p, i as u32)) - }) - .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, - }) - .expect("no suitable physical device found"); - - 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); - - let (device, mut queues) = Device::new( - physical_device, - DeviceCreateInfo { - queue_create_infos: vec![QueueCreateInfo { - queue_family_index, - ..Default::default() - }], - enabled_extensions: device_extensions, - enabled_features: DeviceFeatures { - dynamic_rendering: true, - ..DeviceFeatures::empty() - }, - ..Default::default() - }, - ) - .unwrap(); - - let 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 uniform_buffer_allocator = SubbufferAllocator::new( - memory_allocator.clone(), - SubbufferAllocatorCreateInfo { - buffer_usage: BufferUsage::UNIFORM_BUFFER, - memory_type_filter: MemoryTypeFilter::PREFER_DEVICE - | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, - ..Default::default() - }, - ); - - let descriptor_set_allocator = Arc::new(StandardDescriptorSetAllocator::new( - device.clone(), - Default::default(), - )); - - Self { - instance, - device, - queue, - memory_allocator, - command_buffer_allocator, - uniform_buffer_allocator, - descriptor_set_allocator, - rcx: 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 = Surface::from_window(self.instance.clone(), window.clone()).unwrap(); - - self.rcx = Some(RenderContext::new(window, surface, &self.device)); - self.scene = Some(Scene::load(&self).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.rcx.as_mut().unwrap(); - rcx.recreate_swapchain = true; - } - WindowEvent::RedrawRequested => { - let (image_index, acquire_future) = { - let rcx = self.rcx.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 = AutoCommandBufferBuilder::primary( - self.command_buffer_allocator.clone(), - self.queue.queue_family_index(), - CommandBufferUsage::OneTimeSubmit, - ) - .unwrap(); - - { - let rcx = self.rcx.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, &mut builder).unwrap(); - } - - builder.end_rendering().unwrap(); - - let command_buffer = builder.build().unwrap(); - - { - let rcx = self.rcx.as_mut().unwrap(); - - let future = rcx - .previous_frame_end - .take() - .unwrap() - .join(acquire_future) - .then_execute(self.queue.clone(), command_buffer) - .unwrap() - .then_swapchain_present( - self.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.device.clone()).boxed()); - } - Err(e) => { - println!("failed to flush future: {e}"); - rcx.previous_frame_end = Some(sync::now(self.device.clone()).boxed()); - } - } - } - } - _ => {} - } - } - - fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) { - let rcx = self.rcx.as_mut().unwrap(); - rcx.window.request_redraw(); - } -} diff --git a/src/vulkan/mod.rs b/src/vulkan/mod.rs index bbcff9a..56d8c07 100644 --- a/src/vulkan/mod.rs +++ b/src/vulkan/mod.rs @@ -1,9 +1,6 @@ -mod app; -mod pipelines; -mod render_context; -mod vertex; -pub use app::App; +pub mod pipelines; +pub mod vertex; +pub mod vulkan_context; +pub mod window_render_context; -mod scene; -pub use scene::Scene; -pub use vertex::Vertex2D; +pub mod scene; diff --git a/src/vulkan/pipelines/triangle_pipeline.rs b/src/vulkan/pipelines/triangle_pipeline.rs index 0c1554d..bb07389 100644 --- a/src/vulkan/pipelines/triangle_pipeline.rs +++ b/src/vulkan/pipelines/triangle_pipeline.rs @@ -20,7 +20,7 @@ use vulkano::pipeline::{ use vulkano::shader::{EntryPoint, ShaderStages}; use vulkano::swapchain::Swapchain; -use crate::vulkan::Vertex2D; +use crate::vulkan::vertex::Vertex2D; pub mod shaders { pub mod vs { diff --git a/src/vulkan/scene.rs b/src/vulkan/scene.rs index 83863e2..1f77e5a 100644 --- a/src/vulkan/scene.rs +++ b/src/vulkan/scene.rs @@ -8,7 +8,10 @@ use vulkano::command_buffer::{AutoCommandBufferBuilder, PrimaryAutoCommandBuffer use vulkano::descriptor_set::{DescriptorSet, WriteDescriptorSet}; use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint}; -use crate::vulkan::{App, Vertex2D, pipelines::triangle_pipeline::create_triangle_pipeline}; +use crate::vulkan::{pipelines::triangle_pipeline::create_triangle_pipeline, vertex::Vertex2D}; + +use super::vulkan_context::VulkanContext; +use super::window_render_context::WindowRenderContext; const VERTICES: [Vertex2D; 12] = [ // Triangle en haut à gauche @@ -73,10 +76,14 @@ pub struct Scene { } impl Scene { - pub fn load(app: &App) -> Result> { - let pipeline = create_triangle_pipeline(&app.device, &app.rcx.as_ref().unwrap().swapchain)?; + 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), &app.memory_allocator)?; + Vertex2D::create_buffer(Vec::from_iter(VERTICES), &vulkan_context.memory_allocator)?; Ok(Scene { pipeline, @@ -87,16 +94,17 @@ impl Scene { pub fn render( &self, - app: &App, + 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(app); + 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( - app.descriptor_set_allocator.clone(), + vulkan_context.descriptor_set_allocator.clone(), layout.clone(), [WriteDescriptorSet::buffer(0, uniform_buffer)], [], @@ -119,8 +127,12 @@ impl Scene { Ok(()) } - fn get_uniform_buffer(&self, app: &App) -> Subbuffer { - let swapchain = &app.rcx.as_ref().unwrap().swapchain; + 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); @@ -143,7 +155,10 @@ impl Scene { projection: proj.to_cols_array_2d(), }; - let buffer = app.uniform_buffer_allocator.allocate_sized().unwrap(); + let buffer = vulkan_context + .uniform_buffer_allocator + .allocate_sized() + .unwrap(); *buffer.write().unwrap() = uniform_data; buffer diff --git a/src/vulkan/vulkan_context.rs b/src/vulkan/vulkan_context.rs new file mode 100644 index 0000000..ef2c6f7 --- /dev/null +++ b/src/vulkan/vulkan_context.rs @@ -0,0 +1,203 @@ +use std::{any::Any, sync::Arc}; + +use vulkano::{ + Version, VulkanLibrary, + buffer::{ + BufferUsage, + allocator::{SubbufferAllocator, SubbufferAllocatorCreateInfo}, + }, + command_buffer::{ + AutoCommandBufferBuilder, CommandBufferUsage, PrimaryAutoCommandBuffer, + allocator::StandardCommandBufferAllocator, + }, + descriptor_set::allocator::StandardDescriptorSetAllocator, + device::{ + Device, DeviceCreateInfo, DeviceExtensions, DeviceFeatures, Queue, QueueCreateInfo, + QueueFlags, physical::PhysicalDeviceType, + }, + instance::{Instance, InstanceCreateFlags, InstanceCreateInfo, InstanceExtensions}, + memory::allocator::{MemoryTypeFilter, 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 uniform_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 uniform_buffer_allocator = Arc::new(SubbufferAllocator::new( + memory_allocator.clone(), + SubbufferAllocatorCreateInfo { + buffer_usage: BufferUsage::UNIFORM_BUFFER, + memory_type_filter: MemoryTypeFilter::PREFER_DEVICE + | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, + ..Default::default() + }, + )); + + let descriptor_set_allocator = Arc::new(StandardDescriptorSetAllocator::new( + device.clone(), + Default::default(), + )); + + Self { + instance, + device, + graphics_queue, + memory_allocator, + command_buffer_allocator, + uniform_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 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, queue_family_index) = 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| { + p.queue_family_properties() + .iter() + .enumerate() + .position(|(i, q)| { + q.queue_flags.intersects(QueueFlags::GRAPHICS) + && p.presentation_support(i as u32, event_loop).unwrap() + }) + .map(|i| (p, i as u32)) + }) + .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, + }) + .expect("no suitable physical device found"); + + 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, + ..Default::default() + }], + enabled_extensions: device_extensions, + enabled_features: DeviceFeatures { + dynamic_rendering: true, + ..DeviceFeatures::empty() + }, + ..Default::default() + }, + ) + .unwrap() +} diff --git a/src/vulkan/render_context.rs b/src/vulkan/window_render_context.rs similarity index 89% rename from src/vulkan/render_context.rs rename to src/vulkan/window_render_context.rs index dd7e840..54120d0 100644 --- a/src/vulkan/render_context.rs +++ b/src/vulkan/window_render_context.rs @@ -5,19 +5,19 @@ use vulkano::image::{Image, ImageUsage}; use vulkano::pipeline::graphics::viewport::Viewport; use vulkano::swapchain::{Surface, Swapchain, SwapchainCreateInfo}; use vulkano::sync::GpuFuture; -use vulkano::{sync, Validated, VulkanError}; +use vulkano::{Validated, VulkanError, sync}; use winit::window::Window; -pub struct RenderContext { - pub(super) window: Arc, - pub(super) swapchain: Arc, - pub(super) attachment_image_views: Vec>, - pub(super) viewport: Viewport, - pub(super) recreate_swapchain: bool, - pub(super) previous_frame_end: Option>, +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 RenderContext { +impl WindowRenderContext { pub fn new(window: Arc, surface: Arc, device: &Arc) -> Self { let window_size = window.inner_size(); From 2fbf4e6ce2ff41a2234fda87da49439a35f9191b Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Thu, 3 Apr 2025 21:10:08 +0200 Subject: [PATCH 31/41] Split pick_graphics_device --- src/vulkan/vulkan_context.rs | 81 +++++++++++++++++++++++------------- 1 file changed, 53 insertions(+), 28 deletions(-) diff --git a/src/vulkan/vulkan_context.rs b/src/vulkan/vulkan_context.rs index ef2c6f7..ea1b29b 100644 --- a/src/vulkan/vulkan_context.rs +++ b/src/vulkan/vulkan_context.rs @@ -13,7 +13,8 @@ use vulkano::{ descriptor_set::allocator::StandardDescriptorSetAllocator, device::{ Device, DeviceCreateInfo, DeviceExtensions, DeviceFeatures, Queue, QueueCreateInfo, - QueueFlags, physical::PhysicalDeviceType, + QueueFlags, + physical::{PhysicalDevice, PhysicalDeviceType}, }, instance::{Instance, InstanceCreateFlags, InstanceCreateInfo, InstanceExtensions}, memory::allocator::{MemoryTypeFilter, StandardMemoryAllocator}, @@ -133,6 +134,53 @@ fn create_instance( .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<()>, @@ -145,32 +193,9 @@ fn pick_graphics_device( ..DeviceExtensions::empty() }; - let (physical_device, queue_family_index) = 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| { - p.queue_family_properties() - .iter() - .enumerate() - .position(|(i, q)| { - q.queue_flags.intersects(QueueFlags::GRAPHICS) - && p.presentation_support(i as u32, event_loop).unwrap() - }) - .map(|i| (p, i as u32)) - }) - .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, - }) - .expect("no suitable physical device found"); + let (physical_device, graphics_family_index) = + pick_physical_device_and_queue_family_indexes(instance, event_loop, &device_extensions) + .unwrap(); log::debug!( "Using device: {} (type: {:?})", @@ -188,7 +213,7 @@ fn pick_graphics_device( physical_device, DeviceCreateInfo { queue_create_infos: vec![QueueCreateInfo { - queue_family_index, + queue_family_index: graphics_family_index, ..Default::default() }], enabled_extensions: device_extensions, From 852d72d716710ac0e9c30298d26371c7d98bdbf5 Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Fri, 4 Apr 2025 13:38:27 +0200 Subject: [PATCH 32/41] Begin move mesh + Vertex and Camera into core --- src/core/camera/mod.rs | 19 +++++++++++++++++++ src/core/mod.rs | 3 +++ src/core/render/mesh.rs | 14 ++++++++++++++ src/core/render/mod.rs | 2 ++ src/{vulkan => core/render}/vertex.rs | 0 src/core/scene.rs | 21 +++++++++++++++++++++ src/game/mod.rs | 1 + src/main.rs | 1 + src/vulkan/mod.rs | 1 - src/vulkan/pipelines/triangle_pipeline.rs | 2 +- src/vulkan/scene.rs | 3 ++- 11 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 src/core/camera/mod.rs create mode 100644 src/core/render/mesh.rs create mode 100644 src/core/render/mod.rs rename src/{vulkan => core/render}/vertex.rs (100%) create mode 100644 src/core/scene.rs create mode 100644 src/game/mod.rs diff --git a/src/core/camera/mod.rs b/src/core/camera/mod.rs new file mode 100644 index 0000000..f9b6925 --- /dev/null +++ b/src/core/camera/mod.rs @@ -0,0 +1,19 @@ +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 index 309be62..f058532 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -1 +1,4 @@ pub mod app; +pub mod camera; +pub mod render; +pub mod scene; diff --git a/src/core/render/mesh.rs b/src/core/render/mesh.rs new file mode 100644 index 0000000..ca5ec0f --- /dev/null +++ b/src/core/render/mesh.rs @@ -0,0 +1,14 @@ +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 new file mode 100644 index 0000000..6f29814 --- /dev/null +++ b/src/core/render/mod.rs @@ -0,0 +1,2 @@ +pub mod mesh; +pub mod vertex; diff --git a/src/vulkan/vertex.rs b/src/core/render/vertex.rs similarity index 100% rename from src/vulkan/vertex.rs rename to src/core/render/vertex.rs diff --git a/src/core/scene.rs b/src/core/scene.rs new file mode 100644 index 0000000..a424da3 --- /dev/null +++ b/src/core/scene.rs @@ -0,0 +1,21 @@ +use bevy_ecs::world::World; + +pub struct Scene { + world: World, +} + +impl Scene { + pub fn new() -> Self { + Self { + world: World::new(), + } + } + + pub fn world(&self) -> &World { + &self.world + } + + pub fn world_mut(&mut self) -> &mut World { + &mut self.world + } +} diff --git a/src/game/mod.rs b/src/game/mod.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/game/mod.rs @@ -0,0 +1 @@ + diff --git a/src/main.rs b/src/main.rs index 54a1427..2b80274 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ use std::error::Error; use winit::event_loop::{ControlFlow, EventLoop}; pub mod core; +pub mod game; pub mod vulkan; fn main() -> Result<(), impl Error> { diff --git a/src/vulkan/mod.rs b/src/vulkan/mod.rs index 56d8c07..dc3d731 100644 --- a/src/vulkan/mod.rs +++ b/src/vulkan/mod.rs @@ -1,5 +1,4 @@ pub mod pipelines; -pub mod vertex; pub mod vulkan_context; pub mod window_render_context; diff --git a/src/vulkan/pipelines/triangle_pipeline.rs b/src/vulkan/pipelines/triangle_pipeline.rs index bb07389..e573747 100644 --- a/src/vulkan/pipelines/triangle_pipeline.rs +++ b/src/vulkan/pipelines/triangle_pipeline.rs @@ -20,7 +20,7 @@ use vulkano::pipeline::{ use vulkano::shader::{EntryPoint, ShaderStages}; use vulkano::swapchain::Swapchain; -use crate::vulkan::vertex::Vertex2D; +use crate::core::render::vertex::Vertex2D; pub mod shaders { pub mod vs { diff --git a/src/vulkan/scene.rs b/src/vulkan/scene.rs index 1f77e5a..4d1de95 100644 --- a/src/vulkan/scene.rs +++ b/src/vulkan/scene.rs @@ -8,7 +8,8 @@ use vulkano::command_buffer::{AutoCommandBufferBuilder, PrimaryAutoCommandBuffer use vulkano::descriptor_set::{DescriptorSet, WriteDescriptorSet}; use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint}; -use crate::vulkan::{pipelines::triangle_pipeline::create_triangle_pipeline, vertex::Vertex2D}; +use crate::core::render::vertex::Vertex2D; +use crate::vulkan::pipelines::triangle_pipeline::create_triangle_pipeline; use super::vulkan_context::VulkanContext; use super::window_render_context::WindowRenderContext; From 9664ea754ca4a0cda52a76603391699e9ce9fad7 Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Mon, 7 Apr 2025 13:11:19 +0200 Subject: [PATCH 33/41] flake: Fix missing libstdc++ --- flake.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/flake.nix b/flake.nix index 565976b..4f7cd2e 100644 --- a/flake.nix +++ b/flake.nix @@ -39,6 +39,8 @@ 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 From 1d333b633b19e0691a760e504df4cc17185bf392 Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Mon, 7 Apr 2025 17:03:00 +0200 Subject: [PATCH 34/41] Push lunch break code --- src/core/render/material/mod.rs | 10 ++++++++ src/core/render/material/triangle.rs | 34 ++++++++++++++++++++++++++++ src/core/render/mod.rs | 1 + 3 files changed, 45 insertions(+) create mode 100644 src/core/render/material/mod.rs create mode 100644 src/core/render/material/triangle.rs diff --git a/src/core/render/material/mod.rs b/src/core/render/material/mod.rs new file mode 100644 index 0000000..8cccde2 --- /dev/null +++ b/src/core/render/material/mod.rs @@ -0,0 +1,10 @@ +pub mod triangle; + +use vulkano::command_buffer::CommandBuffer; + +use crate::vulkan::vulkan_context::VulkanContext; + +pub trait Material { + fn load(&self, vulkan_context: &VulkanContext); + fn bind(&self, command_buffer: &mut CommandBuffer); +} diff --git a/src/core/render/material/triangle.rs b/src/core/render/material/triangle.rs new file mode 100644 index 0000000..c3bafaa --- /dev/null +++ b/src/core/render/material/triangle.rs @@ -0,0 +1,34 @@ +use glam::Vec4; +use vulkano::command_buffer::CommandBuffer; + +use super::Material; + +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 struct TriangleMaterial { + pub colors: [Vec4; 3], +} + +impl Material for TriangleMaterial { + fn bind(&self, command_buffer: &mut CommandBuffer) { + todo!() + } + + fn load(&self, vulkan_context: &crate::vulkan::vulkan_context::VulkanContext) { + todo!() + } +} diff --git a/src/core/render/mod.rs b/src/core/render/mod.rs index 6f29814..5d003a8 100644 --- a/src/core/render/mod.rs +++ b/src/core/render/mod.rs @@ -1,2 +1,3 @@ +pub mod material; pub mod mesh; pub mod vertex; From b361965033337551f488e39f4bd81b945abf4754 Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Mon, 7 Apr 2025 22:51:49 +0200 Subject: [PATCH 35/41] Update --- src/core/render/material.rs | 7 ++++++ src/core/render/material/mod.rs | 10 -------- src/core/render/material/triangle.rs | 34 ---------------------------- src/core/render/vertex.rs | 2 +- src/vulkan/scene.rs | 24 +++++++++++++------- src/vulkan/vulkan_context.rs | 18 +-------------- 6 files changed, 25 insertions(+), 70 deletions(-) create mode 100644 src/core/render/material.rs delete mode 100644 src/core/render/material/mod.rs delete mode 100644 src/core/render/material/triangle.rs diff --git a/src/core/render/material.rs b/src/core/render/material.rs new file mode 100644 index 0000000..539d4bc --- /dev/null +++ b/src/core/render/material.rs @@ -0,0 +1,7 @@ +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/material/mod.rs b/src/core/render/material/mod.rs deleted file mode 100644 index 8cccde2..0000000 --- a/src/core/render/material/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -pub mod triangle; - -use vulkano::command_buffer::CommandBuffer; - -use crate::vulkan::vulkan_context::VulkanContext; - -pub trait Material { - fn load(&self, vulkan_context: &VulkanContext); - fn bind(&self, command_buffer: &mut CommandBuffer); -} diff --git a/src/core/render/material/triangle.rs b/src/core/render/material/triangle.rs deleted file mode 100644 index c3bafaa..0000000 --- a/src/core/render/material/triangle.rs +++ /dev/null @@ -1,34 +0,0 @@ -use glam::Vec4; -use vulkano::command_buffer::CommandBuffer; - -use super::Material; - -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 struct TriangleMaterial { - pub colors: [Vec4; 3], -} - -impl Material for TriangleMaterial { - fn bind(&self, command_buffer: &mut CommandBuffer) { - todo!() - } - - fn load(&self, vulkan_context: &crate::vulkan::vulkan_context::VulkanContext) { - todo!() - } -} diff --git a/src/core/render/vertex.rs b/src/core/render/vertex.rs index fc2ee21..9bf133e 100644 --- a/src/core/render/vertex.rs +++ b/src/core/render/vertex.rs @@ -1,10 +1,10 @@ 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; -use vulkano::Validated; #[derive(BufferContents, Vertex)] #[repr(C)] diff --git a/src/vulkan/scene.rs b/src/vulkan/scene.rs index 4d1de95..22986ff 100644 --- a/src/vulkan/scene.rs +++ b/src/vulkan/scene.rs @@ -3,9 +3,10 @@ use glam::{Mat3, Mat4, Vec3}; use std::error::Error; use std::sync::Arc; use std::time::Instant; -use vulkano::buffer::Subbuffer; +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; @@ -156,12 +157,19 @@ impl Scene { projection: proj.to_cols_array_2d(), }; - let buffer = vulkan_context - .uniform_buffer_allocator - .allocate_sized() - .unwrap(); - *buffer.write().unwrap() = uniform_data; - - buffer + 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/vulkan/vulkan_context.rs b/src/vulkan/vulkan_context.rs index ea1b29b..bad47de 100644 --- a/src/vulkan/vulkan_context.rs +++ b/src/vulkan/vulkan_context.rs @@ -2,10 +2,6 @@ use std::{any::Any, sync::Arc}; use vulkano::{ Version, VulkanLibrary, - buffer::{ - BufferUsage, - allocator::{SubbufferAllocator, SubbufferAllocatorCreateInfo}, - }, command_buffer::{ AutoCommandBufferBuilder, CommandBufferUsage, PrimaryAutoCommandBuffer, allocator::StandardCommandBufferAllocator, @@ -17,7 +13,7 @@ use vulkano::{ physical::{PhysicalDevice, PhysicalDeviceType}, }, instance::{Instance, InstanceCreateFlags, InstanceCreateInfo, InstanceExtensions}, - memory::allocator::{MemoryTypeFilter, StandardMemoryAllocator}, + memory::allocator::StandardMemoryAllocator, swapchain::Surface, }; use winit::{ @@ -32,7 +28,6 @@ pub struct VulkanContext { pub memory_allocator: Arc, pub command_buffer_allocator: Arc, - pub uniform_buffer_allocator: Arc, pub descriptor_set_allocator: Arc, } @@ -54,16 +49,6 @@ impl From<&EventLoop<()>> for VulkanContext { Default::default(), )); - let uniform_buffer_allocator = Arc::new(SubbufferAllocator::new( - memory_allocator.clone(), - SubbufferAllocatorCreateInfo { - buffer_usage: BufferUsage::UNIFORM_BUFFER, - memory_type_filter: MemoryTypeFilter::PREFER_DEVICE - | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, - ..Default::default() - }, - )); - let descriptor_set_allocator = Arc::new(StandardDescriptorSetAllocator::new( device.clone(), Default::default(), @@ -75,7 +60,6 @@ impl From<&EventLoop<()>> for VulkanContext { graphics_queue, memory_allocator, command_buffer_allocator, - uniform_buffer_allocator, descriptor_set_allocator, } } From f4694157ab53d3223089ad0032964dd67ca500da Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Sun, 13 Apr 2025 16:35:21 +0200 Subject: [PATCH 36/41] Update --- src/core/app/app.rs | 54 +++++++++++++++++++++++++++++++ src/core/app/mod.rs | 4 +++ src/core/app/plugin.rs | 5 +++ src/core/mod.rs | 2 ++ src/core/{app.rs => old_app.rs} | 0 src/core/window/mod.rs | 24 ++++++++++++++ src/core/window/window_handler.rs | 40 +++++++++++++++++++++++ src/main.rs | 17 ++++++++-- 8 files changed, 143 insertions(+), 3 deletions(-) create mode 100644 src/core/app/app.rs create mode 100644 src/core/app/mod.rs create mode 100644 src/core/app/plugin.rs rename src/core/{app.rs => old_app.rs} (100%) create mode 100644 src/core/window/mod.rs create mode 100644 src/core/window/window_handler.rs diff --git a/src/core/app/app.rs b/src/core/app/app.rs new file mode 100644 index 0000000..12b4be7 --- /dev/null +++ b/src/core/app/app.rs @@ -0,0 +1,54 @@ +use std::error::Error; + +use bevy_ecs::{schedule::Schedules, world::World}; + +pub enum AppExit { + Success, + Error(Box), +} + +pub type RunnerFn = Box AppExit>; + +pub struct App { + world: World, + runner: Option, +} + +impl Default for App { + fn default() -> Self { + let mut world = World::new(); + world.init_resource::(); + + Self { + world, + 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<(), Box> { + match self.runner.take() { + Some(runner) => match runner() { + AppExit::Success => Ok(()), + AppExit::Error(e) => Err(e), + }, + None => Err(Box::new(std::io::Error::new( + std::io::ErrorKind::Other, + "runner is not set", + ))), + } + } + + 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 new file mode 100644 index 0000000..f7320aa --- /dev/null +++ b/src/core/app/mod.rs @@ -0,0 +1,4 @@ +mod app; +pub mod plugin; + +pub use app::App; diff --git a/src/core/app/plugin.rs b/src/core/app/plugin.rs new file mode 100644 index 0000000..987c540 --- /dev/null +++ b/src/core/app/plugin.rs @@ -0,0 +1,5 @@ +use super::app::App; + +pub trait Plugin { + fn build(&self, app: &mut App); +} diff --git a/src/core/mod.rs b/src/core/mod.rs index f058532..07427ac 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -1,4 +1,6 @@ pub mod app; pub mod camera; +pub mod old_app; pub mod render; pub mod scene; +pub mod window; diff --git a/src/core/app.rs b/src/core/old_app.rs similarity index 100% rename from src/core/app.rs rename to src/core/old_app.rs diff --git a/src/core/window/mod.rs b/src/core/window/mod.rs new file mode 100644 index 0000000..55f6a70 --- /dev/null +++ b/src/core/window/mod.rs @@ -0,0 +1,24 @@ +pub mod window_handler; + +use super::app::{App, plugin::Plugin}; +use window_handler::WindowHandler; +use winit::event_loop::EventLoop; +use winit::window::WindowAttributes; + +pub struct WindowPlugin { + window_attributes: WindowAttributes, + event_loop: EventLoop<()>, +} + +impl Plugin for WindowPlugin { + fn build(&self, app: &mut App) { + let world = app.world_mut(); + world.insert_resource(WindowHandler::new(self.window_attributes.clone())); + + let window_handler = world.get_resource_mut::().unwrap(); + + // app.set_runner(Box::new(move || { + // self.event_loop.run_app(&mut window_handler); + // })); + } +} diff --git a/src/core/window/window_handler.rs b/src/core/window/window_handler.rs new file mode 100644 index 0000000..2b87d35 --- /dev/null +++ b/src/core/window/window_handler.rs @@ -0,0 +1,40 @@ +use bevy_ecs::system::Resource; +use winit::{ + application::ApplicationHandler, + event::WindowEvent, + event_loop::ActiveEventLoop, + window::{Window, WindowAttributes, WindowId}, +}; + +#[derive(Resource)] +pub struct WindowHandler { + window_attributes: WindowAttributes, + window: Option>, +} + +impl WindowHandler { + pub fn new(window_attributes: WindowAttributes) -> Self { + Self { + window_attributes, + window: None, + } + } +} +impl ApplicationHandler for WindowHandler { + fn resumed(&mut self, event_loop: &ActiveEventLoop) { + let window = event_loop + .create_window(self.window_attributes.clone()) + .unwrap(); + self.window = Some(Box::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/main.rs b/src/main.rs index 2b80274..f09236f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,14 +5,25 @@ pub mod core; pub mod game; pub mod vulkan; -fn main() -> Result<(), impl Error> { +fn main() -> Result<(), Box> { env_logger::init(); + run_old_app() +} + +fn run_new_app() -> Result<(), Box> { + let mut app = core::app::App::default(); + app.run() +} + +fn run_old_app() -> Result<(), Box> { let event_loop = EventLoop::new().unwrap(); event_loop.set_control_flow(ControlFlow::Poll); let vulkan_context = vulkan::vulkan_context::VulkanContext::from(&event_loop); - let mut app = core::app::App::from(vulkan_context); + let mut app = core::old_app::App::from(vulkan_context); - event_loop.run_app(&mut app) + event_loop.run_app(&mut app).map_err(Box::new)?; + + Ok(()) } From df99ef3a3f1641f4f753bb67de76f99c288532fc Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Sun, 13 Apr 2025 16:49:07 +0200 Subject: [PATCH 37/41] Add AppError --- Cargo.lock | 33 +++++++++++++++++++++++++++------ Cargo.toml | 1 + src/core/app/app.rs | 21 +++++++++++++-------- src/main.rs | 14 ++++++-------- 4 files changed, 47 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e35561c..da7454f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -65,7 +65,7 @@ dependencies = [ "ndk-context", "ndk-sys", "num_enum", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -384,7 +384,7 @@ dependencies = [ "polling", "rustix", "slab", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -863,7 +863,7 @@ dependencies = [ "combine", "jni-sys", "log", - "thiserror", + "thiserror 1.0.69", "walkdir", "windows-sys 0.45.0", ] @@ -975,7 +975,7 @@ dependencies = [ "ndk-sys", "num_enum", "raw-window-handle", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -1537,6 +1537,7 @@ dependencies = [ "env_logger", "glam", "log", + "thiserror 2.0.12", "vulkano", "vulkano-shaders", "winit", @@ -1695,7 +1696,7 @@ dependencies = [ "log", "memmap2", "rustix", - "thiserror", + "thiserror 1.0.69", "wayland-backend", "wayland-client", "wayland-csd-frame", @@ -1738,7 +1739,16 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", ] [[package]] @@ -1752,6 +1762,17 @@ 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" diff --git a/Cargo.toml b/Cargo.toml index a6ece63..a84f681 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ publish = false [dependencies] anyhow = "1.0" +thiserror = "2.0" winit = { version = "0.30", features = ["rwh_06"] } vulkano = "0.35" diff --git a/src/core/app/app.rs b/src/core/app/app.rs index 12b4be7..21ebd28 100644 --- a/src/core/app/app.rs +++ b/src/core/app/app.rs @@ -7,7 +7,15 @@ pub enum AppExit { Error(Box), } -pub type RunnerFn = Box AppExit>; +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, @@ -35,16 +43,13 @@ impl App { &self.world } - pub fn run(&mut self) -> Result<(), Box> { + pub fn run(mut self) -> Result<(), AppError> { match self.runner.take() { - Some(runner) => match runner() { + Some(runner) => match runner(self) { AppExit::Success => Ok(()), - AppExit::Error(e) => Err(e), + AppExit::Error(e) => Err(AppError::RunnerError(e)), }, - None => Err(Box::new(std::io::Error::new( - std::io::ErrorKind::Other, - "runner is not set", - ))), + None => Err(AppError::RunnerNotSet), } } diff --git a/src/main.rs b/src/main.rs index f09236f..9412fad 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,25 +5,23 @@ pub mod core; pub mod game; pub mod vulkan; -fn main() -> Result<(), Box> { +fn main() -> Result<(), impl Error> { env_logger::init(); - run_old_app() + run_new_app() } -fn run_new_app() -> Result<(), Box> { - let mut app = core::app::App::default(); +fn run_new_app() -> Result<(), impl Error> { + let app = core::app::App::default(); app.run() } -fn run_old_app() -> Result<(), Box> { +fn run_old_app() -> Result<(), impl Error> { let event_loop = EventLoop::new().unwrap(); event_loop.set_control_flow(ControlFlow::Poll); let vulkan_context = vulkan::vulkan_context::VulkanContext::from(&event_loop); let mut app = core::old_app::App::from(vulkan_context); - event_loop.run_app(&mut app).map_err(Box::new)?; - - Ok(()) + event_loop.run_app(&mut app) } From 4f6216635f7fe88577f6e05b624ceb6a19589a5b Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Sun, 13 Apr 2025 18:06:18 +0200 Subject: [PATCH 38/41] Update --- src/core/app/mod.rs | 4 +- src/core/app/plugin.rs | 5 --- src/core/mod.rs | 2 - src/core/scene.rs | 21 --------- src/core/window/config.rs | 17 +++++++ src/core/window/mod.rs | 37 ++++++++------- src/core/window/state.rs | 45 +++++++++++++++++++ src/core/window/window_handler.rs | 40 ----------------- src/game/mod.rs | 13 ++++++ src/main.rs | 12 ++--- src/{core/old_app.rs => old_app/app.rs} | 6 +-- src/{vulkan => old_app}/mod.rs | 4 +- src/{vulkan => old_app}/pipelines/mod.rs | 0 .../pipelines/triangle_pipeline.rs | 0 src/{vulkan => old_app}/scene.rs | 4 +- src/{vulkan => old_app}/vulkan_context.rs | 0 .../window_render_context.rs | 0 17 files changed, 110 insertions(+), 100 deletions(-) delete mode 100644 src/core/app/plugin.rs delete mode 100644 src/core/scene.rs create mode 100644 src/core/window/config.rs create mode 100644 src/core/window/state.rs delete mode 100644 src/core/window/window_handler.rs rename src/{core/old_app.rs => old_app/app.rs} (97%) rename src/{vulkan => old_app}/mod.rs (87%) rename src/{vulkan => old_app}/pipelines/mod.rs (100%) rename src/{vulkan => old_app}/pipelines/triangle_pipeline.rs (100%) rename src/{vulkan => old_app}/scene.rs (97%) rename src/{vulkan => old_app}/vulkan_context.rs (100%) rename src/{vulkan => old_app}/window_render_context.rs (100%) diff --git a/src/core/app/mod.rs b/src/core/app/mod.rs index f7320aa..c6c8a20 100644 --- a/src/core/app/mod.rs +++ b/src/core/app/mod.rs @@ -1,4 +1,2 @@ mod app; -pub mod plugin; - -pub use app::App; +pub use app::*; diff --git a/src/core/app/plugin.rs b/src/core/app/plugin.rs deleted file mode 100644 index 987c540..0000000 --- a/src/core/app/plugin.rs +++ /dev/null @@ -1,5 +0,0 @@ -use super::app::App; - -pub trait Plugin { - fn build(&self, app: &mut App); -} diff --git a/src/core/mod.rs b/src/core/mod.rs index 07427ac..bd7ce34 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -1,6 +1,4 @@ pub mod app; pub mod camera; -pub mod old_app; pub mod render; -pub mod scene; pub mod window; diff --git a/src/core/scene.rs b/src/core/scene.rs deleted file mode 100644 index a424da3..0000000 --- a/src/core/scene.rs +++ /dev/null @@ -1,21 +0,0 @@ -use bevy_ecs::world::World; - -pub struct Scene { - world: World, -} - -impl Scene { - pub fn new() -> Self { - Self { - world: World::new(), - } - } - - pub fn world(&self) -> &World { - &self.world - } - - pub fn world_mut(&mut self) -> &mut World { - &mut self.world - } -} diff --git a/src/core/window/config.rs b/src/core/window/config.rs new file mode 100644 index 0000000..8fbef8c --- /dev/null +++ b/src/core/window/config.rs @@ -0,0 +1,17 @@ +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 index 55f6a70..e600120 100644 --- a/src/core/window/mod.rs +++ b/src/core/window/mod.rs @@ -1,24 +1,27 @@ -pub mod window_handler; - -use super::app::{App, plugin::Plugin}; -use window_handler::WindowHandler; +use config::WindowConfig; +use state::WindowState; use winit::event_loop::EventLoop; -use winit::window::WindowAttributes; -pub struct WindowPlugin { - window_attributes: WindowAttributes, - event_loop: EventLoop<()>, +use super::app::{App, AppExit}; + +pub mod config; +pub mod state; + +pub fn init(app: &mut App, window_config: WindowConfig) { + 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().unwrap(); + + app.set_runner(Box::new(move |app| runner(app, event_loop))); } -impl Plugin for WindowPlugin { - fn build(&self, app: &mut App) { - let world = app.world_mut(); - world.insert_resource(WindowHandler::new(self.window_attributes.clone())); +fn runner(app: App, event_loop: EventLoop<()>) -> AppExit { + let mut window_state = WindowState::new(app); - let window_handler = world.get_resource_mut::().unwrap(); - - // app.set_runner(Box::new(move || { - // self.event_loop.run_app(&mut window_handler); - // })); + match event_loop.run_app(&mut window_state) { + Ok(_) => AppExit::Success, + Err(e) => AppExit::Error(Box::new(e)), } } diff --git a/src/core/window/state.rs b/src/core/window/state.rs new file mode 100644 index 0000000..94bfcc7 --- /dev/null +++ b/src/core/window/state.rs @@ -0,0 +1,45 @@ +use bevy_ecs::world::World; +use winit::{ + application::ApplicationHandler, + event::WindowEvent, + event_loop::ActiveEventLoop, + window::{Window, WindowId}, +}; + +use crate::core::app::App; + +use super::config::WindowConfig; + +pub struct WindowState { + app: App, + window: Option, +} + +impl WindowState { + pub fn new(app: App) -> Self { + Self { app, window: None } + } + + 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.window = Some(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/core/window/window_handler.rs b/src/core/window/window_handler.rs deleted file mode 100644 index 2b87d35..0000000 --- a/src/core/window/window_handler.rs +++ /dev/null @@ -1,40 +0,0 @@ -use bevy_ecs::system::Resource; -use winit::{ - application::ApplicationHandler, - event::WindowEvent, - event_loop::ActiveEventLoop, - window::{Window, WindowAttributes, WindowId}, -}; - -#[derive(Resource)] -pub struct WindowHandler { - window_attributes: WindowAttributes, - window: Option>, -} - -impl WindowHandler { - pub fn new(window_attributes: WindowAttributes) -> Self { - Self { - window_attributes, - window: None, - } - } -} -impl ApplicationHandler for WindowHandler { - fn resumed(&mut self, event_loop: &ActiveEventLoop) { - let window = event_loop - .create_window(self.window_attributes.clone()) - .unwrap(); - self.window = Some(Box::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/game/mod.rs b/src/game/mod.rs index 8b13789..ffee10f 100644 --- a/src/game/mod.rs +++ b/src/game/mod.rs @@ -1 +1,14 @@ +use crate::core::{ + app::App, + window::{self, config::WindowConfig}, +}; +pub fn init(app: &mut App) { + let window_config = WindowConfig { + title: "Rust ASH Test".to_string(), + width: 800, + height: 600, + }; + + window::init(app, window_config); +} diff --git a/src/main.rs b/src/main.rs index 9412fad..c981713 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,16 +3,18 @@ use winit::event_loop::{ControlFlow, EventLoop}; pub mod core; pub mod game; -pub mod vulkan; +pub mod old_app; fn main() -> Result<(), impl Error> { env_logger::init(); - run_new_app() + // run_new_app() + run_old_app() } fn run_new_app() -> Result<(), impl Error> { - let app = core::app::App::default(); + let mut app = core::app::App::default(); + game::init(&mut app); app.run() } @@ -20,8 +22,8 @@ fn run_old_app() -> Result<(), impl Error> { let event_loop = EventLoop::new().unwrap(); event_loop.set_control_flow(ControlFlow::Poll); - let vulkan_context = vulkan::vulkan_context::VulkanContext::from(&event_loop); - let mut app = core::old_app::App::from(vulkan_context); + let vulkan_context = old_app::vulkan_context::VulkanContext::from(&event_loop); + let mut app = old_app::app::App::from(vulkan_context); event_loop.run_app(&mut app) } diff --git a/src/core/old_app.rs b/src/old_app/app.rs similarity index 97% rename from src/core/old_app.rs rename to src/old_app/app.rs index 93a7d56..cfcf038 100644 --- a/src/core/old_app.rs +++ b/src/old_app/app.rs @@ -1,6 +1,6 @@ -use crate::vulkan::scene::Scene; -use crate::vulkan::vulkan_context::VulkanContext; -use crate::vulkan::window_render_context::WindowRenderContext; +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}; diff --git a/src/vulkan/mod.rs b/src/old_app/mod.rs similarity index 87% rename from src/vulkan/mod.rs rename to src/old_app/mod.rs index dc3d731..9fce0a9 100644 --- a/src/vulkan/mod.rs +++ b/src/old_app/mod.rs @@ -1,5 +1,5 @@ +pub mod app; pub mod pipelines; +pub mod scene; pub mod vulkan_context; pub mod window_render_context; - -pub mod scene; diff --git a/src/vulkan/pipelines/mod.rs b/src/old_app/pipelines/mod.rs similarity index 100% rename from src/vulkan/pipelines/mod.rs rename to src/old_app/pipelines/mod.rs diff --git a/src/vulkan/pipelines/triangle_pipeline.rs b/src/old_app/pipelines/triangle_pipeline.rs similarity index 100% rename from src/vulkan/pipelines/triangle_pipeline.rs rename to src/old_app/pipelines/triangle_pipeline.rs diff --git a/src/vulkan/scene.rs b/src/old_app/scene.rs similarity index 97% rename from src/vulkan/scene.rs rename to src/old_app/scene.rs index 22986ff..72e3f48 100644 --- a/src/vulkan/scene.rs +++ b/src/old_app/scene.rs @@ -1,4 +1,4 @@ -use crate::vulkan::pipelines::triangle_pipeline::shaders::vs; +use crate::old_app::pipelines::triangle_pipeline::shaders::vs; use glam::{Mat3, Mat4, Vec3}; use std::error::Error; use std::sync::Arc; @@ -10,7 +10,7 @@ use vulkano::memory::allocator::{AllocationCreateInfo, MemoryTypeFilter}; use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint}; use crate::core::render::vertex::Vertex2D; -use crate::vulkan::pipelines::triangle_pipeline::create_triangle_pipeline; +use crate::old_app::pipelines::triangle_pipeline::create_triangle_pipeline; use super::vulkan_context::VulkanContext; use super::window_render_context::WindowRenderContext; diff --git a/src/vulkan/vulkan_context.rs b/src/old_app/vulkan_context.rs similarity index 100% rename from src/vulkan/vulkan_context.rs rename to src/old_app/vulkan_context.rs diff --git a/src/vulkan/window_render_context.rs b/src/old_app/window_render_context.rs similarity index 100% rename from src/vulkan/window_render_context.rs rename to src/old_app/window_render_context.rs From e2616a0ef5af2ae8ff0d1e351017976f97c7138a Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Sun, 13 Apr 2025 18:45:33 +0200 Subject: [PATCH 39/41] Add vulkan creation from resources --- src/core/mod.rs | 1 + src/core/vulkan/context.rs | 65 ++++++++++++++++ src/core/vulkan/mod.rs | 24 ++++++ src/core/vulkan/utils.rs | 137 ++++++++++++++++++++++++++++++++++ src/core/window/mod.rs | 39 +++++++--- src/core/window/raw_handle.rs | 18 +++++ src/game/mod.rs | 6 +- src/main.rs | 4 +- 8 files changed, 281 insertions(+), 13 deletions(-) create mode 100644 src/core/vulkan/context.rs create mode 100644 src/core/vulkan/mod.rs create mode 100644 src/core/vulkan/utils.rs create mode 100644 src/core/window/raw_handle.rs diff --git a/src/core/mod.rs b/src/core/mod.rs index bd7ce34..abaeeae 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -1,4 +1,5 @@ pub mod app; pub mod camera; pub mod render; +pub mod vulkan; pub mod window; diff --git a/src/core/vulkan/context.rs b/src/core/vulkan/context.rs new file mode 100644 index 0000000..b4e9763 --- /dev/null +++ b/src/core/vulkan/context.rs @@ -0,0 +1,65 @@ +use std::sync::Arc; + +use bevy_ecs::system::Resource; +use vulkano::{ + command_buffer::allocator::StandardCommandBufferAllocator, + descriptor_set::allocator::StandardDescriptorSetAllocator, + device::{Device, Queue}, + instance::Instance, + memory::allocator::StandardMemoryAllocator, + swapchain::Surface, +}; + +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 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/mod.rs b/src/core/vulkan/mod.rs new file mode 100644 index 0000000..e80d56b --- /dev/null +++ b/src/core/vulkan/mod.rs @@ -0,0 +1,24 @@ +use context::VulkanContext; + +use super::app::App; + +mod context; +mod utils; + +#[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); + + Ok(()) + } +} diff --git a/src/core/vulkan/utils.rs b/src/core/vulkan/utils.rs new file mode 100644 index 0000000..046528f --- /dev/null +++ b/src/core/vulkan/utils.rs @@ -0,0 +1,137 @@ +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/window/mod.rs b/src/core/window/mod.rs index e600120..4368310 100644 --- a/src/core/window/mod.rs +++ b/src/core/window/mod.rs @@ -1,23 +1,44 @@ 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; -pub fn init(app: &mut App, window_config: WindowConfig) { - 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().unwrap(); - - app.set_runner(Box::new(move |app| runner(app, event_loop))); +#[derive(Debug, thiserror::Error)] +pub enum WindowError { + #[error("Failed to create event loop")] + FailedToCreateEventLoop, } -fn runner(app: App, event_loop: EventLoop<()>) -> AppExit { +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) { diff --git a/src/core/window/raw_handle.rs b/src/core/window/raw_handle.rs new file mode 100644 index 0000000..16b2178 --- /dev/null +++ b/src/core/window/raw_handle.rs @@ -0,0 +1,18 @@ +use bevy_ecs::system::Resource; +use winit::event_loop::EventLoopProxy; + +#[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); diff --git a/src/game/mod.rs b/src/game/mod.rs index ffee10f..0b7787d 100644 --- a/src/game/mod.rs +++ b/src/game/mod.rs @@ -1,6 +1,7 @@ use crate::core::{ app::App, - window::{self, config::WindowConfig}, + vulkan::Vulkan, + window::{Window, config::WindowConfig}, }; pub fn init(app: &mut App) { @@ -10,5 +11,6 @@ pub fn init(app: &mut App) { height: 600, }; - window::init(app, window_config); + Window::new(app, window_config).unwrap(); + Vulkan::new(app).unwrap(); } diff --git a/src/main.rs b/src/main.rs index c981713..8297797 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,8 +8,8 @@ pub mod old_app; fn main() -> Result<(), impl Error> { env_logger::init(); - // run_new_app() - run_old_app() + run_new_app() + // run_old_app() } fn run_new_app() -> Result<(), impl Error> { From a04c7694389af64c1e716f29949aa9b8155b786b Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Sun, 13 Apr 2025 19:23:05 +0200 Subject: [PATCH 40/41] Begin add Window Render Context --- src/core/vulkan/mod.rs | 10 +- .../vulkan/{context.rs => vulkan_context.rs} | 26 +++- src/core/vulkan/window_render_context.rs | 117 ++++++++++++++++++ src/core/window/raw_handle.rs | 7 +- src/core/window/state.rs | 17 +-- 5 files changed, 163 insertions(+), 14 deletions(-) rename src/core/vulkan/{context.rs => vulkan_context.rs} (69%) create mode 100644 src/core/vulkan/window_render_context.rs diff --git a/src/core/vulkan/mod.rs b/src/core/vulkan/mod.rs index e80d56b..fe22fb3 100644 --- a/src/core/vulkan/mod.rs +++ b/src/core/vulkan/mod.rs @@ -1,9 +1,11 @@ -use context::VulkanContext; +use vulkan_context::VulkanContext; +use window_render_context::WindowRenderContext; use super::app::App; -mod context; mod utils; +mod vulkan_context; +mod window_render_context; #[derive(Debug, thiserror::Error)] pub enum VulkanError { @@ -16,9 +18,11 @@ 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/context.rs b/src/core/vulkan/vulkan_context.rs similarity index 69% rename from src/core/vulkan/context.rs rename to src/core/vulkan/vulkan_context.rs index b4e9763..f59d9a3 100644 --- a/src/core/vulkan/context.rs +++ b/src/core/vulkan/vulkan_context.rs @@ -1,14 +1,18 @@ -use std::sync::Arc; +use std::{any::Any, sync::Arc}; use bevy_ecs::system::Resource; use vulkano::{ - command_buffer::allocator::StandardCommandBufferAllocator, + 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}; @@ -25,6 +29,24 @@ pub struct VulkanContext { 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(); diff --git a/src/core/vulkan/window_render_context.rs b/src/core/vulkan/window_render_context.rs new file mode 100644 index 0000000..1c653a7 --- /dev/null +++ b/src/core/vulkan/window_render_context.rs @@ -0,0 +1,117 @@ +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/raw_handle.rs b/src/core/window/raw_handle.rs index 16b2178..ad9c8dd 100644 --- a/src/core/window/raw_handle.rs +++ b/src/core/window/raw_handle.rs @@ -1,5 +1,7 @@ +use std::sync::Arc; + use bevy_ecs::system::Resource; -use winit::event_loop::EventLoopProxy; +use winit::{event_loop::EventLoopProxy, window::Window}; #[derive(Resource)] pub struct EventLoopProxyWrapper(EventLoopProxy); @@ -16,3 +18,6 @@ impl EventLoopProxyWrapper { #[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 index 94bfcc7..0b0966e 100644 --- a/src/core/window/state.rs +++ b/src/core/window/state.rs @@ -1,23 +1,22 @@ +use std::sync::Arc; + use bevy_ecs::world::World; use winit::{ - application::ApplicationHandler, - event::WindowEvent, - event_loop::ActiveEventLoop, - window::{Window, WindowId}, + application::ApplicationHandler, event::WindowEvent, event_loop::ActiveEventLoop, + window::WindowId, }; use crate::core::app::App; -use super::config::WindowConfig; +use super::{config::WindowConfig, raw_handle::WindowWrapper}; pub struct WindowState { app: App, - window: Option, } impl WindowState { pub fn new(app: App) -> Self { - Self { app, window: None } + Self { app } } fn world(&self) -> &World { @@ -30,7 +29,9 @@ impl ApplicationHandler for WindowState { let window_config = self.world().get_resource::().unwrap(); let window = event_loop.create_window(window_config.into()).unwrap(); - self.window = Some(window); + self.app + .world_mut() + .insert_resource(WindowWrapper(Arc::new(window))); } fn window_event(&mut self, event_loop: &ActiveEventLoop, _id: WindowId, event: WindowEvent) { From 8b0c59f7c0682a0391a9527033e56174640dc57f Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Sun, 13 Apr 2025 20:05:17 +0200 Subject: [PATCH 41/41] Remove useless schedule (for now) --- src/core/app/app.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/core/app/app.rs b/src/core/app/app.rs index 21ebd28..3821bfc 100644 --- a/src/core/app/app.rs +++ b/src/core/app/app.rs @@ -1,6 +1,6 @@ use std::error::Error; -use bevy_ecs::{schedule::Schedules, world::World}; +use bevy_ecs::world::World; pub enum AppExit { Success, @@ -24,11 +24,8 @@ pub struct App { impl Default for App { fn default() -> Self { - let mut world = World::new(); - world.init_resource::(); - Self { - world, + world: World::new(), runner: None, } }