Remove ECS pattern: Split into new repo
Some checks failed
Build legacy Nix package on Ubuntu / build (push) Failing after 6m2s

This commit is contained in:
Florian RICHER 2025-05-25 18:55:58 +02:00
parent d232706f68
commit f486486be3
Signed by: florian.richer
GPG key ID: C73D37CBED7BFC77
32 changed files with 23 additions and 1823 deletions

489
Cargo.lock generated
View file

@ -117,6 +117,12 @@ dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "anyhow"
version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
[[package]]
name = "arrayref"
version = "0.3.9"
@ -144,48 +150,11 @@ dependencies = [
"libloading",
]
[[package]]
name = "assert_type_match"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f548ad2c4031f2902e3edc1f29c29e835829437de49562d8eb5dc5584d3a1043"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "async-executor"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb812ffb58524bdd10860d7d974e2f01cc0950c2438a74ee5ec2e2280c6c4ffa"
dependencies = [
"async-task",
"concurrent-queue",
"fastrand",
"futures-lite",
"pin-project-lite",
"slab",
]
[[package]]
name = "async-task"
version = "4.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"
dependencies = [
"portable-atomic",
]
[[package]]
name = "atomic-waker"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
dependencies = [
"portable-atomic",
]
[[package]]
name = "autocfg"
@ -193,178 +162,6 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "bevy_app"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2b6267ac23a9947d5b2725ff047a1e1add70076d85fa9fb73d044ab9bea1f3c"
dependencies = [
"bevy_derive",
"bevy_ecs",
"bevy_platform",
"bevy_reflect",
"bevy_tasks",
"bevy_utils",
"cfg-if",
"ctrlc",
"downcast-rs 2.0.1",
"log",
"thiserror 2.0.12",
"variadics_please",
]
[[package]]
name = "bevy_derive"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f626531b9c05c25a758ede228727bd11c2c2c8498ecbed9925044386d525a2a3"
dependencies = [
"bevy_macro_utils",
"quote",
"syn",
]
[[package]]
name = "bevy_ecs"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9e807b5d9aab3bb8dfe47e7a44c9ff088bad2ceefe299b80ac77609a87fe9d4"
dependencies = [
"arrayvec",
"bevy_ecs_macros",
"bevy_platform",
"bevy_ptr",
"bevy_reflect",
"bevy_tasks",
"bevy_utils",
"bitflags 2.9.1",
"bumpalo",
"concurrent-queue",
"derive_more",
"disqualified",
"fixedbitset",
"indexmap",
"log",
"nonmax",
"serde",
"smallvec",
"thiserror 2.0.12",
"variadics_please",
]
[[package]]
name = "bevy_ecs_macros"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "467d7bb98aeb8dd30f36e6a773000c12a891d4f1bee2adc3841ec89cc8eaf54e"
dependencies = [
"bevy_macro_utils",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "bevy_macro_utils"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a2473db70d8785b5c75d6dd951a2e51e9be2c2311122db9692c79c9d887517b"
dependencies = [
"parking_lot",
"proc-macro2",
"quote",
"syn",
"toml_edit",
]
[[package]]
name = "bevy_platform"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "704db2c11b7bc31093df4fbbdd3769f9606a6a5287149f4b51f2680f25834ebc"
dependencies = [
"cfg-if",
"critical-section",
"foldhash",
"hashbrown",
"portable-atomic",
"portable-atomic-util",
"serde",
"spin",
]
[[package]]
name = "bevy_ptr"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86f1275dfb4cfef4ffc90c3fa75408964864facf833acc932413d52aa5364ba4"
[[package]]
name = "bevy_reflect"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "607ebacc31029cf2f39ac330eabf1d4bc411b159528ec08dbe6b0593eaccfd41"
dependencies = [
"assert_type_match",
"bevy_platform",
"bevy_ptr",
"bevy_reflect_derive",
"bevy_utils",
"derive_more",
"disqualified",
"downcast-rs 2.0.1",
"erased-serde",
"foldhash",
"glam 0.29.3",
"serde",
"smallvec",
"smol_str",
"thiserror 2.0.12",
"uuid",
"variadics_please",
"wgpu-types",
]
[[package]]
name = "bevy_reflect_derive"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf35e45e4eb239018369f63f2adc2107a54c329f9276d020e01eee1625b0238b"
dependencies = [
"bevy_macro_utils",
"proc-macro2",
"quote",
"syn",
"uuid",
]
[[package]]
name = "bevy_tasks"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "444c450b65e108855f42ecb6db0c041a56ea7d7f10cc6222f0ca95e9536a7d19"
dependencies = [
"async-executor",
"async-task",
"atomic-waker",
"bevy_platform",
"cfg-if",
"crossbeam-queue",
"derive_more",
"futures-lite",
"heapless",
]
[[package]]
name = "bevy_utils"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac2da3b3c1f94dadefcbe837aaa4aa119fcea37f7bdc5307eb05b4ede1921e24"
dependencies = [
"bevy_platform",
"thread_local",
]
[[package]]
name = "bitflags"
version = "1.3.2"
@ -376,9 +173,6 @@ name = "bitflags"
version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
dependencies = [
"serde",
]
[[package]]
name = "block2"
@ -415,12 +209,6 @@ dependencies = [
"syn",
]
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "bytes"
version = "1.10.1"
@ -514,7 +302,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
dependencies = [
"crossbeam-utils",
"portable-atomic",
]
[[package]]
@ -557,12 +344,6 @@ dependencies = [
"libc",
]
[[package]]
name = "critical-section"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
[[package]]
name = "crossbeam-queue"
version = "0.3.12"
@ -584,43 +365,12 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929"
[[package]]
name = "ctrlc"
version = "3.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46f93780a459b7d656ef7f071fe699c4d3d2cb201c4b24d085b6ddc505276e73"
dependencies = [
"nix",
"windows-sys 0.59.0",
]
[[package]]
name = "cursor-icon"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991"
[[package]]
name = "derive_more"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05"
dependencies = [
"derive_more-impl",
]
[[package]]
name = "derive_more-impl"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22"
dependencies = [
"proc-macro2",
"quote",
"syn",
"unicode-xid",
]
[[package]]
name = "dispatch"
version = "0.2.0"
@ -637,12 +387,6 @@ dependencies = [
"objc2 0.6.1",
]
[[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"
@ -658,55 +402,12 @@ version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
[[package]]
name = "downcast-rs"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea8a8b81cacc08888170eef4d13b775126db426d0b348bee9d18c2c1eaf123cf"
[[package]]
name = "dpi"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76"
[[package]]
name = "engine_render"
version = "0.1.0"
dependencies = [
"bevy_app",
"bevy_ecs",
"engine_vulkan",
"engine_window",
"log",
"vulkano",
]
[[package]]
name = "engine_vulkan"
version = "0.1.0"
dependencies = [
"bevy_app",
"bevy_ecs",
"engine_window",
"env_logger",
"log",
"thiserror 2.0.12",
"vulkano",
"winit",
]
[[package]]
name = "engine_window"
version = "0.1.0"
dependencies = [
"bevy_app",
"bevy_ecs",
"log",
"thiserror 2.0.12",
"winit",
]
[[package]]
name = "env_filter"
version = "0.1.3"
@ -736,16 +437,6 @@ 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.12"
@ -756,18 +447,6 @@ dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "fastrand"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
[[package]]
name = "fixedbitset"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
[[package]]
name = "foldhash"
version = "0.1.5"
@ -801,31 +480,6 @@ 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 = "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"
@ -848,15 +502,6 @@ dependencies = [
"wasi",
]
[[package]]
name = "glam"
version = "0.29.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8babf46d4c1c9d92deac9f7be466f76dfc4482b6452fc5024b5e8daf6ffeb3ee"
dependencies = [
"serde",
]
[[package]]
name = "glam"
version = "0.30.3"
@ -874,35 +519,11 @@ dependencies = [
"crunchy",
]
[[package]]
name = "hash32"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606"
dependencies = [
"byteorder",
]
[[package]]
name = "hashbrown"
version = "0.15.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
dependencies = [
"equivalent",
"serde",
]
[[package]]
name = "heapless"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad"
dependencies = [
"hash32",
"portable-atomic",
"stable_deref_trait",
]
[[package]]
name = "heck"
@ -1104,18 +725,6 @@ dependencies = [
"jni-sys",
]
[[package]]
name = "nix"
version = "0.30.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
dependencies = [
"bitflags 2.9.1",
"cfg-if",
"cfg_aliases",
"libc",
]
[[package]]
name = "nom"
version = "7.1.3"
@ -1126,12 +735,6 @@ 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"
@ -1435,12 +1038,6 @@ 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"
@ -1652,14 +1249,11 @@ dependencies = [
name = "rust_vulkan_test"
version = "0.1.0"
dependencies = [
"bevy_app",
"bevy_ecs",
"engine_render",
"engine_vulkan",
"engine_window",
"anyhow",
"env_logger",
"glam 0.30.3",
"glam",
"log",
"thiserror 2.0.12",
"vulkano",
"vulkano-shaders",
"winit",
@ -1838,21 +1432,6 @@ dependencies = [
"serde",
]
[[package]]
name = "spin"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
dependencies = [
"portable-atomic",
]
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "strict-num"
version = "0.1.1"
@ -1984,12 +1563,6 @@ 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"
@ -2002,41 +1575,12 @@ 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.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9"
dependencies = [
"getrandom",
"js-sys",
"serde",
"wasm-bindgen",
]
[[package]]
name = "variadics_please"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41b6d82be61465f97d42bd1d15bf20f3b0a3a0905018f38f9d6f6962055b0b5c"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "version_check"
version = "0.9.5"
@ -2208,7 +1752,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe770181423e5fc79d3e2a7f4410b7799d5aab1de4372853de3c6aa13ca24121"
dependencies = [
"cc",
"downcast-rs 1.2.1",
"downcast-rs",
"rustix",
"scoped-tls",
"smallvec",
@ -2330,19 +1874,6 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "wgpu-types"
version = "24.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50ac044c0e76c03a0378e7786ac505d010a873665e2d51383dcff8dd227dc69c"
dependencies = [
"bitflags 2.9.1",
"js-sys",
"log",
"serde",
"web-sys",
]
[[package]]
name = "winapi-util"
version = "0.1.9"

View file

@ -5,11 +5,7 @@ edition = "2024"
authors = ["Florian RICHER <florian.richer@protonmail.com>"]
publish = false
[workspace]
resolver = "2"
members = ["crates/*"]
[workspace.dependencies]
[dependencies]
anyhow = "1.0"
thiserror = "2.0"
winit = { version = "0.30", features = ["rwh_06"] }
@ -20,28 +16,7 @@ vulkano-shaders = "0.35"
# Math
glam = { version = "0.30" }
# ECS
bevy_ecs = "0.16"
bevy_app = "0.16"
# Log and tracing
log = "0.4"
env_logger = "0.11"
engine_vulkan = { path = "crates/engine_vulkan" }
engine_window = { path = "crates/engine_window" }
engine_render = { path = "crates/engine_render" }
[dependencies]
log = { workspace = true }
env_logger = { workspace = true }
bevy_app = { workspace = true }
bevy_ecs = { workspace = true }
winit = { workspace = true }
vulkano = { workspace = true }
vulkano-shaders = { workspace = true }
glam = { workspace = true }
engine_vulkan = { workspace = true }
engine_window = { workspace = true }
engine_render = { workspace = true }

View file

@ -1,12 +0,0 @@
[package]
name = "engine_render"
version = "0.1.0"
edition = "2024"
[dependencies]
log = { workspace = true }
bevy_app = { workspace = true }
bevy_ecs = { workspace = true }
vulkano = { workspace = true }
engine_vulkan = { workspace = true }
engine_window = { workspace = true }

View file

@ -1,120 +0,0 @@
use bevy_app::{App, AppLabel, Last, Plugin, SubApp};
use bevy_ecs::{
schedule::{IntoScheduleConfigs, Schedule, ScheduleLabel, SystemSet},
system::{Commands, Res},
world::World,
};
use engine_vulkan::{
VulkanCommandBufferAllocator, VulkanDescriptorSetAllocator, VulkanDevice, VulkanGraphicsQueue,
VulkanInstance, VulkanMemoryAllocator,
};
use engine_window::raw_handle::WindowWrapper;
use window::WindowRenderPlugin;
pub mod render;
pub mod window;
#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]
pub enum RenderSystems {
ManageViews,
Prepare,
Queue,
Render,
Present,
}
#[derive(ScheduleLabel, Debug, Hash, PartialEq, Eq, Clone, Default)]
pub struct Render;
impl Render {
pub fn base_schedule() -> Schedule {
use RenderSystems::*;
let mut schedule = Schedule::new(Self);
schedule.configure_sets((ManageViews, Prepare, Queue, Render, Present).chain());
schedule
}
}
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, AppLabel)]
pub struct RenderApp;
pub struct RenderPlugin;
impl Plugin for RenderPlugin {
fn build(&self, _app: &mut App) {}
fn ready(&self, app: &App) -> bool {
let world = app.world();
world.get_resource::<WindowWrapper>().is_some()
&& world.get_resource::<VulkanInstance>().is_some()
&& world.get_resource::<VulkanDevice>().is_some()
&& world.get_resource::<VulkanGraphicsQueue>().is_some()
&& world.get_resource::<VulkanMemoryAllocator>().is_some()
&& world
.get_resource::<VulkanCommandBufferAllocator>()
.is_some()
&& world
.get_resource::<VulkanDescriptorSetAllocator>()
.is_some()
}
fn finish(&self, app: &mut App) {
let mut render_app = SubApp::new();
render_app.update_schedule = Some(Render.intern());
render_app.add_schedule(Render::base_schedule());
render_app.add_systems(
Render,
render::render_system
.in_set(RenderSystems::Render)
.run_if(render::can_render),
);
extract_app_resources(app.world_mut(), render_app.world_mut());
app.insert_sub_app(RenderApp, render_app);
app.add_plugins(WindowRenderPlugin);
}
}
fn extract_app_resources(world: &mut World, render_world: &mut World) {
let window_wrapper = world
.get_resource::<WindowWrapper>()
.expect("Failed to get WindowWrapper. Check is WindowPlugin is added before RenderPlugin.");
let vulkan_instance = world.get_resource::<VulkanInstance>().expect(
"Failed to get Vulkan instance. Check is VulkanPlugin is added before RenderPlugin.",
);
let vulkan_device = world
.get_resource::<VulkanDevice>()
.expect("Failed to get Vulkan device. Check is VulkanPlugin is added before RenderPlugin.");
let vulkan_graphics_queue = world.get_resource::<VulkanGraphicsQueue>().expect(
"Failed to get Vulkan graphics queue. Check is VulkanPlugin is added before RenderPlugin.",
);
let vulkan_memory_allocator = world
.get_resource::<VulkanMemoryAllocator>()
.expect("Failed to get Vulkan memory allocator. Check is VulkanPlugin is added before RenderPlugin.");
let vulkan_command_buffer_allocator = world
.get_resource::<VulkanCommandBufferAllocator>()
.expect("Failed to get Vulkan command buffer allocator. Check is VulkanPlugin is added before RenderPlugin.");
let vulkan_descriptor_set_allocator = world
.get_resource::<VulkanDescriptorSetAllocator>()
.expect("Failed to get Vulkan descriptor set allocator. Check is VulkanPlugin is added before RenderPlugin.");
render_world.insert_resource(vulkan_instance.clone());
render_world.insert_resource(vulkan_device.clone());
render_world.insert_resource(vulkan_graphics_queue.clone());
render_world.insert_resource(vulkan_memory_allocator.clone());
render_world.insert_resource(vulkan_command_buffer_allocator.clone());
render_world.insert_resource(vulkan_descriptor_set_allocator.clone());
render_world.insert_resource(window_wrapper.clone());
}

View file

@ -1,122 +0,0 @@
use bevy_ecs::system::{Res, ResMut};
use engine_vulkan::{VulkanCommandBufferAllocator, VulkanDevice, VulkanGraphicsQueue};
use vulkano::{
Validated, VulkanError,
command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, RenderingAttachmentInfo, RenderingInfo,
},
render_pass::{AttachmentLoadOp, AttachmentStoreOp},
swapchain::{SwapchainAcquireFuture, SwapchainPresentInfo, acquire_next_image},
sync::{self, GpuFuture},
};
use crate::window::{WindowSurface, WindowSurfaceData};
pub fn can_render(window_surface: Res<WindowSurface>) -> bool {
window_surface.surface.is_some()
}
pub fn render_system(
mut window_surface: ResMut<WindowSurface>,
command_buffer_allocator: Res<VulkanCommandBufferAllocator>,
graphics_queue: Res<VulkanGraphicsQueue>,
device: Res<VulkanDevice>,
) {
{
let surface = window_surface.surface.as_ref().unwrap();
if surface.viewport.extent[0] == 0.0 || surface.viewport.extent[1] == 0.0 {
return;
}
}
let (image_index, acquire_future) =
match acquire_image(&mut window_surface.surface.as_mut().unwrap()) {
Some(r) => r,
None => return,
};
let mut builder = AutoCommandBufferBuilder::primary(
command_buffer_allocator.0.clone(),
graphics_queue.0.queue_family_index(),
CommandBufferUsage::OneTimeSubmit,
)
.expect("failed to create command buffer builder");
{
let surface = window_surface.surface.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, 0.0].into()),
..RenderingAttachmentInfo::image_view(
surface.attachment_image_views[image_index as usize].clone(),
)
})],
..Default::default()
})
.unwrap()
.set_viewport(0, [surface.viewport.clone()].into_iter().collect())
.unwrap();
}
builder.end_rendering().unwrap();
let command_buffer = builder.build().unwrap();
{
let surface = window_surface.surface.as_mut().unwrap();
let future = surface
.previous_frame_end
.take()
.unwrap()
.join(acquire_future)
.then_execute(graphics_queue.0.clone(), command_buffer)
.unwrap()
.then_swapchain_present(
graphics_queue.0.clone(),
SwapchainPresentInfo::swapchain_image_index(surface.swapchain.clone(), image_index),
)
.then_signal_fence_and_flush();
match future.map_err(Validated::unwrap) {
Ok(future) => {
surface.previous_frame_end = Some(future.boxed_send_sync());
}
Err(VulkanError::OutOfDate) => {
surface.recreate_swapchain = true;
surface.previous_frame_end = Some(sync::now(device.0.clone()).boxed_send_sync());
}
Err(e) => {
println!("failed to flush future: {e}");
surface.previous_frame_end = Some(sync::now(device.0.clone()).boxed_send_sync());
}
}
}
}
fn acquire_image(surface: &mut WindowSurfaceData) -> Option<(u32, SwapchainAcquireFuture)> {
surface
.previous_frame_end
.as_mut()
.unwrap()
.cleanup_finished();
let (image_index, suboptimal, acquire_future) =
match acquire_next_image(surface.swapchain.clone(), None).map_err(Validated::unwrap) {
Ok(r) => r,
Err(VulkanError::OutOfDate) => {
surface.recreate_swapchain = true;
return None;
}
Err(e) => panic!("failed to acquire next image: {e}"),
};
if suboptimal {
surface.recreate_swapchain = true;
}
Some((image_index, acquire_future))
}

View file

@ -1,222 +0,0 @@
use std::sync::Arc;
use bevy_app::{App, Plugin};
use bevy_ecs::{
resource::Resource,
schedule::IntoScheduleConfigs,
system::{Res, ResMut},
};
use engine_vulkan::{VulkanDevice, VulkanInstance};
use engine_window::raw_handle::WindowWrapper;
use vulkano::{
image::{Image, ImageUsage, view::ImageView},
pipeline::graphics::viewport::Viewport,
swapchain::{Surface, Swapchain, SwapchainCreateInfo},
sync::{self, GpuFuture},
};
use super::{Render, RenderApp, RenderSystems};
pub struct WindowSurfaceData {
pub swapchain: Arc<Swapchain>,
pub attachment_image_views: Vec<Arc<ImageView>>,
pub viewport: Viewport,
pub recreate_swapchain: bool,
pub previous_frame_end: Option<Box<dyn GpuFuture + Send + Sync>>,
}
#[derive(Resource, Default)]
pub struct WindowSurface {
pub surface: Option<WindowSurfaceData>,
}
pub struct WindowRenderPlugin;
impl Plugin for WindowRenderPlugin {
fn build(&self, app: &mut App) {
let render_app = app
.get_sub_app_mut(RenderApp)
.expect("Failed to get RenderApp. Check is RenderPlugin is added.");
render_app.init_resource::<WindowSurface>();
render_app.add_systems(
Render,
create_window_surface
.in_set(RenderSystems::ManageViews)
.run_if(need_create_window_surface)
.before(need_update_window_surface),
);
render_app.add_systems(
Render,
update_window_surface
.in_set(RenderSystems::ManageViews)
.run_if(need_update_window_surface),
);
}
}
fn need_create_window_surface(window_surface: Res<WindowSurface>) -> bool {
window_surface.surface.is_none()
}
fn create_window_surface(
mut window_surface: ResMut<WindowSurface>,
window_handle: Res<WindowWrapper>,
vulkan_instance: Res<VulkanInstance>,
vulkan_device: Res<VulkanDevice>,
) {
let window_size = window_handle.0.inner_size();
let surface = Surface::from_window(vulkan_instance.0.clone(), window_handle.0.clone())
.expect("Failed to create surface");
log::debug!("Surface created");
let (swapchain, images) = {
let surface_capabilities = vulkan_device
.0
.physical_device()
.surface_capabilities(&surface, Default::default())
.unwrap();
let (image_format, _) = vulkan_device
.0
.physical_device()
.surface_formats(&surface, Default::default())
.unwrap()[0];
Swapchain::new(
vulkan_device.0.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()
};
log_swapchain_info(&swapchain, false);
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,
};
log_viewport_info(&viewport, false);
let recreate_swapchain = false;
let previous_frame_end = Some(sync::now(vulkan_device.0.clone()).boxed_send_sync());
window_surface.surface = Some(WindowSurfaceData {
swapchain,
attachment_image_views,
viewport,
recreate_swapchain,
previous_frame_end,
});
}
fn window_size_dependent_setup(images: &[Arc<Image>]) -> Vec<Arc<ImageView>> {
images
.iter()
.map(|image| ImageView::new_default(image.clone()).unwrap())
.collect::<Vec<_>>()
}
fn need_update_window_surface(
window_surface: Res<WindowSurface>,
window_handle: Res<WindowWrapper>,
) -> bool {
match &window_surface.surface {
Some(surface) => {
let window_size: [f32; 2] = window_handle.0.inner_size().into();
surface.recreate_swapchain || surface.viewport.extent != window_size
}
None => false,
}
}
fn update_window_surface(
mut window_surface: ResMut<WindowSurface>,
window_handle: Res<WindowWrapper>,
) {
let window_surface = window_surface.surface.as_mut().unwrap();
let window_size = window_handle.0.inner_size();
let (new_swapchain, new_images) = window_surface
.swapchain
.recreate(SwapchainCreateInfo {
image_extent: window_size.into(),
..window_surface.swapchain.create_info()
})
.expect("Failed to recreate swapchain");
window_surface.swapchain = new_swapchain;
window_surface.attachment_image_views = window_size_dependent_setup(&new_images);
window_surface.viewport.extent = window_size.into();
window_surface.recreate_swapchain = false;
log_swapchain_info(&window_surface.swapchain, true);
log_viewport_info(&window_surface.viewport, true);
}
fn log_swapchain_info(swapchain: &Swapchain, recreate_swapchain: bool) {
if recreate_swapchain {
log::debug!("Swapchain recreated");
} else {
log::debug!("Swapchain created");
}
log::debug!(
"\tMin image count: {}",
swapchain.create_info().min_image_count
);
log::debug!("\tImage format: {:?}", swapchain.create_info().image_format);
log::debug!("\tImage extent: {:?}", swapchain.create_info().image_extent);
log::debug!("\tImage usage: {:?}", swapchain.create_info().image_usage);
log::debug!(
"\tComposite alpha: {:?}",
swapchain.create_info().composite_alpha
);
log::debug!("\tPresent mode: {:?}", swapchain.create_info().present_mode);
log::debug!(
"\tImage sharing: {:?}",
swapchain.create_info().image_sharing
);
log::debug!(
"\tPre transform: {:?}",
swapchain.create_info().pre_transform
);
log::debug!(
"\tComposite alpha: {:?}",
swapchain.create_info().composite_alpha
);
log::debug!("\tPresent mode: {:?}", swapchain.create_info().present_mode);
log::debug!(
"\tFull screen exclusive: {:?}",
swapchain.create_info().full_screen_exclusive
);
}
fn log_viewport_info(viewport: &Viewport, recreate_viewport: bool) {
if recreate_viewport {
log::debug!("Viewport recreated");
} else {
log::debug!("Viewport created");
}
log::debug!("\tOffset: {:?}", viewport.offset);
log::debug!("\tExtent: {:?}", viewport.extent);
log::debug!("\tDepth range: {:?}", viewport.depth_range);
}

View file

@ -1,14 +0,0 @@
[package]
name = "engine_vulkan"
version = "0.1.0"
edition = "2024"
[dependencies]
thiserror = { workspace = true }
log = { workspace = true }
env_logger = { workspace = true }
bevy_app = { workspace = true }
bevy_ecs = { workspace = true }
winit = { workspace = true }
vulkano = { workspace = true }
engine_window = { workspace = true }

View file

@ -1,214 +0,0 @@
use std::sync::Arc;
use bevy_ecs::world::World;
use engine_window::raw_handle::DisplayHandleWrapper;
use vulkano::{
command_buffer::allocator::StandardCommandBufferAllocator,
descriptor_set::allocator::StandardDescriptorSetAllocator,
device::{
Device, DeviceCreateInfo, DeviceExtensions, Queue,
physical::{PhysicalDevice, PhysicalDeviceType},
},
memory::allocator::StandardMemoryAllocator,
};
use crate::{
VulkanCommandBufferAllocator, VulkanComputeQueue, VulkanConfig, VulkanDescriptorSetAllocator,
VulkanDevice, VulkanGraphicsQueue, VulkanInstance, VulkanMemoryAllocator, VulkanTransferQueue,
queues::{VulkanQueueFamilyIndices, VulkanQueuesQuery, find_queues_family_indices},
};
pub fn create_and_insert_device(world: &mut World, config: &VulkanConfig) {
let picked_device =
pick_physical_device(world, &config).expect("Failed to pick physical device");
let device = picked_device.device;
let physical_device = device.physical_device();
log::debug!("Vulkan device created");
log::debug!(
"\tPhysical device: {:?} ({:?})",
physical_device.properties().device_name,
physical_device.properties().device_type
);
log::debug!("\tDevice extensions: {:?}", device.enabled_extensions());
log::debug!("\tDevice features: {:?}", device.enabled_features());
world.insert_resource(VulkanDevice(device.clone()));
log::debug!("\tDevice selected queues:");
if config.with_graphics_queue {
world.insert_resource(VulkanGraphicsQueue(
picked_device
.graphics_queue
.expect("Failed to get graphics queue"),
));
log::debug!("\t\t- Graphics queue");
}
if config.with_compute_queue {
world.insert_resource(VulkanComputeQueue(
picked_device
.compute_queue
.expect("Failed to get compute queue"),
));
log::debug!("\t\t- Compute queue");
}
if config.with_transfer_queue {
world.insert_resource(VulkanTransferQueue(
picked_device
.transfer_queue
.expect("Failed to get transfer queue"),
));
log::debug!("\t\t- Transfer queue");
}
world.insert_resource(VulkanMemoryAllocator(Arc::new(
StandardMemoryAllocator::new_default(device.clone()),
)));
world.insert_resource(VulkanCommandBufferAllocator(Arc::new(
StandardCommandBufferAllocator::new(device.clone(), Default::default()),
)));
world.insert_resource(VulkanDescriptorSetAllocator(Arc::new(
StandardDescriptorSetAllocator::new(device.clone(), Default::default()),
)));
}
struct PickedDevice {
pub device: Arc<Device>,
pub graphics_queue: Option<Arc<Queue>>,
pub compute_queue: Option<Arc<Queue>>,
pub transfer_queue: Option<Arc<Queue>>,
}
fn pick_physical_device(world: &World, config: &VulkanConfig) -> Option<PickedDevice> {
let instance = world
.get_resource::<VulkanInstance>()
.expect("Failed to get VulkanInstance during vulkan plugin initialization");
instance
.0
.enumerate_physical_devices()
.expect("Failed to enumerate physical devices")
.filter_map(|p| check_physical_device_support(world, &p, config).and_then(|r| Some((p, r))))
.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,
})
.take()
.and_then(|(p, (device_extensions, queue_family_indices))| {
Some(create_device(
config,
&p,
device_extensions,
queue_family_indices,
))
})
}
fn check_device_extensions_support(
physical_device: &Arc<PhysicalDevice>,
config: &VulkanConfig,
) -> Option<DeviceExtensions> {
let device_extensions = DeviceExtensions {
khr_swapchain: config.with_window_surface,
..config.device_extensions
};
if physical_device
.supported_extensions()
.contains(&device_extensions)
{
log::debug!(
"\t\t[OK] Device supports required extensions {:?}",
device_extensions
);
Some(device_extensions)
} else {
log::debug!(
"\t\t[FAILED] Device does not support required extensions {:?}",
device_extensions
);
None
}
}
fn check_physical_device_support(
world: &World,
physical_device: &Arc<PhysicalDevice>,
config: &VulkanConfig,
) -> Option<(DeviceExtensions, VulkanQueueFamilyIndices)> {
log::debug!("Checking physical device");
log::debug!("\tProperties");
log::debug!("\t\tName: {}", physical_device.properties().device_name);
log::debug!("\t\tAPI version: {}", physical_device.api_version());
log::debug!(
"\t\tDevice type: {:?}",
physical_device.properties().device_type
);
log::debug!("\tRequired supports checking report");
let device_extensions = check_device_extensions_support(physical_device, config)?;
let display_handle = world
.get_resource::<DisplayHandleWrapper>()
.expect("DisplayHandleWrapper must be added before VulkanPlugin");
let queue_support_query = VulkanQueuesQuery {
with_surface: Some(&display_handle),
with_graphics_queue: config.with_graphics_queue,
with_compute_queue: config.with_compute_queue,
with_transfer_queue: config.with_transfer_queue,
};
let queue_family_indices = find_queues_family_indices(physical_device, &queue_support_query);
log::debug!("\t\tQueue family indices: {:#?}", queue_family_indices);
Some((device_extensions, queue_family_indices))
}
fn create_device(
config: &VulkanConfig,
physical_device: &Arc<PhysicalDevice>,
device_extensions: DeviceExtensions,
queue_family_indices: VulkanQueueFamilyIndices,
) -> PickedDevice {
let (device, mut queues) = Device::new(
physical_device.clone(),
DeviceCreateInfo {
queue_create_infos: queue_family_indices.into(),
enabled_extensions: device_extensions,
enabled_features: config.device_features,
..Default::default()
},
)
.expect("Failed to create device");
let mut graphics_queue = None;
let mut compute_queue = None;
let mut transfer_queue = None;
if config.with_graphics_queue {
graphics_queue = queues.next();
}
if config.with_compute_queue {
compute_queue = queues.next();
}
if config.with_transfer_queue {
transfer_queue = queues.next();
}
PickedDevice {
device,
graphics_queue,
compute_queue,
transfer_queue,
}
}

View file

@ -1,70 +0,0 @@
use std::sync::Arc;
use bevy_ecs::world::World;
use engine_window::raw_handle::DisplayHandleWrapper;
use vulkano::{
VulkanLibrary,
instance::{Instance, InstanceCreateFlags, InstanceCreateInfo, InstanceExtensions},
swapchain::Surface,
};
use crate::{VulkanConfig, VulkanInstance};
fn load_library() -> Arc<VulkanLibrary> {
let library = VulkanLibrary::new().unwrap();
log::debug!("Available Instance layers:");
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 fn create_and_insert_instance(world: &mut World, config: &VulkanConfig) {
let library = load_library();
let instance_extensions = {
if config.with_window_surface {
let display_handle = world
.get_resource::<DisplayHandleWrapper>()
.expect("DisplayHandleWrapper must be added before VulkanPlugin");
Surface::required_extensions(&display_handle.0)
.expect("Failed to get surface required extensions")
} else {
InstanceExtensions::default()
}
};
let instance = Instance::new(
library,
InstanceCreateInfo {
// Enable enumerating devices that use non-conformant Vulkan implementations.
// (e.g. MoltenVK)
flags: InstanceCreateFlags::ENUMERATE_PORTABILITY,
enabled_extensions: instance_extensions,
enabled_layers: config.instance_layers.clone(),
..Default::default()
},
)
.expect("Failed to create vulkan instance");
log::debug!("Instance created");
log::debug!(
"\t- Enabled extensions: {:?}",
instance.enabled_extensions()
);
log::debug!("\t- Enabled layers: {:?}", instance.enabled_layers());
log::debug!("\t- API version: {:?}", instance.api_version());
log::debug!("\t- Max API version: {:?}", instance.max_api_version());
log::debug!("\t- Flags: {:?}", instance.flags());
world.insert_resource(VulkanInstance(instance));
}

View file

@ -1,85 +0,0 @@
use std::sync::Arc;
use bevy_app::{App, Plugin};
use bevy_ecs::resource::Resource;
use vulkano::{
command_buffer::allocator::StandardCommandBufferAllocator,
descriptor_set::allocator::StandardDescriptorSetAllocator,
device::{Device, DeviceExtensions, DeviceFeatures, Queue},
instance::Instance,
memory::allocator::StandardMemoryAllocator,
};
mod device;
mod instance;
mod queues;
use crate::{device::create_and_insert_device, instance::create_and_insert_instance};
#[derive(Resource, Clone)]
pub struct VulkanInstance(pub Arc<Instance>);
#[derive(Resource, Clone)]
pub struct VulkanDevice(pub Arc<Device>);
#[derive(Resource, Clone)]
pub struct VulkanGraphicsQueue(pub Arc<Queue>);
#[derive(Resource, Clone)]
pub struct VulkanComputeQueue(pub Arc<Queue>);
#[derive(Resource, Clone)]
pub struct VulkanTransferQueue(pub Arc<Queue>);
#[derive(Resource, Clone)]
pub struct VulkanMemoryAllocator(pub Arc<StandardMemoryAllocator>);
#[derive(Resource, Clone)]
pub struct VulkanCommandBufferAllocator(pub Arc<StandardCommandBufferAllocator>);
#[derive(Resource, Clone)]
pub struct VulkanDescriptorSetAllocator(pub Arc<StandardDescriptorSetAllocator>);
#[derive(Debug, thiserror::Error)]
pub enum VulkanError {
#[error("Failed to create vulkan context")]
FailedToCreateVulkanContext,
}
pub struct VulkanConfig {
pub instance_layers: Vec<String>,
pub device_extensions: DeviceExtensions,
pub device_features: DeviceFeatures,
pub with_window_surface: bool,
pub with_graphics_queue: bool,
pub with_compute_queue: bool,
pub with_transfer_queue: bool,
}
impl Default for VulkanConfig {
fn default() -> Self {
Self {
instance_layers: Vec::default(),
device_extensions: DeviceExtensions::default(),
device_features: DeviceFeatures::default(),
with_window_surface: true,
with_graphics_queue: true,
with_compute_queue: true,
with_transfer_queue: true,
}
}
}
#[derive(Default)]
pub struct VulkanPlugin {
pub vulkan_config: VulkanConfig,
}
impl Plugin for VulkanPlugin {
fn build(&self, app: &mut App) {
let world = app.world_mut();
create_and_insert_instance(world, &self.vulkan_config);
create_and_insert_device(world, &self.vulkan_config);
}
}

View file

@ -1,176 +0,0 @@
use std::{collections::HashMap, sync::Arc};
use engine_window::raw_handle::DisplayHandleWrapper;
use vulkano::device::{
QueueCreateInfo, QueueFamilyProperties, QueueFlags, physical::PhysicalDevice,
};
#[derive(Debug)]
pub enum VulkanQueueFamilyStatus {
Unused,
NotSupported,
Supported(u32),
}
impl VulkanQueueFamilyStatus {
pub fn can_be_set(&self) -> bool {
match self {
VulkanQueueFamilyStatus::NotSupported => true,
_ => false,
}
}
}
/// Convert a boolean to a VulkanQueueFamilyStatus as default value
impl From<bool> for VulkanQueueFamilyStatus {
fn from(value: bool) -> Self {
if value {
VulkanQueueFamilyStatus::NotSupported
} else {
VulkanQueueFamilyStatus::Unused
}
}
}
/// Convert a DisplayHandleWrapper Option to a VulkanQueueFamilyStatus as default value
impl From<Option<&DisplayHandleWrapper>> for VulkanQueueFamilyStatus {
fn from(value: Option<&DisplayHandleWrapper>) -> Self {
if value.is_some() {
VulkanQueueFamilyStatus::NotSupported
} else {
VulkanQueueFamilyStatus::Unused
}
}
}
#[derive(Debug)]
pub struct VulkanQueueFamilyIndices {
pub graphics_queue_family_index: VulkanQueueFamilyStatus,
pub compute_queue_family_index: VulkanQueueFamilyStatus,
pub transfer_queue_family_index: VulkanQueueFamilyStatus,
}
impl From<VulkanQueueFamilyIndices> for Vec<(VulkanQueueFamilyStatus, f32)> {
fn from(indices: VulkanQueueFamilyIndices) -> Self {
vec![
(indices.graphics_queue_family_index, 1.0),
(indices.compute_queue_family_index, 0.5),
(indices.transfer_queue_family_index, 0.5),
]
}
}
impl From<VulkanQueueFamilyIndices> for Vec<QueueCreateInfo> {
fn from(indices: VulkanQueueFamilyIndices) -> Self {
let mut queue_create_infos = HashMap::<u32, QueueCreateInfo>::new();
let statuses: Vec<(VulkanQueueFamilyStatus, f32)> = indices.into();
for (status, priority) in statuses.iter() {
match status {
VulkanQueueFamilyStatus::Supported(index) => {
let entry = queue_create_infos.entry(*index).or_insert(QueueCreateInfo {
queue_family_index: *index,
queues: Vec::new(),
..Default::default()
});
entry.queues.push(*priority);
}
_ => {}
}
}
queue_create_infos
.into_iter()
.map(|(_, value)| value)
.collect()
}
}
/// Convert a VulkanQueuesQuery to a VulkanQueuesFamilyIndices as default value
impl<'a> From<&'a VulkanQueuesQuery<'a>> for VulkanQueueFamilyIndices {
fn from(query: &'a VulkanQueuesQuery<'a>) -> Self {
VulkanQueueFamilyIndices {
graphics_queue_family_index: query.with_graphics_queue.into(),
compute_queue_family_index: query.with_compute_queue.into(),
transfer_queue_family_index: query.with_transfer_queue.into(),
}
}
}
pub struct VulkanQueuesQuery<'a> {
pub with_surface: Option<&'a DisplayHandleWrapper>,
pub with_graphics_queue: bool,
pub with_compute_queue: bool,
pub with_transfer_queue: bool,
}
pub fn find_queues_family_indices(
physical_device: &Arc<PhysicalDevice>,
query: &VulkanQueuesQuery,
) -> VulkanQueueFamilyIndices {
let mut indices: VulkanQueueFamilyIndices = query.into();
for (i, queue_family_properties) in physical_device.queue_family_properties().iter().enumerate()
{
let mut available_queue_count = queue_family_properties.queue_count;
if indices.graphics_queue_family_index.can_be_set()
&& check_queue_support(queue_family_properties, QueueFlags::GRAPHICS)
&& available_queue_count > 0
{
if query.with_surface.is_none()
|| check_presentation_support(
physical_device,
i as u32,
&query.with_surface.as_ref().unwrap(),
)
{
indices.graphics_queue_family_index = VulkanQueueFamilyStatus::Supported(i as u32);
available_queue_count -= 1;
}
}
if indices.compute_queue_family_index.can_be_set()
&& check_queue_support(queue_family_properties, QueueFlags::COMPUTE)
&& available_queue_count > 0
{
indices.compute_queue_family_index = VulkanQueueFamilyStatus::Supported(i as u32);
available_queue_count -= 1;
}
if indices.transfer_queue_family_index.can_be_set()
&& check_queue_support(queue_family_properties, QueueFlags::TRANSFER)
&& available_queue_count > 0
{
indices.transfer_queue_family_index = VulkanQueueFamilyStatus::Supported(i as u32);
}
if !indices.graphics_queue_family_index.can_be_set()
&& !indices.compute_queue_family_index.can_be_set()
&& !indices.transfer_queue_family_index.can_be_set()
{
break;
}
}
return indices;
}
fn check_presentation_support(
physical_device: &Arc<PhysicalDevice>,
queue_family_index: u32,
surface: &DisplayHandleWrapper,
) -> bool {
physical_device
.presentation_support(queue_family_index, &surface.0)
.unwrap()
}
fn check_queue_support(
queue_family_property: &QueueFamilyProperties,
queue_flags: QueueFlags,
) -> bool {
queue_family_property.queue_flags.intersects(queue_flags)
}

View file

@ -1,11 +0,0 @@
[package]
name = "engine_window"
version = "0.1.0"
edition = "2024"
[dependencies]
thiserror = { workspace = true }
log = { workspace = true }
bevy_app = { workspace = true }
bevy_ecs = { workspace = true }
winit = { workspace = true }

View file

@ -1,17 +0,0 @@
use bevy_ecs::resource::Resource;
use winit::{dpi::PhysicalSize, window::WindowAttributes};
#[derive(Resource, Clone)]
pub struct WindowConfig {
pub title: String,
pub width: u32,
pub height: u32,
}
impl Into<WindowAttributes> 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))
}
}

View file

@ -1,56 +0,0 @@
use bevy_app::{App, AppExit, Plugin, PluginsState};
use config::WindowConfig;
use raw_handle::{DisplayHandleWrapper, EventLoopProxyWrapper, WindowWrapper};
use state::WindowState;
use winit::event_loop::EventLoop;
pub mod config;
pub mod raw_handle;
pub mod state;
#[derive(Debug, thiserror::Error)]
pub enum WindowError {
#[error("Failed to create event loop")]
FailedToCreateEventLoop,
}
pub struct WindowPlugin {
pub window_config: WindowConfig,
}
impl Plugin for WindowPlugin {
fn build(&self, app: &mut App) {
let world = app.world_mut();
world.insert_resource(self.window_config.clone());
let mut event_loop_builder = EventLoop::with_user_event();
let event_loop = event_loop_builder
.build()
.map_err(|_| WindowError::FailedToCreateEventLoop)
.expect("Failed to create event loop");
world.insert_resource(DisplayHandleWrapper(event_loop.owned_display_handle()));
app.set_runner(Box::new(move |app| runner(app, event_loop)));
}
}
fn runner(mut app: App, event_loop: EventLoop<()>) -> AppExit {
if app.plugins_state() == PluginsState::Ready {
app.finish();
app.cleanup();
}
app.world_mut()
.insert_resource(EventLoopProxyWrapper::new(event_loop.create_proxy()));
let mut window_state = WindowState::new(app);
match event_loop.run_app(&mut window_state) {
Ok(_) => AppExit::Success,
Err(e) => {
log::error!("Error running window state: {e}");
AppExit::error()
}
}
}

View file

@ -1,23 +0,0 @@
use std::sync::Arc;
use bevy_ecs::resource::Resource;
use winit::{event_loop::EventLoopProxy, window::Window};
#[derive(Resource)]
pub struct EventLoopProxyWrapper<T: 'static>(EventLoopProxy<T>);
impl<T: 'static> EventLoopProxyWrapper<T> {
pub fn new(event_loop: EventLoopProxy<T>) -> Self {
Self(event_loop)
}
pub fn proxy(&self) -> &EventLoopProxy<T> {
&self.0
}
}
#[derive(Resource, Clone)]
pub struct DisplayHandleWrapper(pub winit::event_loop::OwnedDisplayHandle);
#[derive(Resource, Clone)]
pub struct WindowWrapper(pub Arc<Window>);

View file

@ -1,63 +0,0 @@
use std::sync::Arc;
use bevy_app::{App, PluginsState};
use bevy_ecs::world::World;
use winit::{
application::ApplicationHandler, event::WindowEvent, event_loop::ActiveEventLoop,
window::WindowId,
};
use super::{config::WindowConfig, raw_handle::WindowWrapper};
pub struct WindowState {
app: App,
}
impl WindowState {
pub fn new(app: App) -> Self {
Self { app }
}
fn world(&self) -> &World {
self.app.world()
}
}
impl ApplicationHandler for WindowState {
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
let window_config = self.world().get_resource::<WindowConfig>().unwrap();
let window = event_loop.create_window(window_config.into()).unwrap();
self.app
.world_mut()
.insert_resource(WindowWrapper(Arc::new(window)));
}
fn new_events(&mut self, event_loop: &ActiveEventLoop, cause: winit::event::StartCause) {
if self.app.plugins_state() == PluginsState::Ready {
self.app.finish();
self.app.cleanup();
}
}
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::RedrawRequested => {
if self.app.plugins_state() == PluginsState::Cleaned {
self.app.update();
}
let window_wrapper = self.app.world().get_resource::<WindowWrapper>().unwrap();
window_wrapper.0.request_redraw();
}
_ => {}
}
}
fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) {}
}

View file

@ -76,7 +76,7 @@
packages = {
default = rustPlatform.buildRustPackage {
pname = "rust_ash_test";
pname = "vulkan_test";
version = "0.1.0";
src = self;

View file

@ -1,19 +0,0 @@
use bevy_ecs::component::Component;
use glam::{Mat4, Quat, Vec3};
pub trait Camera: Into<Mat4> + Component {}
#[derive(Component)]
pub struct Camera3D {
pub projection: Mat4,
pub position: Vec3,
pub rotation: Quat,
}
impl Into<Mat4> for Camera3D {
fn into(self) -> Mat4 {
Mat4::from_rotation_translation(self.rotation, self.position) * self.projection
}
}
impl Camera for Camera3D {}

View file

@ -1,2 +0,0 @@
pub mod camera;
pub mod render;

View file

@ -1,7 +0,0 @@
use std::sync::Arc;
use bevy_ecs::component::Component;
use vulkano::pipeline::GraphicsPipeline;
#[derive(Component)]
pub struct Material(pub Arc<GraphicsPipeline>);

View file

@ -1,14 +0,0 @@
use bevy_ecs::component::Component;
use super::vertex::Vertex2D;
#[derive(Component)]
pub struct Mesh2D {
pub vertices: Vec<Vertex2D>,
}
impl Mesh2D {
pub fn new(vertices: Vec<Vertex2D>) -> Self {
Self { vertices }
}
}

View file

@ -1,3 +0,0 @@
pub mod material;
pub mod mesh;
pub mod vertex;

View file

@ -1,36 +0,0 @@
use bevy_app::App;
use engine_render::RenderPlugin;
use engine_vulkan::{VulkanConfig, VulkanPlugin};
use engine_window::{WindowPlugin, config::WindowConfig};
use vulkano::device::{DeviceExtensions, DeviceFeatures};
pub fn init(app: &mut App) {
let window_config = WindowConfig {
title: "Rust ASH Test".to_string(),
width: 800,
height: 600,
};
let device_extensions = DeviceExtensions {
khr_dynamic_rendering: true,
..Default::default()
};
let device_features = DeviceFeatures {
dynamic_rendering: true,
..Default::default()
};
let vulkan_config = VulkanConfig {
instance_layers: vec![String::from("VK_LAYER_KHRONOS_validation")],
device_extensions,
device_features,
..Default::default()
};
app.add_plugins((
WindowPlugin { window_config },
VulkanPlugin { vulkan_config },
RenderPlugin,
));
}

View file

@ -1,35 +1,14 @@
use winit::event_loop::{ControlFlow, EventLoop};
use bevy_app::{App, AppExit};
pub mod core;
pub mod game;
pub mod old_app;
mod render;
fn main() {
env_logger::init();
run_new_app();
// run_old_app();
}
fn run_new_app() {
let mut app = App::default();
game::init(&mut app);
match app.run() {
AppExit::Success => {}
AppExit::Error(e) => {
log::error!("Error running new app: {e}");
}
}
}
fn run_old_app() {
let event_loop = EventLoop::new().unwrap();
event_loop.set_control_flow(ControlFlow::Poll);
let vulkan_context = old_app::vulkan_context::VulkanContext::from(&event_loop);
let mut app = old_app::app::App::from(vulkan_context);
let vulkan_context = render::vulkan_context::VulkanContext::from(&event_loop);
let mut app = render::app::App::from(vulkan_context);
match event_loop.run_app(&mut app) {
Ok(_) => {}

View file

@ -1,6 +1,6 @@
use crate::old_app::scene::Scene;
use crate::old_app::vulkan_context::VulkanContext;
use crate::old_app::window_render_context::WindowRenderContext;
use crate::render::scene::Scene;
use crate::render::vulkan_context::VulkanContext;
use crate::render::window_render_context::WindowRenderContext;
use std::sync::Arc;
use vulkano::command_buffer::{RenderingAttachmentInfo, RenderingInfo};
use vulkano::render_pass::{AttachmentLoadOp, AttachmentStoreOp};

View file

@ -3,3 +3,4 @@ pub mod pipelines;
pub mod scene;
pub mod vulkan_context;
pub mod window_render_context;
pub mod vertex;

View file

@ -20,7 +20,7 @@ use vulkano::pipeline::{
use vulkano::shader::{EntryPoint, ShaderStages};
use vulkano::swapchain::Swapchain;
use crate::core::render::vertex::Vertex2D;
use crate::render::vertex::Vertex2D;
pub mod shaders {
pub mod vs {

View file

@ -1,4 +1,4 @@
use crate::old_app::pipelines::triangle_pipeline::shaders::vs;
use crate::render::pipelines::triangle_pipeline::shaders::vs;
use glam::{Mat3, Mat4, Vec3};
use std::error::Error;
use std::sync::Arc;
@ -9,8 +9,8 @@ use vulkano::descriptor_set::{DescriptorSet, WriteDescriptorSet};
use vulkano::memory::allocator::{AllocationCreateInfo, MemoryTypeFilter};
use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint};
use crate::core::render::vertex::Vertex2D;
use crate::old_app::pipelines::triangle_pipeline::create_triangle_pipeline;
use crate::render::vertex::Vertex2D;
use crate::render::pipelines::triangle_pipeline::create_triangle_pipeline;
use super::vulkan_context::VulkanContext;
use super::window_render_context::WindowRenderContext;