diff --git a/Cargo.lock b/Cargo.lock index 84d93d9..7297667 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,37 +18,6 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" -[[package]] -name = "accesskit" -version = "0.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3d3b8f9bae46a948369bc4a03e815d4ed6d616bd00de4051133a5019dc31c5a" -dependencies = [ - "enumn", - "serde", -] - -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "adler2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" - [[package]] name = "ahash" version = "0.8.11" @@ -56,19 +25,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "getrandom 0.2.15", + "getrandom", "once_cell", - "serde", "version_check", - "zerocopy 0.7.35", + "zerocopy", ] -[[package]] -name = "aligned-vec" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1" - [[package]] name = "android-activity" version = "0.6.0" @@ -152,43 +114,6 @@ version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" -[[package]] -name = "arbitrary" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" - -[[package]] -name = "arboard" -version = "3.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1df21f715862ede32a0c525ce2ca4d52626bb0007f8c18b87a384503ac33e70" -dependencies = [ - "clipboard-win", - "image", - "log", - "objc2 0.6.0", - "objc2-app-kit 0.3.0", - "objc2-core-foundation", - "objc2-core-graphics", - "objc2-foundation 0.3.0", - "parking_lot", - "percent-encoding", - "windows-sys 0.59.0", - "x11rb", -] - -[[package]] -name = "arg_enum_proc_macro" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "arrayref" version = "0.3.9" @@ -239,56 +164,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" -[[package]] -name = "av1-grain" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6678909d8c5d46a42abcf571271e15fdbc0a225e3646cf23762cd415046c78bf" -dependencies = [ - "anyhow", - "arrayvec", - "log", - "nom", - "num-rational", - "v_frame", -] - -[[package]] -name = "avif-serialize" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98922d6a4cfbcb08820c69d8eeccc05bb1f29bfa06b4f5b1dbfe9a868bd7608e" -dependencies = [ - "arrayvec", -] - -[[package]] -name = "backtrace" -version = "0.3.71" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide 0.7.4", - "object", - "rustc-demangle", -] - -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "bit_field" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" - [[package]] name = "bitflags" version = "1.3.2" @@ -301,12 +176,6 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" -[[package]] -name = "bitstream-io" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2" - [[package]] name = "block" version = "0.1.6" @@ -319,15 +188,9 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" dependencies = [ - "objc2 0.5.2", + "objc2", ] -[[package]] -name = "built" -version = "0.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b" - [[package]] name = "bumpalo" version = "3.17.0" @@ -345,27 +208,15 @@ dependencies = [ [[package]] name = "bytemuck_derive" -version = "1.9.3" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ecc273b49b3205b83d648f0690daa588925572cc5063745bfe547fe7ec8e1a1" +checksum = "2ff22c2722516255d1823ce3cc4bc0b154dbc9364be5c905d6baa6eccbbc8774" dependencies = [ "proc-macro2", "quote", "syn", ] -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "byteorder-lite" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" - [[package]] name = "bytes" version = "1.10.1" @@ -415,16 +266,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" -[[package]] -name = "cfg-expr" -version = "0.15.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" -dependencies = [ - "smallvec", - "target-lexicon", -] - [[package]] name = "cfg-if" version = "1.0.0" @@ -439,9 +280,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "clap" -version = "4.5.35" +version = "4.5.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944" +checksum = "e958897981290da2a852763fe9cdb89cd36977a5d729023127095fa94d95e2ff" dependencies = [ "clap_builder", "clap_derive", @@ -449,9 +290,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.35" +version = "4.5.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9" +checksum = "83b0f35019843db2160b5bb19ae09b4e6411ac33fc6a712003c33e03090e2489" dependencies = [ "anstream", "anstyle", @@ -477,15 +318,6 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" -[[package]] -name = "clipboard-win" -version = "5.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15efe7a882b08f34e38556b14f2fb3daa98769d06c7f0c1b076dfd0d983bc892" -dependencies = [ - "error-code", -] - [[package]] name = "cmake" version = "0.1.54" @@ -504,7 +336,7 @@ dependencies = [ "bitflags 1.3.2", "block", "cocoa-foundation", - "core-foundation 0.9.4", + "core-foundation", "core-graphics", "foreign-types", "libc", @@ -519,45 +351,12 @@ checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" dependencies = [ "bitflags 1.3.2", "block", - "core-foundation 0.9.4", + "core-foundation", "core-graphics-types", "libc", "objc", ] -[[package]] -name = "color-eyre" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55146f5e46f237f7423d74111267d4597b59b0dad0ffaf7303bce9945d843ad5" -dependencies = [ - "backtrace", - "color-spantrace", - "eyre", - "indenter", - "once_cell", - "owo-colors", - "tracing-error", -] - -[[package]] -name = "color-spantrace" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2" -dependencies = [ - "once_cell", - "owo-colors", - "tracing-core", - "tracing-error", -] - -[[package]] -name = "color_quant" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" - [[package]] name = "colorchoice" version = "1.0.3" @@ -593,16 +392,6 @@ dependencies = [ "libc", ] -[[package]] -name = "core-foundation" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -616,7 +405,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" dependencies = [ "bitflags 1.3.2", - "core-foundation 0.9.4", + "core-foundation", "core-graphics-types", "foreign-types", "libc", @@ -629,139 +418,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" dependencies = [ "bitflags 1.3.2", - "core-foundation 0.9.4", + "core-foundation", "libc", ] -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "crossbeam-utils" version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" -[[package]] -name = "crunchy" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" - [[package]] name = "cursor-icon" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" -[[package]] -name = "darling" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn", -] - -[[package]] -name = "darling_macro" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" -dependencies = [ - "darling_core", - "quote", - "syn", -] - -[[package]] -name = "derive_builder" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" -dependencies = [ - "derive_builder_macro", -] - -[[package]] -name = "derive_builder_core" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "derive_builder_macro" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" -dependencies = [ - "derive_builder_core", - "syn", -] - [[package]] name = "dispatch" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "dlib" version = "0.5.2" @@ -789,9 +467,7 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc4feb366740ded31a004a0e4452fbf84e80ef432ecf8314c485210229672fd1" dependencies = [ - "bytemuck", "emath", - "serde", ] [[package]] @@ -800,15 +476,12 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25dd34cec49ab55d85ebf70139cb1ccd29c977ef6b6ba4fe85489d6877ee9ef3" dependencies = [ - "accesskit", "ahash", "bitflags 2.9.0", "emath", "epaint", - "log", "nohash-hasher", "profiling", - "serde", ] [[package]] @@ -824,53 +497,11 @@ dependencies = [ "thiserror 2.0.12", ] -[[package]] -name = "egui-winit" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d9dfbb78fe4eb9c3a39ad528b90ee5915c252e77bbab9d4ebc576541ab67e13" -dependencies = [ - "ahash", - "arboard", - "bytemuck", - "egui", - "log", - "profiling", - "raw-window-handle", - "smithay-clipboard", - "web-time", - "webbrowser", - "winit", -] - -[[package]] -name = "egui_tiles" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67756b63b283a65bd0534b0c2a5fb1a12a5768bb6383d422147cc93193d09cfc" -dependencies = [ - "ahash", - "egui", - "itertools 0.13.0", - "log", - "serde", -] - -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - [[package]] name = "emath" version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e4cadcff7a5353ba72b7fea76bf2122b5ebdbc68e8155aa56dfdea90083fe1b" -dependencies = [ - "bytemuck", - "serde", -] [[package]] name = "engine" @@ -879,34 +510,17 @@ dependencies = [ "ash", "ash-window", "clap", - "color-eyre", "egui", - "egui-winit", - "egui_tiles", "gfx_hal", - "glam", "raw-window-handle", "renderer", "resource_manager", - "scene", - "shared", "thiserror 2.0.12", "tracing", "tracing-subscriber", "winit", ] -[[package]] -name = "enumn" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "epaint" version = "0.31.1" @@ -915,15 +529,12 @@ checksum = "41fcc0f5a7c613afd2dee5e4b30c3e6acafb8ad6f0edb06068811f708a67c562" dependencies = [ "ab_glyph", "ahash", - "bytemuck", "ecolor", "emath", "epaint_default_fonts", - "log", "nohash-hasher", "parking_lot", "profiling", - "serde", ] [[package]] @@ -948,62 +559,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "error-code" -version = "3.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5d9305ccc6942a704f4335694ecd3de2ea531b114ac2d51f5f843750787a92f" - -[[package]] -name = "exr" -version = "1.73.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83197f59927b46c04a183a619b7c29df34e63e63c7869320862268c0ef687e0" -dependencies = [ - "bit_field", - "half", - "lebe", - "miniz_oxide 0.8.7", - "rayon-core", - "smallvec", - "zune-inflate", -] - -[[package]] -name = "eyre" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" -dependencies = [ - "indenter", - "once_cell", -] - -[[package]] -name = "fdeflate" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" -dependencies = [ - "simd-adler32", -] - -[[package]] -name = "flate2" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" -dependencies = [ - "crc32fast", - "miniz_oxide 0.8.7", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - [[package]] name = "foreign-types" version = "0.5.0" @@ -1031,15 +586,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - [[package]] name = "gethostname" version = "0.4.3" @@ -1058,19 +604,7 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", -] - -[[package]] -name = "getrandom" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" -dependencies = [ - "cfg-if", - "libc", - "r-efi", - "wasi 0.14.2+wasi-0.2.4", + "wasi", ] [[package]] @@ -1079,28 +613,12 @@ version = "0.1.0" dependencies = [ "ash", "ash-window", - "gpu-allocator", + "parking_lot", "thiserror 2.0.12", "tracing", "winit", ] -[[package]] -name = "gif" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2" -dependencies = [ - "color_quant", - "weezl", -] - -[[package]] -name = "gimli" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" - [[package]] name = "glam" version = "0.22.0" @@ -1111,45 +629,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "gltf" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ce1918195723ce6ac74e80542c5a96a40c2b26162c1957a5cd70799b8cacf7" -dependencies = [ - "base64", - "byteorder", - "gltf-json", - "image", - "lazy_static", - "serde_json", - "urlencoding", -] - -[[package]] -name = "gltf-derive" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14070e711538afba5d6c807edb74bcb84e5dbb9211a3bf5dea0dfab5b24f4c51" -dependencies = [ - "inflections", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "gltf-json" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6176f9d60a7eab0a877e8e96548605dedbde9190a7ae1e80bbcc1c9af03ab14" -dependencies = [ - "gltf-derive", - "serde", - "serde_derive", - "serde_json", -] - [[package]] name = "gpu-allocator" version = "0.27.0" @@ -1163,16 +642,6 @@ dependencies = [ "windows", ] -[[package]] -name = "half" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7db2ff139bba50379da6aa0766b52fdcb62cb5b263009b09ed58ba604e14bbd1" -dependencies = [ - "cfg-if", - "crunchy", -] - [[package]] name = "hashbrown" version = "0.15.2" @@ -1191,205 +660,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" -[[package]] -name = "home" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "icu_collections" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locid" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" - -[[package]] -name = "icu_normalizer" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "utf16_iter", - "utf8_iter", - "write16", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" - -[[package]] -name = "icu_properties" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_locid_transform", - "icu_properties_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" - -[[package]] -name = "icu_provider" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_provider_macros", - "stable_deref_trait", - "tinystr", - "writeable", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "idna" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[package]] -name = "image" -version = "0.25.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a" -dependencies = [ - "bytemuck", - "byteorder-lite", - "color_quant", - "exr", - "gif", - "image-webp", - "num-traits", - "png", - "qoi", - "ravif", - "rayon", - "rgb", - "tiff", - "zune-core", - "zune-jpeg", -] - -[[package]] -name = "image-webp" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b77d01e822461baa8409e156015a1d91735549f0f2c17691bd2d996bef238f7f" -dependencies = [ - "byteorder-lite", - "quick-error", -] - -[[package]] -name = "imgref" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408" - -[[package]] -name = "indenter" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" - [[package]] name = "indexmap" version = "2.8.0" @@ -1400,52 +670,17 @@ dependencies = [ "hashbrown", ] -[[package]] -name = "inflections" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a257582fdcde896fd96463bf2d40eefea0580021c0712a0e2b028b60b47a837a" - -[[package]] -name = "interpolate_name" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "is_terminal_polyfill" version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] - [[package]] name = "itoa" -version = "1.0.15" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "jni" @@ -1471,20 +706,13 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.33" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" dependencies = [ - "getrandom 0.3.2", "libc", ] -[[package]] -name = "jpeg-decoder" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" - [[package]] name = "js-sys" version = "0.3.77" @@ -1501,28 +729,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -[[package]] -name = "lebe" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" - [[package]] name = "libc" version = "0.2.171" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" -[[package]] -name = "libfuzzer-sys" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf78f52d400cf2d84a3a973a78a592b4adc535739e0a5597a0da6f0c357adc75" -dependencies = [ - "arbitrary", - "cc", -] - [[package]] name = "libloading" version = "0.8.6" @@ -1565,12 +777,6 @@ version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" -[[package]] -name = "litemap" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" - [[package]] name = "lock_api" version = "0.4.12" @@ -1587,15 +793,6 @@ version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" -[[package]] -name = "loop9" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" -dependencies = [ - "imgref", -] - [[package]] name = "malloc_buf" version = "0.0.6" @@ -1605,16 +802,6 @@ dependencies = [ "libc", ] -[[package]] -name = "maybe-rayon" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" -dependencies = [ - "cfg-if", - "rayon", -] - [[package]] name = "memchr" version = "2.7.4" @@ -1630,40 +817,6 @@ dependencies = [ "libc", ] -[[package]] -name = "memoffset" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" -dependencies = [ - "autocfg", -] - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "miniz_oxide" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" -dependencies = [ - "adler", -] - -[[package]] -name = "miniz_oxide" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430" -dependencies = [ - "adler2", - "simd-adler32", -] - [[package]] name = "ndk" version = "0.9.0" @@ -1694,34 +847,12 @@ dependencies = [ "jni-sys", ] -[[package]] -name = "new_debug_unreachable" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" - [[package]] name = "nohash-hasher" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "noop_proc_macro" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" - [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -1732,47 +863,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-derive" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.19" @@ -1829,15 +919,6 @@ 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" @@ -1847,25 +928,13 @@ dependencies = [ "bitflags 2.9.0", "block2", "libc", - "objc2 0.5.2", + "objc2", "objc2-core-data", "objc2-core-image", - "objc2-foundation 0.2.2", + "objc2-foundation", "objc2-quartz-core", ] -[[package]] -name = "objc2-app-kit" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5906f93257178e2f7ae069efb89fbd6ee94f0592740b5f8a1512ca498814d0fb" -dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.0", - "objc2-core-graphics", - "objc2-foundation 0.3.0", -] - [[package]] name = "objc2-cloud-kit" version = "0.2.2" @@ -1874,9 +943,9 @@ checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" dependencies = [ "bitflags 2.9.0", "block2", - "objc2 0.5.2", + "objc2", "objc2-core-location", - "objc2-foundation 0.2.2", + "objc2-foundation", ] [[package]] @@ -1886,8 +955,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" dependencies = [ "block2", - "objc2 0.5.2", - "objc2-foundation 0.2.2", + "objc2", + "objc2-foundation", ] [[package]] @@ -1898,30 +967,8 @@ checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ "bitflags 2.9.0", "block2", - "objc2 0.5.2", - "objc2-foundation 0.2.2", -] - -[[package]] -name = "objc2-core-foundation" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daeaf60f25471d26948a1c2f840e3f7d86f4109e3af4e8e4b5cd70c39690d925" -dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.0", -] - -[[package]] -name = "objc2-core-graphics" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dca602628b65356b6513290a21a6405b4d4027b8b250f0b98dddbb28b7de02" -dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.0", - "objc2-core-foundation", - "objc2-io-surface", + "objc2", + "objc2-foundation", ] [[package]] @@ -1931,8 +978,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" dependencies = [ "block2", - "objc2 0.5.2", - "objc2-foundation 0.2.2", + "objc2", + "objc2-foundation", "objc2-metal", ] @@ -1943,9 +990,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" dependencies = [ "block2", - "objc2 0.5.2", + "objc2", "objc2-contacts", - "objc2-foundation 0.2.2", + "objc2-foundation", ] [[package]] @@ -1964,29 +1011,7 @@ dependencies = [ "block2", "dispatch", "libc", - "objc2 0.5.2", -] - -[[package]] -name = "objc2-foundation" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a21c6c9014b82c39515db5b396f91645182611c97d24637cf56ac01e5f8d998" -dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.0", - "objc2-core-foundation", -] - -[[package]] -name = "objc2-io-surface" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "161a8b87e32610086e1a7a9e9ec39f84459db7b3a0881c1f16ca5a2605581c19" -dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.0", - "objc2-core-foundation", + "objc2", ] [[package]] @@ -1996,9 +1021,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" dependencies = [ "block2", - "objc2 0.5.2", - "objc2-app-kit 0.2.2", - "objc2-foundation 0.2.2", + "objc2", + "objc2-app-kit", + "objc2-foundation", ] [[package]] @@ -2009,8 +1034,8 @@ checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ "bitflags 2.9.0", "block2", - "objc2 0.5.2", - "objc2-foundation 0.2.2", + "objc2", + "objc2-foundation", ] [[package]] @@ -2021,8 +1046,8 @@ checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ "bitflags 2.9.0", "block2", - "objc2 0.5.2", - "objc2-foundation 0.2.2", + "objc2", + "objc2-foundation", "objc2-metal", ] @@ -2032,8 +1057,8 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc" dependencies = [ - "objc2 0.5.2", - "objc2-foundation 0.2.2", + "objc2", + "objc2-foundation", ] [[package]] @@ -2044,12 +1069,12 @@ checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" dependencies = [ "bitflags 2.9.0", "block2", - "objc2 0.5.2", + "objc2", "objc2-cloud-kit", "objc2-core-data", "objc2-core-image", "objc2-core-location", - "objc2-foundation 0.2.2", + "objc2-foundation", "objc2-link-presentation", "objc2-quartz-core", "objc2-symbols", @@ -2064,8 +1089,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" dependencies = [ "block2", - "objc2 0.5.2", - "objc2-foundation 0.2.2", + "objc2", + "objc2-foundation", ] [[package]] @@ -2076,25 +1101,16 @@ checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ "bitflags 2.9.0", "block2", - "objc2 0.5.2", + "objc2", "objc2-core-location", - "objc2-foundation 0.2.2", -] - -[[package]] -name = "object" -version = "0.32.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" -dependencies = [ - "memchr", + "objc2-foundation", ] [[package]] name = "once_cell" -version = "1.21.3" +version = "1.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "c2806eaa3524762875e21c3dcd057bc4b7bfa01ce4da8d46be1cd43649e1cc6b" [[package]] name = "orbclient" @@ -2120,12 +1136,6 @@ dependencies = [ "ttf-parser", ] -[[package]] -name = "owo-colors" -version = "3.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" - [[package]] name = "parking_lot" version = "0.12.3" @@ -2149,12 +1159,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - [[package]] name = "percent-encoding" version = "2.3.1" @@ -2193,19 +1197,6 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" -[[package]] -name = "png" -version = "0.17.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" -dependencies = [ - "bitflags 1.3.2", - "crc32fast", - "fdeflate", - "flate2", - "miniz_oxide 0.8.7", -] - [[package]] name = "polling" version = "3.7.4" @@ -2221,15 +1212,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy 0.8.24", -] - [[package]] name = "presser" version = "0.3.1" @@ -2259,40 +1241,12 @@ name = "profiling" version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d" -dependencies = [ - "profiling-procmacros", -] - -[[package]] -name = "profiling-procmacros" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30" -dependencies = [ - "quote", - "syn", -] - -[[package]] -name = "qoi" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" -dependencies = [ - "bytemuck", -] - -[[package]] -name = "quick-error" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] name = "quick-xml" -version = "0.37.4" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4ce8c88de324ff838700f36fb6ab86c96df0e3c4ab6ef3a9b2044465cce1369" +checksum = "bf763ab1c7a3aa408be466efc86efe35ed1bd3dd74173ed39d6b0d0a6f0ba148" dependencies = [ "memchr", ] @@ -2306,92 +1260,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "r-efi" -version = "5.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.15", -] - -[[package]] -name = "rav1e" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9" -dependencies = [ - "arbitrary", - "arg_enum_proc_macro", - "arrayvec", - "av1-grain", - "bitstream-io", - "built", - "cfg-if", - "interpolate_name", - "itertools 0.12.1", - "libc", - "libfuzzer-sys", - "log", - "maybe-rayon", - "new_debug_unreachable", - "noop_proc_macro", - "num-derive", - "num-traits", - "once_cell", - "paste", - "profiling", - "rand", - "rand_chacha", - "simd_helpers", - "system-deps", - "thiserror 1.0.69", - "v_frame", - "wasm-bindgen", -] - -[[package]] -name = "ravif" -version = "0.11.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2413fd96bd0ea5cdeeb37eaf446a22e6ed7b981d792828721e74ded1980a45c6" -dependencies = [ - "avif-serialize", - "imgref", - "loop9", - "quick-error", - "rav1e", - "rayon", - "rgb", -] - [[package]] name = "raw-window-handle" version = "0.6.2" @@ -2410,26 +1278,6 @@ dependencies = [ "raw-window-handle", ] -[[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" @@ -2460,10 +1308,9 @@ dependencies = [ "gfx_hal", "glam", "gpu-allocator", + "parking_lot", "resource_manager", - "scene", "shaderc", - "shared", "thiserror 2.0.12", "tracing", "walkdir", @@ -2476,31 +1323,18 @@ version = "0.1.0" dependencies = [ "ash", "gfx_hal", - "gltf", "gpu-allocator", - "image", + "parking_lot", "thiserror 2.0.12", "tracing", ] -[[package]] -name = "rgb" -version = "0.8.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" - [[package]] name = "roxmltree" version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - [[package]] name = "rustix" version = "0.38.44" @@ -2522,9 +1356,9 @@ checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" [[package]] name = "ryu" -version = "1.0.20" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" [[package]] name = "same-file" @@ -2535,19 +1369,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "scene" -version = "0.1.0" -dependencies = [ - "ash", - "glam", - "gltf", - "resource_manager", - "shared", - "thiserror 2.0.12", - "tracing", -] - [[package]] name = "scoped-tls" version = "1.0.1" @@ -2595,9 +1416,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "44f86c3acccc9c65b153fe1b85a3be07fe5515274ec9f0653b4a0875731c72a6" dependencies = [ "itoa", "memchr", @@ -2605,15 +1426,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_spanned" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" -dependencies = [ - "serde", -] - [[package]] name = "shaderc" version = "0.9.1" @@ -2646,38 +1458,12 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "shared" -version = "0.1.0" -dependencies = [ - "ash", - "bytemuck", - "derive_builder", - "glam", - "memoffset", -] - [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" -[[package]] -name = "simd-adler32" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" - -[[package]] -name = "simd_helpers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" -dependencies = [ - "quote", -] - [[package]] name = "slab" version = "0.4.9" @@ -2718,17 +1504,6 @@ dependencies = [ "xkeysym", ] -[[package]] -name = "smithay-clipboard" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc8216eec463674a0e90f29e0ae41a4db573ec5b56b1c6c1c71615d249b6d846" -dependencies = [ - "libc", - "smithay-client-toolkit", - "wayland-backend", -] - [[package]] name = "smol_str" version = "0.2.2" @@ -2738,12 +1513,6 @@ dependencies = [ "serde", ] -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - [[package]] name = "strict-num" version = "0.1.1" @@ -2767,36 +1536,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "synstructure" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "system-deps" -version = "6.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" -dependencies = [ - "cfg-expr", - "heck", - "pkg-config", - "toml", - "version-compare", -] - -[[package]] -name = "target-lexicon" -version = "0.12.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" - [[package]] name = "thiserror" version = "1.0.69" @@ -2847,17 +1586,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "tiff" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" -dependencies = [ - "flate2", - "jpeg-decoder", - "weezl", -] - [[package]] name = "tiny-skia" version = "0.11.4" @@ -2883,36 +1611,11 @@ dependencies = [ "strict-num", ] -[[package]] -name = "tinystr" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "toml" -version = "0.8.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - [[package]] name = "toml_datetime" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" -dependencies = [ - "serde", -] [[package]] name = "toml_edit" @@ -2921,8 +1624,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" dependencies = [ "indexmap", - "serde", - "serde_spanned", "toml_datetime", "winnow", ] @@ -2959,16 +1660,6 @@ dependencies = [ "valuable", ] -[[package]] -name = "tracing-error" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db" -dependencies = [ - "tracing", - "tracing-subscriber", -] - [[package]] name = "tracing-log" version = "0.2.0" @@ -3025,64 +1716,18 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" -[[package]] -name = "url" -version = "2.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - [[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" -[[package]] -name = "v_frame" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6f32aaa24bacd11e488aa9ba66369c7cd514885742c9fe08cfe85884db3e92b" -dependencies = [ - "aligned-vec", - "num-traits", - "wasm-bindgen", -] - [[package]] name = "valuable" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" -[[package]] -name = "version-compare" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" - [[package]] name = "version_check" version = "0.9.5" @@ -3105,15 +1750,6 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" -[[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" -dependencies = [ - "wit-bindgen-rt", -] - [[package]] name = "wasm-bindgen" version = "0.2.100" @@ -3314,29 +1950,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webbrowser" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5df295f8451142f1856b1bd86a606dfe9587d439bc036e319c827700dbd555e" -dependencies = [ - "core-foundation 0.10.0", - "home", - "jni", - "log", - "ndk-context", - "objc2 0.6.0", - "objc2-foundation 0.3.0", - "url", - "web-sys", -] - -[[package]] -name = "weezl" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" - [[package]] name = "winapi" version = "0.3.9" @@ -3652,7 +2265,7 @@ dependencies = [ "calloop", "cfg_aliases", "concurrent-queue", - "core-foundation 0.9.4", + "core-foundation", "core-graphics", "cursor-icon", "dpi", @@ -3660,9 +2273,9 @@ dependencies = [ "libc", "memmap2", "ndk", - "objc2 0.5.2", - "objc2-app-kit 0.2.2", - "objc2-foundation 0.2.2", + "objc2", + "objc2-app-kit", + "objc2-foundation", "objc2-ui-kit", "orbclient", "percent-encoding", @@ -3698,27 +2311,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "wit-bindgen-rt" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags 2.9.0", -] - -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - -[[package]] -name = "writeable" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" - [[package]] name = "x11-dl" version = "2.21.0" @@ -3776,46 +2368,13 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" -[[package]] -name = "yoke" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" -dependencies = [ - "serde", - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - [[package]] name = "zerocopy" version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ - "zerocopy-derive 0.7.35", -] - -[[package]] -name = "zerocopy" -version = "0.8.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" -dependencies = [ - "zerocopy-derive 0.8.24", + "zerocopy-derive", ] [[package]] @@ -3828,81 +2387,3 @@ dependencies = [ "quote", "syn", ] - -[[package]] -name = "zerocopy-derive" -version = "0.8.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "zerofrom" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zerovec" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "zune-core" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" - -[[package]] -name = "zune-inflate" -version = "0.2.54" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" -dependencies = [ - "simd-adler32", -] - -[[package]] -name = "zune-jpeg" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99a5bab8d7dedf81405c4bb1f2b83ea057643d9cb28778cea9eecddeedd2e028" -dependencies = [ - "zune-core", -] diff --git a/Cargo.toml b/Cargo.toml index 0cdd355..ed32bcf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,8 +6,6 @@ members = [ "crates/gfx_hal", "crates/renderer", "crates/resource_manager", - "crates/scene", - "crates/shared", ] [workspace.dependencies] @@ -26,12 +24,11 @@ egui-ash-renderer = { version = "0.8.0", features = [ "dynamic-rendering", ] } egui = "0.31" -egui_tiles = "0.12" bytemuck = { version = "1.21.0", features = ["derive"] } -tracing = { features = ["release_max_level_warn"], version = "0.1" } +tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["json"] } +parking_lot = "0.12.3" thiserror = "2.0.12" -gltf = "1.4.1" # # Enable incremental by default in release mode. @@ -60,7 +57,4 @@ gltf = "1.4.1" # # rustflags = ["-Zshare-generics=off"] # codegen-units = 1 -opt-level = 1 - -[profile.dev.package."*"] opt-level = 3 diff --git a/crates/engine/Cargo.toml b/crates/engine/Cargo.toml index c111b04..84a72bc 100644 --- a/crates/engine/Cargo.toml +++ b/crates/engine/Cargo.toml @@ -5,22 +5,15 @@ edition = "2021" [dependencies] egui.workspace = true -egui_tiles.workspace = true ash.workspace = true ash-window.workspace = true -color-eyre.workspace = true tracing.workspace = true tracing-subscriber.workspace = true winit.workspace = true raw-window-handle.workspace = true thiserror.workspace = true -glam.workspace = true gfx_hal = { path = "../gfx_hal" } renderer = { path = "../renderer" } resource_manager = { path = "../resource_manager" } -shared = { path = "../shared" } -scene = { path = "../scene" } - clap = { version = "4.5.34", features = ["derive"] } -egui-winit = "0.31.1" diff --git a/crates/engine/src/main.rs b/crates/engine/src/main.rs index bcd9aa2..ff90adb 100644 --- a/crates/engine/src/main.rs +++ b/crates/engine/src/main.rs @@ -8,28 +8,21 @@ use std::{ use ash::vk; use clap::Parser; -use egui::{Context, Slider, ViewportId}; -use egui_winit::State; use gfx_hal::{ device::Device, error::GfxHalError, instance::Instance, instance::InstanceConfig, physical_device::PhysicalDevice, queue::Queue, surface::Surface, }; -use glam::Vec3; use raw_window_handle::HasDisplayHandle; use renderer::{Renderer, RendererError}; use resource_manager::{ResourceManager, ResourceManagerError}; -use scene::Scene; -use shared::CameraInfo; use tracing::{debug, error, info, warn}; use tracing_subscriber::{filter, layer::SubscriberExt, util::SubscriberInitExt, Layer}; use winit::{ application::ApplicationHandler, - event::{ElementState, KeyEvent, MouseButton, WindowEvent}, + event::WindowEvent, event_loop::{ActiveEventLoop, EventLoop}, - keyboard::{KeyCode, PhysicalKey}, window::Window, }; - // --- Configuration --- const APP_NAME: &str = "BeginDisregard"; const ENGINE_NAME: &str = "Engine"; @@ -49,8 +42,6 @@ enum AppError { NoSuitableDevice, #[error("Failed to create CString: {0}")] NulError(#[from] std::ffi::NulError), - #[error("Scene Error: {0}")] - SceneError(#[from] scene::SceneError), } struct Application { @@ -66,125 +57,12 @@ struct Application { // Renderer renderer: Renderer, - egui_ctx: Context, - egui_winit: State, - egui_app: EditorUI, - - // --- Camera State --- - camera_info: CameraInfo, - camera_speed: f32, - camera_sensitivity: f32, - - // --- Input State --- - is_forward_pressed: bool, - is_backward_pressed: bool, - is_left_pressed: bool, - is_right_pressed: bool, - is_up_pressed: bool, // Optional: For flying up - is_down_pressed: bool, // Optional: For flying down - is_rmb_pressed: bool, // Right mouse button - last_mouse_pos: Option<(f64, f64)>, - mouse_delta: (f64, f64), - capture_mouse: bool, // Flag to indicate if mouse should control camera - // Windowing window: Arc, // Use Arc for potential multi-threading later frame_count: u32, last_fps_update_time: Instant, last_frame_time: Instant, - current_fps: f64, -} - -#[derive(Default)] -struct EditorUI {} - -impl EditorUI { - fn title() -> String { - "engine".to_string() - } - - fn build_ui(&mut self, ctx: &egui::Context, current_fps: f64, camera_info: &mut CameraInfo) { - egui::SidePanel::new(egui::panel::Side::Left, Self::title()).show(ctx, |ui| { - ui.label(format!("FPS - {:.2}", current_fps)); - - ui.separator(); - - egui::Grid::new("main_grid") - .spacing([40.0, 4.0]) - .striped(true) - .show(ui, |ui| { - ui.label("FOV"); - // Modify the passed-in camera_info - ui.add(Slider::new(&mut camera_info.camera_fov, 10.0..=120.0)); - ui.end_row(); // Good practice in grids - - // You could add more camera controls here if needed - // e.g., sliders for position, target (though direct manipulation is better) - ui.label("Camera Pos"); - ui.label(format!( - "({:.1}, {:.1}, {:.1})", - camera_info.camera_pos.x, - camera_info.camera_pos.y, - camera_info.camera_pos.z - )); - ui.end_row(); - - ui.label("Camera Target"); - ui.label(format!( - "({:.1}, {:.1}, {:.1})", - camera_info.camera_target.x, - camera_info.camera_target.y, - camera_info.camera_target.z - )); - ui.end_row(); - }); - - ui.separator(); - ui.label("Controls:"); - ui.label("RMB + Drag: Look"); - ui.label("WASD: Move"); - ui.label("Space: Up"); - ui.label("Shift: Down"); - ui.label("Hold RMB to activate controls."); - }); - - // let mut tree = create_tree(); - // - // egui::panel::SidePanel::new(egui::panel::Side::Left, Id::new("main_panel")).show( - // ctx, - // |ui| { - // let mut behavior = TreeBehavior {}; - // tree.ui(&mut behavior, ui); - // }, - // ); - } -} - -fn create_tree() -> egui_tiles::Tree { - let mut next_view_nr = 0; - let mut gen_pane = || { - let pane = EditorUI {}; - next_view_nr += 1; - pane - }; - - let mut tiles = egui_tiles::Tiles::default(); - - let mut tabs = vec![]; - tabs.push({ - let children = (0..7).map(|_| tiles.insert_pane(gen_pane())).collect(); - tiles.insert_horizontal_tile(children) - }); - tabs.push({ - let cells = (0..11).map(|_| tiles.insert_pane(gen_pane())).collect(); - tiles.insert_grid_tile(cells) - }); - tabs.push(tiles.insert_pane(gen_pane())); - - let root = tiles.insert_tab_tile(tabs); - - egui_tiles::Tree::new("my_tree", root, tiles) } #[derive(Default)] @@ -344,15 +222,30 @@ impl Application { // Get specific queues (assuming graphics and present are the same for simplicity) let graphics_queue = device.get_graphics_queue(); + let queue_associated_device_handle = graphics_queue.device().raw().handle(); + info!( + "App: Queue is associated with Device handle: {:?}", + queue_associated_device_handle + ); + assert_eq!( + device_handle_at_creation, queue_associated_device_handle, + "Device handle mismatch immediately after queue creation!" + ); // --- 4. Resource Manager --- let resource_manager = Arc::new(ResourceManager::new(instance.clone(), device.clone())?); info!("Resource Manager initialized."); - let scene = Scene::from_gltf( - "./sponza/NewSponza_Main_glTF_003.gltf", - resource_manager.clone(), - )?; + let renderer_device_handle_to_pass = device.raw().handle(); + let renderer_queue_device_handle_to_pass = graphics_queue.device().raw().handle(); + info!( + "App: Passing Device handle to Renderer: {:?}", + renderer_device_handle_to_pass + ); + info!( + "App: Passing Queue associated with Device handle: {:?}", + renderer_queue_device_handle_to_pass + ); // --- 5. Renderer --- let initial_size = window.inner_size(); @@ -362,26 +255,11 @@ impl Application { graphics_queue.clone(), surface.clone(), resource_manager.clone(), - scene, initial_size.width, initial_size.height, )?; - - let egui_ctx = Context::default(); - let egui_winit = State::new( - egui_ctx.clone(), - ViewportId::ROOT, - &window, - None, - None, - None, - ); - let egui_app = EditorUI::default(); - info!("Renderer initialized."); - let camera_info = CameraInfo::default(); // Get default camera settings - Ok(Self { _instance: instance, _physical_device: physical_device, @@ -391,40 +269,13 @@ impl Application { _resource_manager: resource_manager, renderer, window, - egui_winit, - egui_ctx, - egui_app, - - // --- Camera --- - camera_info, // Store the camera state here - camera_speed: 5.0, // Adjust as needed - camera_sensitivity: 0.002, // Adjust as needed - - // --- Input --- - is_forward_pressed: false, - is_backward_pressed: false, - is_left_pressed: false, - is_right_pressed: false, - is_up_pressed: false, - is_down_pressed: false, - is_rmb_pressed: false, - last_mouse_pos: None, - mouse_delta: (0.0, 0.0), - capture_mouse: false, // Start with mouse free frame_count: 0, - current_fps: 0., last_fps_update_time: Instant::now(), last_frame_time: Instant::now(), }) } fn handle_event(&mut self, event: &WindowEvent, active_event_loop: &ActiveEventLoop) { - // Let egui process the event first - let egui_consumed_event = self.egui_winit.on_window_event(&self.window, event); - - // Only process input for camera if egui didn't consume it AND we are capturing - let process_camera_input = !egui_consumed_event.consumed && self.capture_mouse; - match event { WindowEvent::CloseRequested => { info!("Close requested. Exiting..."); @@ -447,153 +298,30 @@ impl Application { .resize(new_inner_size.width, new_inner_size.height); } // Handle other inputs if not consumed by egui - WindowEvent::MouseInput { state, button, .. } => { - if *button == MouseButton::Right { - let is_pressed = *state == ElementState::Pressed; - self.is_rmb_pressed = is_pressed; - - // Decide whether to capture/release mouse based on RMB - // Only capture if pressed *outside* an egui interactive area - if is_pressed && !self.egui_ctx.is_pointer_over_area() { - self.capture_mouse = true; - self.window - .set_cursor_grab(winit::window::CursorGrabMode::Confined) - .or_else(|_| { - self.window - .set_cursor_grab(winit::window::CursorGrabMode::Locked) - }) - .unwrap_or(()); - self.window.set_cursor_visible(false); - self.last_mouse_pos = None; // Reset last pos on capture start - } else if !is_pressed { - self.capture_mouse = false; - self.window - .set_cursor_grab(winit::window::CursorGrabMode::None) - .unwrap_or(()); - self.window.set_cursor_visible(true); - self.mouse_delta = (0.0, 0.0); // Stop camera movement - } - } - // Let egui handle its mouse clicks regardless of capture state - // (handled by on_window_event) - } - - WindowEvent::CursorMoved { position, .. } => { - let current_pos = (position.x, position.y); - if self.capture_mouse { - // Only calculate delta if capturing - if let Some(last_pos) = self.last_mouse_pos { - self.mouse_delta.0 += current_pos.0 - last_pos.0; - self.mouse_delta.1 += current_pos.1 - last_pos.1; - } - // Store position relative to window center might be more robust - // with set_cursor_position, but this works with grab/confine too. - self.last_mouse_pos = Some(current_pos); - } else { - // Still update egui's pointer position even if not capturing - // (handled by on_window_event) - self.last_mouse_pos = None; // Reset if not capturing - } - } - - // Use PhysicalKey for layout-independent keys - WindowEvent::KeyboardInput { - event: - KeyEvent { - physical_key, - state, - .. - }, - .. - } => { - // Let egui handle keyboard input first if it wants it - if egui_consumed_event.consumed { - return; - } - - let is_pressed = *state == ElementState::Pressed; - match physical_key { - PhysicalKey::Code(KeyCode::KeyW) | PhysicalKey::Code(KeyCode::ArrowUp) => { - self.is_forward_pressed = is_pressed; - } - PhysicalKey::Code(KeyCode::KeyS) | PhysicalKey::Code(KeyCode::ArrowDown) => { - self.is_backward_pressed = is_pressed; - } - PhysicalKey::Code(KeyCode::KeyA) | PhysicalKey::Code(KeyCode::ArrowLeft) => { - self.is_left_pressed = is_pressed; - } - PhysicalKey::Code(KeyCode::KeyD) | PhysicalKey::Code(KeyCode::ArrowRight) => { - self.is_right_pressed = is_pressed; - } - PhysicalKey::Code(KeyCode::Space) => { - self.is_up_pressed = is_pressed; - } - PhysicalKey::Code(KeyCode::ShiftLeft) - | PhysicalKey::Code(KeyCode::ShiftRight) => { - self.is_down_pressed = is_pressed; - } - // Optional: Escape to release mouse capture - PhysicalKey::Code(KeyCode::Escape) if is_pressed && self.capture_mouse => { - self.capture_mouse = false; - self.is_rmb_pressed = false; // Ensure RMB state is also reset - self.window - .set_cursor_grab(winit::window::CursorGrabMode::None) - .unwrap_or(()); - self.window.set_cursor_visible(true); - self.mouse_delta = (0.0, 0.0); - } - _ => {} - } - } + WindowEvent::KeyboardInput { .. } + | WindowEvent::CursorMoved { .. } + | WindowEvent::MouseInput { .. } => {} WindowEvent::RedrawRequested => { let now = Instant::now(); - let delta_time = now.duration_since(self.last_frame_time).as_secs_f32(); + let _delta_time = now.duration_since(self.last_frame_time); self.last_frame_time = now; - // --- FPS Calculation --- - let elapsed_since_last_update = now.duration_since(self.last_fps_update_time); + let elapsed_sice_last_update = now.duration_since(self.last_fps_update_time); self.frame_count += 1; - if elapsed_since_last_update >= Duration::from_secs(1) { - self.current_fps = - self.frame_count as f64 / elapsed_since_last_update.as_secs_f64(); - let new_title = format!( - "{} - {} - {:.0} FPS", - ENGINE_NAME, APP_NAME, self.current_fps - ); + + if elapsed_sice_last_update >= Duration::from_secs(1) { + let fps = self.frame_count as f64 / elapsed_sice_last_update.as_secs_f64(); + + let new_title = format!("{} - {} - {:.0} FPS", ENGINE_NAME, APP_NAME, fps); self.window.set_title(&new_title); + self.frame_count = 0; self.last_fps_update_time = now; } - self.update_camera(delta_time); // Call the new update function - - let raw_input = self.egui_winit.take_egui_input(&self.window); - - let egui::FullOutput { - platform_output, - textures_delta, - shapes, - pixels_per_point, - .. - } = self.egui_ctx.run(raw_input, |ctx| { - self.egui_app - .build_ui(ctx, self.current_fps, &mut self.camera_info); - }); - - self.renderer.update_textures(textures_delta).unwrap(); - - self.egui_winit - .handle_platform_output(&self.window, platform_output); - - let clipped_primitives = self.egui_ctx.tessellate(shapes, pixels_per_point); - // --- Render Frame --- - match self.renderer.render_frame( - pixels_per_point, - &clipped_primitives, - self.camera_info, - ) { + match self.renderer.render_frame() { Ok(_) => { self.window.request_redraw(); } @@ -615,106 +343,6 @@ impl Application { _ => {} } } - - // --- New Camera Update Function --- - fn update_camera(&mut self, dt: f32) { - if !self.capture_mouse - && self.mouse_delta == (0.0, 0.0) - && !self.is_forward_pressed - && !self.is_backward_pressed - && !self.is_left_pressed - && !self.is_right_pressed - && !self.is_up_pressed - && !self.is_down_pressed - { - return; // No input, no update needed - } - - let mut cam_pos = self.camera_info.camera_pos; - let mut cam_target = self.camera_info.camera_target; - let cam_up = self.camera_info.camera_up; // Usually Vec3::Y - - // --- Mouse Look (Rotation) --- - if self.capture_mouse && self.mouse_delta != (0.0, 0.0) { - let (delta_x, delta_y) = self.mouse_delta; - self.mouse_delta = (0.0, 0.0); // Consume the delta - - let sensitivity = self.camera_sensitivity; - let yaw_delta = delta_x as f32 * sensitivity; - let pitch_delta = delta_y as f32 * sensitivity; - - let forward_dir = (cam_target - cam_pos).normalize(); - let right_dir = forward_dir.cross(cam_up).normalize(); - // Recalculate up to prevent roll if needed, though cross product handles it here - let current_up = right_dir.cross(forward_dir).normalize(); - - // --- Pitch (Up/Down) --- - // Calculate new forward direction based on pitch rotation around right axis - let pitch_quat = glam::Quat::from_axis_angle(right_dir, -pitch_delta); // Negative for standard mouse look - let mut new_forward = pitch_quat * forward_dir; - - // Clamp pitch to avoid flipping over (e.g., +/- 89 degrees) - let max_pitch_angle = 89.0f32.to_radians(); - let current_pitch = new_forward.angle_between(cam_up) - 90.0f32.to_radians(); - if current_pitch.abs() > max_pitch_angle { - // Revert pitch if it exceeds limits - new_forward = forward_dir; // Keep previous forward if clamp needed - } - - // --- Yaw (Left/Right) --- - // Rotate the (potentially pitch-adjusted) forward direction and right vector around the global up axis (Y) - let yaw_quat = glam::Quat::from_axis_angle(Vec3::Y, -yaw_delta); // Negative for standard mouse look - new_forward = yaw_quat * new_forward; - - // Update target based on the new forward direction - cam_target = cam_pos + new_forward; - - // Update the camera's internal up vector based on yaw rotation as well - // This prevents weird tilting when looking straight up/down if up wasn't Vec3::Y - // self.camera_info.camera_up = yaw_quat * current_up; // Optional: only if up can change - } - - // --- Keyboard Movement --- - let forward_dir = (cam_target - cam_pos).normalize(); - // Use Vec3::Y for world-relative right/up movement, or calculate from forward/up - let right_dir = forward_dir.cross(Vec3::Y).normalize(); - // let up_dir = right_dir.cross(forward_dir).normalize(); // Camera's local up - let world_up_dir = Vec3::Y; // Use world up for space/shift - - let effective_speed = self.camera_speed * dt; - let mut move_delta = Vec3::ZERO; - - if self.is_forward_pressed { - move_delta += forward_dir; - } - if self.is_backward_pressed { - move_delta -= forward_dir; - } - if self.is_left_pressed { - move_delta -= right_dir; - } - if self.is_right_pressed { - move_delta += right_dir; - } - if self.is_up_pressed { - move_delta += world_up_dir; // Move along world Y - } - if self.is_down_pressed { - move_delta -= world_up_dir; // Move along world Y - } - - // Normalize move_delta if non-zero to ensure consistent speed diagonally - if move_delta != Vec3::ZERO { - let move_vec = move_delta.normalize() * effective_speed; - cam_pos += move_vec; - cam_target += move_vec; // Move target along with position - } - - // --- Apply Changes --- - self.camera_info.camera_pos = cam_pos; - self.camera_info.camera_target = cam_target; - // self.camera_info.camera_up remains Vec3::Y usually - } } // --- Helper Functions --- @@ -822,7 +450,6 @@ struct Args { // --- Entry Point --- fn main() -> Result<(), Box> { - color_eyre::install()?; let args = Args::parse(); let fmt_layer = tracing_subscriber::fmt::layer() diff --git a/crates/gfx_hal/Cargo.toml b/crates/gfx_hal/Cargo.toml index de36a5c..caa74b1 100644 --- a/crates/gfx_hal/Cargo.toml +++ b/crates/gfx_hal/Cargo.toml @@ -9,4 +9,4 @@ ash-window.workspace = true thiserror.workspace = true tracing.workspace = true winit.workspace = true -gpu-allocator.workspace = true +parking_lot.workspace = true diff --git a/crates/gfx_hal/src/device.rs b/crates/gfx_hal/src/device.rs index 71abd47..a26e36b 100644 --- a/crates/gfx_hal/src/device.rs +++ b/crates/gfx_hal/src/device.rs @@ -1,10 +1,9 @@ use ash::vk; +use parking_lot::Mutex; use std::collections::HashSet; use std::ffi::CStr; -use std::{ - collections::HashMap, - sync::{Arc, Mutex}, -}; +use std::sync::Weak; +use std::{collections::HashMap, sync::Arc}; use crate::error::{GfxHalError, Result}; use crate::instance::Instance; @@ -15,7 +14,7 @@ use crate::queue::Queue; /// /// Owns the `ash::Device` and provides access to device functions and queues. pub struct Device { - _instance: Arc, + instance: Arc, physical_device: vk::PhysicalDevice, device: ash::Device, queues: Mutex>>, @@ -33,7 +32,6 @@ impl Device { /// - `queue_family_indicies` must be valid indicies obtained from the `physical_device_handle`. /// - `required_extensions` must be supported by the `physical_device_handle`. /// - All feature structs passed must be supported by the `physical_device_handle`. - #[allow(clippy::too_many_arguments)] pub(crate) unsafe fn new( instance: Arc, physical_device_handle: vk::PhysicalDevice, @@ -114,7 +112,7 @@ impl Device { // --- 4. Create the Device struct in an Arc (Stage 1) --- // Initialize the queues map as empty for now. let device_arc = Arc::new(Device { - _instance: instance.clone(), + instance: instance.clone(), physical_device: physical_device_handle, device: ash_device, // Move the created ash::Device here queues: Mutex::new(HashMap::new()), // Start with empty map @@ -148,7 +146,7 @@ impl Device { // Lock the mutex and insert the created queues into the map within the Arc { // Scope for the mutex guard - let mut queues_map_guard = device_arc.queues.lock()?; + let mut queues_map_guard = device_arc.queues.lock(); *queues_map_guard = queues_to_insert; // Replace the empty map with the populated one tracing::debug!( "Device Arc populated with {} queues (Stage 2).", @@ -187,21 +185,15 @@ impl Device { /// Gets a wrapped queue handle. /// Currently only supports queue index 0 for each family. - pub fn get_queue(&self, family_index: u32, queue_index: u32) -> Result> { + pub fn get_queue(&self, family_index: u32, queue_index: u32) -> Option> { if queue_index != 0 { tracing::warn!("get_queue currently only supports queue_index 0"); - return Err(GfxHalError::MissingQueueFamily( - "get_queue only supports queue_index 0".to_string(), - )); + return None; } - self.queues - .lock()? + .lock() .get(&(family_index, queue_index)) .cloned() - .ok_or(GfxHalError::MissingQueueFamily( - "could not get queue family".to_string(), - )) } /// Gets the primary graphics queue (family index from `graphics_queue_family_index`, queue index 0). diff --git a/crates/gfx_hal/src/error.rs b/crates/gfx_hal/src/error.rs index efe7c8e..0e3e8d6 100644 --- a/crates/gfx_hal/src/error.rs +++ b/crates/gfx_hal/src/error.rs @@ -56,23 +56,9 @@ pub enum GfxHalError { #[error("Error loading the ash entry.")] AshEntryError(#[from] ash::LoadingError), - /// Poisoned Mutex - #[error("Error from poisoned mutex: {0}")] - MutexPoisoned(String), - /// Placeholder for other specific errors. #[error("An unexpected error occurred: {0}")] Other(String), - - /// Size for Buffer is invalid. - #[error("Buffer size is invalid.")] - BufferSizeInvalid, } pub type Result = std::result::Result; - -impl From> for GfxHalError { - fn from(e: std::sync::PoisonError) -> Self { - Self::MutexPoisoned(e.to_string()) - } -} diff --git a/crates/gfx_hal/src/lib.rs b/crates/gfx_hal/src/lib.rs index 3c1feeb..e83ecc2 100644 --- a/crates/gfx_hal/src/lib.rs +++ b/crates/gfx_hal/src/lib.rs @@ -6,12 +6,3 @@ pub mod queue; pub mod surface; pub mod swapchain; pub mod sync; - -pub use device::*; -pub use error::*; -pub use instance::*; -pub use physical_device::*; -pub use queue::*; -pub use surface::*; -pub use swapchain::*; -pub use sync::*; diff --git a/crates/gfx_hal/src/queue.rs b/crates/gfx_hal/src/queue.rs index e0952b7..8aa4513 100644 --- a/crates/gfx_hal/src/queue.rs +++ b/crates/gfx_hal/src/queue.rs @@ -1,6 +1,7 @@ -use std::sync::{Arc, Mutex}; +use std::sync::Arc; use ash::{vk, Device as AshDevice}; +use parking_lot::Mutex; use crate::device::Device; use crate::error::Result; @@ -65,6 +66,18 @@ impl Queue { submits: &[vk::SubmitInfo], signal_fence: Option<&Fence>, ) -> Result<()> { + debug_assert!( + self.device.raw().handle() == submit_device_raw.handle(), + "Queue::submit called with an ash::Device from a different logical VkDevice than the queue belongs to!" + ); + // Optional: Check fence device consistency + if let Some(fence) = signal_fence { + debug_assert!( + fence.device().raw().handle() == submit_device_raw.handle(), + "Fence passed to Queue::submit belongs to a different logical device than submit_device_raw!" + ); + } + let fence_handle = signal_fence.map_or(vk::Fence::null(), |f| f.handle()); // Keep the lock for thread-safety on the VkQueue object itself diff --git a/crates/gfx_hal/src/sync.rs b/crates/gfx_hal/src/sync.rs index 0d20fa9..0f684aa 100644 --- a/crates/gfx_hal/src/sync.rs +++ b/crates/gfx_hal/src/sync.rs @@ -10,7 +10,6 @@ use crate::{ /// Wraps a `vk::Fence`, used for CPU-GPU synchronization. /// /// Owns the `vk::Fence` handle. -#[derive(Clone)] pub struct Fence { device: Arc, fence: vk::Fence, diff --git a/crates/renderer/Cargo.toml b/crates/renderer/Cargo.toml index c82ec34..6f4bbee 100644 --- a/crates/renderer/Cargo.toml +++ b/crates/renderer/Cargo.toml @@ -13,11 +13,10 @@ gpu-allocator.workspace = true egui.workspace = true egui-ash-renderer.workspace = true winit.workspace = true +parking_lot.workspace = true gfx_hal = { path = "../gfx_hal" } resource_manager = { path = "../resource_manager" } -shared = { path = "../shared" } -scene = { path = "../scene" } [build-dependencies] shaderc = "0.9.1" diff --git a/crates/renderer/build.rs b/crates/renderer/build.rs index a24d5a1..16afb10 100644 --- a/crates/renderer/build.rs +++ b/crates/renderer/build.rs @@ -16,8 +16,6 @@ fn main() -> Result<()> { let out_dir = PathBuf::from(env::var("OUT_DIR")?).join("shaders"); // Put shaders in a subdirectory for clarity fs::create_dir_all(&out_dir).context("Failed to create shader output directory")?; - println!("cargo:rerun-if-changed=build.rs"); - let compiler = Compiler::new().context("Failed to create shader compiler")?; let mut options = CompileOptions::new().context("Failed to create compile options")?; @@ -51,7 +49,6 @@ fn main() -> Result<()> { .filter(|e| e.file_type().is_file()) // Only process files { - println!("cargo:rerun-if-changed={:?}", entry.path()); let in_path = entry.path(); // Determine shader kind from extension diff --git a/crates/renderer/src/lib.rs b/crates/renderer/src/lib.rs index fd69ff9..279df1b 100644 --- a/crates/renderer/src/lib.rs +++ b/crates/renderer/src/lib.rs @@ -1,32 +1,21 @@ -use std::{ - collections::HashMap, - ffi::c_void, - mem, - sync::{Arc, Mutex}, - time::Instant, -}; +use std::{ffi::CStr, sync::Arc}; use ash::vk; -use egui::{ClippedPrimitive, TextureId, TexturesDelta}; -use egui_ash_renderer::{DynamicRendering, Options, Renderer as EguiRenderer}; use gfx_hal::{ device::Device, error::GfxHalError, queue::Queue, surface::Surface, swapchain::Swapchain, swapchain::SwapchainConfig, sync::Fence, sync::Semaphore, }; -use glam::{Mat4, Vec3}; -use gpu_allocator::{ - vulkan::{Allocation, AllocationCreateDesc, Allocator}, - MemoryLocation, -}; -use resource_manager::{ - ImageHandle, Material, ResourceManager, ResourceManagerError, SamplerHandle, Texture, -}; -use shared::{CameraInfo, UniformBufferObject}; +use gpu_allocator::{vulkan::Allocator, MemoryLocation}; +use parking_lot::Mutex; +use resource_manager::{ImageHandle, ResourceManager, ResourceManagerError}; use thiserror::Error; use tracing::{debug, error, info, warn}; +// Assuming winit is used by the app + +// Re-export ash for convenience if needed elsewhere +pub use ash; const MAX_FRAMES_IN_FLIGHT: usize = 2; -const MAX_MATERIALS: usize = 150; #[derive(Debug, Error)] pub enum RendererError { @@ -62,17 +51,6 @@ pub enum RendererError { ImageInfoUnavailable, #[error("Failed to get allocator from resource manager")] AllocatorUnavailable, // Added based on egui requirement - #[error("Allocator Error: {0}")] - AllocatorError(#[from] gpu_allocator::AllocationError), - - #[error("Other Error: {0}")] - Other(String), -} - -impl From> for RendererError { - fn from(_: std::sync::PoisonError) -> Self { - Self::AllocatorUnavailable - } } struct FrameData { @@ -80,14 +58,7 @@ struct FrameData { command_buffer: vk::CommandBuffer, image_available_semaphore: Semaphore, render_finished_semaphore: Semaphore, - textures_to_free: Option>, in_flight_fence: Fence, - - descriptor_set: vk::DescriptorSet, - uniform_buffer_object: UniformBufferObject, - uniform_buffer: vk::Buffer, - uniform_buffer_allocation: Allocation, - uniform_buffer_mapped_ptr: *mut c_void, } struct SwapchainSupportDetails { @@ -108,26 +79,12 @@ pub struct Renderer { swapchain_format: vk::SurfaceFormatKHR, swapchain_extent: vk::Extent2D, - scene: scene::Scene, - - descriptor_set_layout: vk::DescriptorSetLayout, - descriptor_pool: vk::DescriptorPool, - - material_descriptor_set_layout: vk::DescriptorSetLayout, - - egui_renderer: EguiRenderer, - depth_image_handle: ImageHandle, depth_image_view: vk::ImageView, // Store the view directly depth_format: vk::Format, - model_pipeline_layout: vk::PipelineLayout, - model_pipeline: vk::Pipeline, - - material_descriptor_sets: HashMap, - - default_white_texture: Option>, - default_sampler: SamplerHandle, + triangle_pipeline_layout: vk::PipelineLayout, + triangle_pipeline: vk::Pipeline, frames_data: Vec, current_frame: usize, @@ -136,19 +93,15 @@ pub struct Renderer { window_resized: bool, current_width: u32, current_height: u32, - - start_time: Instant, } impl Renderer { - #[allow(clippy::too_many_arguments)] pub fn new( instance: Arc, // Needed for allocator device: Arc, graphics_queue: Arc, surface: Arc, resource_manager: Arc, - scene: scene::Scene, initial_width: u32, initial_height: u32, ) -> Result { @@ -168,215 +121,33 @@ impl Renderer { let (depth_image_handle, depth_image_view) = Self::create_depth_resources(&device, &resource_manager, extent, depth_format)?; - let descriptor_set_layout = Self::create_descriptor_set_layout(&device)?; - let material_descriptor_set_layout = Self::create_material_descriptor_set_layout(&device)?; + let (triangle_pipeline_layout, triangle_pipeline) = + Self::create_triangle_pipeline(&device, format.format, depth_format)?; - let descriptor_set_layouts = [descriptor_set_layout, material_descriptor_set_layout]; - - let descriptor_pool = Self::create_descriptor_pool(&device)?; - - let (model_pipeline_layout, model_pipeline) = Self::create_model_pipeline( - &device, - format.format, - depth_format, - &descriptor_set_layouts, - )?; - - let start_time = Instant::now(); - - let frames_data = Self::create_frame_data( - &device, - &resource_manager, - descriptor_pool, - &descriptor_set_layouts, - swapchain.extent(), - )?; + let frames_data = Self::create_frame_data(&device)?; info!("Renderer initialized successfully."); - let egui_renderer = EguiRenderer::with_gpu_allocator( - resource_manager.allocator(), - device.raw().clone(), - DynamicRendering { - color_attachment_format: swapchain.format().format, - depth_attachment_format: Some(depth_format), - }, - Options { - srgb_framebuffer: true, - in_flight_frames: MAX_FRAMES_IN_FLIGHT, - ..Default::default() - }, - )?; - - let default_sampler = resource_manager.get_or_create_sampler(&Default::default())?; - - let default_white_texture = Some(Self::create_default_texture( - device.clone(), - resource_manager.clone(), - )); - Ok(Self { device, graphics_queue, resource_manager, - egui_renderer, allocator, // Store the allocator Arc surface, swapchain: Some(swapchain), swapchain_image_views: image_views, swapchain_format: format, swapchain_extent: extent, - descriptor_set_layout, - descriptor_pool, - - material_descriptor_set_layout, depth_image_handle, depth_image_view, depth_format, - model_pipeline_layout, - model_pipeline, - - material_descriptor_sets: HashMap::new(), - - default_white_texture, - default_sampler, - + triangle_pipeline_layout, + triangle_pipeline, frames_data, - scene, current_frame: 0, window_resized: false, current_width: initial_width, current_height: initial_height, - - start_time, - }) - } - - /// Gets or creates/updates a descriptor set for a given material. - fn get_or_create_material_set( - &mut self, - material: &Arc, // Use Arc directly if hashable, or use a unique ID - ) -> Result { - // Return generic error - - // Use a unique identifier for the material instance if Arc isn't directly hashable - // or if pointer comparison isn't reliable across runs/reloads. - // For simplicity here, we use the Arc's pointer address as a key. - // WARNING: This is only safe if the Arc instances are stable! - // A better key might be derived from material.name or a generated ID. - let material_key = Arc::as_ptr(material) as usize; - - if let Some(set) = self.material_descriptor_sets.get(&material_key) { - return Ok(*set); - } - - // --- Allocate Descriptor Set --- - let layouts = [self.material_descriptor_set_layout]; - let alloc_info = vk::DescriptorSetAllocateInfo::default() - .descriptor_pool(self.descriptor_pool) - .set_layouts(&layouts); - - let descriptor_set = unsafe { self.device.raw().allocate_descriptor_sets(&alloc_info)? }[0]; - - // --- Update Descriptor Set --- - let (image_handle, view_handle, sampler_handle) = match &material.base_color_texture { - Some(texture) => { - // Get the default view handle associated with the image - let img_info = self.resource_manager.get_image_info(texture.handle)?; - let view_h = img_info.default_view_handle.ok_or(RendererError::Other( - "Image missing default view handle".to_string(), - ))?; - // Use the sampler specified by the material, or the default - let sampler_h = material.base_color_sampler.unwrap_or(self.default_sampler); - (texture.handle, view_h, sampler_h) - } - None => { - // Use default white texture - let default_tex = - self.default_white_texture - .as_ref() - .ok_or(RendererError::Other( - "Default texture not created".to_string(), - ))?; - let img_info = self.resource_manager.get_image_info(default_tex.handle)?; - let view_h = img_info.default_view_handle.ok_or(RendererError::Other( - "Default image missing default view handle".to_string(), - ))?; - (default_tex.handle, view_h, self.default_sampler) - } - }; - - // Get the actual Vulkan handles - let image_view_info = self.resource_manager.get_image_view_info(view_handle)?; - let sampler_info = self.resource_manager.get_sampler_info(sampler_handle)?; - - let image_descriptor_info = vk::DescriptorImageInfo::default() - .image_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL) // Expected layout for sampling - .image_view(image_view_info.view) // The vk::ImageView - .sampler(sampler_info.sampler); // The vk::Sampler - - let writes = [ - // Write for binding 0 (baseColorSampler) - vk::WriteDescriptorSet::default() - .dst_set(descriptor_set) - .dst_binding(0) - .dst_array_element(0) - .descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER) - .image_info(std::slice::from_ref(&image_descriptor_info)), - // Add writes for other bindings (normal map, etc.) here - ]; - - unsafe { - self.device.raw().update_descriptor_sets(&writes, &[]); // Update the set - } - - // Store in cache - self.material_descriptor_sets - .insert(material_key, descriptor_set); - Ok(descriptor_set) - } - - fn create_default_texture( - device: Arc, // Need device Arc for RM - resource_manager: Arc, - ) -> Arc { - let width = 1; - let height = 1; - let data = [255u8, 255, 255, 255]; // White RGBA - let format = vk::Format::R8G8B8A8_UNORM; // Or SRGB if preferred - - let create_info = vk::ImageCreateInfo::default() - .image_type(vk::ImageType::TYPE_2D) - .format(format) - .extent(vk::Extent3D { - width, - height, - depth: 1, - }) - .mip_levels(1) - .array_layers(1) - .samples(vk::SampleCountFlags::TYPE_1) - .tiling(vk::ImageTiling::OPTIMAL) - .usage(vk::ImageUsageFlags::SAMPLED | vk::ImageUsageFlags::TRANSFER_DST) - .initial_layout(vk::ImageLayout::UNDEFINED); - - let handle = resource_manager - .create_image_init( - &create_info, - gpu_allocator::MemoryLocation::GpuOnly, - vk::ImageAspectFlags::COLOR, - &data, - ) - .expect("Failed to create default white texture"); - - Arc::new(Texture { - handle, - format: vk::Format::R8G8B8A8_UNORM, - extent: vk::Extent3D { - width: 1, - height: 1, - depth: 1, - }, }) } @@ -391,33 +162,7 @@ impl Renderer { } } - pub fn update_textures(&mut self, textures_delta: TexturesDelta) -> Result<(), RendererError> { - tracing::trace!("Updating EGUI textures!"); - - if !textures_delta.free.is_empty() { - self.frames_data[self.current_frame].textures_to_free = - Some(textures_delta.free.clone()); - } - - if !textures_delta.set.is_empty() { - self.egui_renderer - .set_textures( - self.device.get_graphics_queue().handle(), - self.frames_data[self.current_frame].command_pool, - textures_delta.set.as_slice(), - ) - .expect("Failed to update texture"); - } - - Ok(()) - } - - pub fn render_frame( - &mut self, - pixels_per_point: f32, - clipped_primitives: &[ClippedPrimitive], - camera_info: CameraInfo, - ) -> Result<(), RendererError> { + pub fn render_frame(&mut self) -> Result<(), RendererError> { // --- Handle Resize --- if self.window_resized { self.window_resized = false; @@ -429,7 +174,7 @@ impl Renderer { // --- Wait for Previous Frame --- let frame_index = self.current_frame; - let frame_data = &mut self.frames_data[frame_index]; + let frame_data = &self.frames_data[frame_index]; frame_data.in_flight_fence.wait(None)?; // Wait indefinitely @@ -438,7 +183,6 @@ impl Renderer { .swapchain .as_ref() .ok_or(RendererError::SwapchainAcquisitionFailed)?; - let (image_index, suboptimal) = unsafe { // Need unsafe block for acquire_next_image swapchain_ref.acquire_next_image( @@ -459,10 +203,6 @@ impl Renderer { // --- Reset Fence (only after successful acquisition) --- frame_data.in_flight_fence.reset()?; - if let Some(textures) = frame_data.textures_to_free.take() { - self.egui_renderer.free_textures(&textures)?; - } - // --- Record Command Buffer --- unsafe { // Need unsafe for Vulkan commands @@ -475,15 +215,6 @@ impl Renderer { let cmd_begin_info = vk::CommandBufferBeginInfo::default() .flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT); - // -- Update uniform buffer -- - self.update_uniform_buffer(camera_info)?; - - let frame_data = &mut self.frames_data[self.current_frame]; - let swapchain_ref = self - .swapchain - .as_ref() - .ok_or(RendererError::SwapchainAcquisitionFailed)?; - unsafe { // Need unsafe for Vulkan commands self.device @@ -585,74 +316,18 @@ impl Renderer { .cmd_set_scissor(command_buffer, 0, &[scissor]); } + // --- Draw Triangle --- unsafe { + // Need unsafe for Vulkan commands self.device.raw().cmd_bind_pipeline( command_buffer, vk::PipelineBindPoint::GRAPHICS, - self.model_pipeline, - ); - - self.device.raw().cmd_bind_descriptor_sets( - command_buffer, - vk::PipelineBindPoint::GRAPHICS, - self.model_pipeline_layout, - 0, - &[frame_data.descriptor_set], - &[], + self.triangle_pipeline, ); + // Draw 3 vertices, 1 instance, 0 first vertex, 0 first instance + self.device.raw().cmd_draw(command_buffer, 3, 1, 0, 0); } - let meshes = self.scene.meshes.clone(); - - for mesh in meshes { - let material_set = self.get_or_create_material_set(&mesh.material)?; - - unsafe { - self.device.raw().cmd_bind_descriptor_sets( - command_buffer, - vk::PipelineBindPoint::GRAPHICS, - self.model_pipeline_layout, - 1, - &[material_set], - &[], - ); - } - - let model_matrix_bytes = unsafe { - std::slice::from_raw_parts( - mesh.transform.as_ref().as_ptr() as *const u8, - std::mem::size_of::(), - ) - }; - - unsafe { - self.device.raw().cmd_push_constants( - command_buffer, - self.model_pipeline_layout, - vk::ShaderStageFlags::VERTEX, - 0, - model_matrix_bytes, - ); - } - - mesh.geometry.draw(self.device.raw(), command_buffer)?; - } - - let frame_data = &mut self.frames_data[self.current_frame]; - let swapchain_ref = self - .swapchain - .as_ref() - .ok_or(RendererError::SwapchainAcquisitionFailed)?; - - tracing::trace!("Rendering EGUI"); - self.egui_renderer.cmd_draw( - command_buffer, - self.swapchain_extent, - pixels_per_point, - clipped_primitives, - )?; - tracing::trace!("Rendered EGUI"); - // --- End Dynamic Rendering --- unsafe { // Need unsafe for Vulkan commands @@ -707,6 +382,12 @@ impl Renderer { .command_buffers(&command_buffers) .signal_semaphores(&signal_semaphores); + // assert_eq!( + // self.graphics_queue.device().raw().handle(), // Device from Queue + // self.device.raw().handle(), // Device stored in Renderer + // "Device handle mismatch between Renderer and Graphics Queue!" + // ); + unsafe { // Need unsafe for queue submit self.graphics_queue.submit( @@ -794,7 +475,7 @@ impl Renderer { // --- Helper: Cleanup Swapchain Dependent Resources --- fn cleanup_swapchain_resources(&mut self) { debug!("Cleaning up swapchain resources..."); - + // Destroy depth buffer view unsafe { self.device .raw() @@ -803,8 +484,9 @@ impl Renderer { // Destroy depth buffer image via resource manager if let Err(e) = self.resource_manager.destroy_image(self.depth_image_handle) { error!("Failed to destroy depth image: {}", e); + // Continue cleanup even if this fails } - + // Drop the old swapchain object (RAII in gfx_hal::Swapchain handles vkDestroySwapchainKHR) self.swapchain = None; debug!("Swapchain resources cleaned up."); } @@ -851,10 +533,38 @@ impl Renderer { let swapchain = unsafe { Swapchain::new(device.clone(), surface.clone(), config, old_swapchain)? }; + // Create Image Views let image_views = swapchain .image_views() // Assuming Swapchain::new creates and stores these .to_vec(); // Clone the slice into a Vec + // If Swapchain::new doesn't create views, we need to do it here: + /* + let images = swapchain.images()?; // Assuming this method exists + let mut image_views = Vec::with_capacity(images.len()); + for &image in images.iter() { + let create_info = vk::ImageViewCreateInfo::default() + .image(image) + .view_type(vk::ImageViewType::TYPE_2D) + .format(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, + }); + let view = unsafe { device.raw().create_image_view(&create_info, None)? }; + image_views.push(view); + } + */ + Ok((swapchain, surface_format, extent, image_views)) } @@ -908,12 +618,33 @@ impl Renderer { } // --- Helper: Create Triangle Pipeline --- - fn create_model_pipeline( + fn create_triangle_pipeline( device: &Arc, color_format: vk::Format, depth_format: vk::Format, - descriptor_set_layouts: &[vk::DescriptorSetLayout], ) -> Result<(vk::PipelineLayout, vk::Pipeline), RendererError> { + // --- Shaders (Hardcoded example) --- + // Vertex Shader (GLSL) - outputs clip space position based on vertex index + /* + #version 450 + vec2 positions[3] = vec2[]( + vec2(0.0, -0.5), + vec2(0.5, 0.5), + vec2(-0.5, 0.5) + ); + void main() { + gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); + } + */ + // Fragment Shader (GLSL) - outputs solid orange + /* + #version 450 + layout(location = 0) out vec4 outColor; + void main() { + outColor = vec4(1.0, 0.5, 0.0, 1.0); // Orange + } + */ + // Load compiled SPIR-V (replace with actual loading) let vert_shader_code = include_bytes!(concat!(env!("OUT_DIR"), "/shaders/vert.glsl.spv")); // Placeholder path let frag_shader_code = include_bytes!(concat!(env!("OUT_DIR"), "/shaders/frag.glsl.spv")); // Placeholder path @@ -921,7 +652,7 @@ impl Renderer { let vert_module = Self::create_shader_module(device, vert_shader_code)?; let frag_module = Self::create_shader_module(device, frag_shader_code)?; - let main_function_name = c"main"; + let main_function_name = CStr::from_bytes_with_nul(b"main\0").unwrap(); let vert_stage_info = vk::PipelineShaderStageCreateInfo::default() .stage(vk::ShaderStageFlags::VERTEX) @@ -935,13 +666,8 @@ impl Renderer { let shader_stages = [vert_stage_info, frag_stage_info]; - let binding_description = shared::Vertex::get_binding_decription(); - let attribute_descriptions = shared::Vertex::get_attribute_descriptions(); - // --- Fixed Function State --- - let vertex_input_info = vk::PipelineVertexInputStateCreateInfo::default() - .vertex_binding_descriptions(std::slice::from_ref(&binding_description)) - .vertex_attribute_descriptions(&attribute_descriptions); + let vertex_input_info = vk::PipelineVertexInputStateCreateInfo::default(); // No vertex buffers/attributes let input_assembly = vk::PipelineInputAssemblyStateCreateInfo::default() .topology(vk::PrimitiveTopology::TRIANGLE_LIST) @@ -983,15 +709,8 @@ impl Renderer { let dynamic_state = vk::PipelineDynamicStateCreateInfo::default().dynamic_states(&dynamic_states); - let push_constant_range = vk::PushConstantRange::default() - .stage_flags(vk::ShaderStageFlags::VERTEX) - .offset(0) - .size(mem::size_of::() as u32); - // --- Pipeline Layout --- - let layout_info = vk::PipelineLayoutCreateInfo::default() - .set_layouts(descriptor_set_layouts) - .push_constant_ranges(std::slice::from_ref(&push_constant_range)); + let layout_info = vk::PipelineLayoutCreateInfo::default(); // No descriptors/push constants let pipeline_layout = unsafe { device .raw() @@ -1075,7 +794,7 @@ impl Renderer { // -------------------------------------------------------------------- // 3. Create the shader module - let create_info = vk::ShaderModuleCreateInfo::default().code(code_slice_ref); // Pass the &[u32] slice + let create_info = vk::ShaderModuleCreateInfo::default().code(&code_slice_ref); // Pass the &[u32] slice unsafe { device @@ -1089,13 +808,7 @@ impl Renderer { } // --- Helper: Create Frame Sync Objects & Command Resources --- - fn create_frame_data( - device: &Arc, - resource_manager: &Arc, - descriptor_pool: vk::DescriptorPool, - descriptor_set_layouts: &[vk::DescriptorSetLayout], - swapchain_extent: vk::Extent2D, - ) -> Result, RendererError> { + fn create_frame_data(device: &Arc) -> Result, RendererError> { let mut frames_data = Vec::with_capacity(MAX_FRAMES_IN_FLIGHT); for _ in 0..MAX_FRAMES_IN_FLIGHT { let image_available_semaphore = Semaphore::new(device.clone())?; @@ -1128,30 +841,12 @@ impl Renderer { .map_err(RendererError::CommandBufferAllocation)?[0] }; - tracing::info!("Allocated frame_data command_buffer: {:?}", command_buffer); - - let descriptor_set = - Self::create_descriptor_set(device, descriptor_set_layouts, descriptor_pool)?; - - let (uniform_buffer, uniform_buffer_allocation, uniform_buffer_mapped_ptr) = - Self::create_uniform_buffer(device, resource_manager)?; - - Self::update_descriptor_set(device.clone(), descriptor_set, uniform_buffer); - - let uniform_buffer_object = calculate_ubo(CameraInfo::default(), swapchain_extent); - frames_data.push(FrameData { - textures_to_free: None, command_pool, command_buffer, // Stays allocated, just reset/rerecorded image_available_semaphore, render_finished_semaphore, in_flight_fence, - descriptor_set, - uniform_buffer, - uniform_buffer_allocation, - uniform_buffer_mapped_ptr, - uniform_buffer_object, }); } Ok(frames_data) @@ -1176,20 +871,22 @@ impl Renderer { } fn choose_swapchain_format(available_formats: &[vk::SurfaceFormatKHR]) -> vk::SurfaceFormatKHR { - *available_formats + available_formats .iter() .find(|format| { format.format == vk::Format::B8G8R8A8_SRGB // Prefer SRGB && format.color_space == vk::ColorSpaceKHR::SRGB_NONLINEAR }) - .unwrap_or(&available_formats[0]) + .unwrap_or(&available_formats[0]) // Fallback to first available + .clone() } fn choose_swapchain_present_mode(available_modes: &[vk::PresentModeKHR]) -> vk::PresentModeKHR { - *available_modes + available_modes .iter() - .find(|&&mode| mode == vk::PresentModeKHR::FIFO) // Prefer Mailbox (low latency) - .unwrap_or(&vk::PresentModeKHR::FIFO) + .find(|&&mode| mode == vk::PresentModeKHR::MAILBOX) // Prefer Mailbox (low latency) + .unwrap_or(&vk::PresentModeKHR::FIFO) // Guaranteed fallback + .clone() } fn choose_swapchain_extent( @@ -1240,197 +937,8 @@ impl Renderer { } Err(RendererError::Vulkan( vk::Result::ERROR_FORMAT_NOT_SUPPORTED, - )) + )) // Or custom error } - - fn create_material_descriptor_set_layout( - device: &Arc, - ) -> Result { - let bindings = [ - // Binding 0: Combined Image Sampler (baseColorSampler) - vk::DescriptorSetLayoutBinding::default() - .binding(0) - .descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER) - .descriptor_count(1) - .stage_flags(vk::ShaderStageFlags::FRAGMENT), // Used in fragment shader - // Add more bindings here if needed (e.g., for normal map, metallic/roughness map) - // Binding 1: Uniform Buffer (Optional: for material factors) - // vk::DescriptorSetLayoutBinding::default() - // .binding(1) - // .descriptor_type(vk::DescriptorType::UNIFORM_BUFFER) - // .descriptor_count(1) - // .stage_flags(vk::ShaderStageFlags::FRAGMENT), - ]; - - let layout_info = vk::DescriptorSetLayoutCreateInfo::default().bindings(&bindings); - - Ok(unsafe { - device - .raw() - .create_descriptor_set_layout(&layout_info, None)? - }) - } - - fn create_descriptor_set_layout( - device: &Arc, - ) -> Result { - let ubo_layout_binding = vk::DescriptorSetLayoutBinding::default() - .binding(0) - .descriptor_type(vk::DescriptorType::UNIFORM_BUFFER) - .descriptor_count(1) - .stage_flags(vk::ShaderStageFlags::VERTEX); - - let layout_info = vk::DescriptorSetLayoutCreateInfo::default() - .bindings(std::slice::from_ref(&ubo_layout_binding)); - - let descriptor_set_layout = unsafe { - device - .raw() - .create_descriptor_set_layout(&layout_info, None)? - }; - - Ok(descriptor_set_layout) - } - - fn create_descriptor_pool(device: &Arc) -> Result { - let pool_sizes = [ - vk::DescriptorPoolSize { - ty: vk::DescriptorType::UNIFORM_BUFFER, - descriptor_count: MAX_FRAMES_IN_FLIGHT as u32, - }, - vk::DescriptorPoolSize { - ty: vk::DescriptorType::COMBINED_IMAGE_SAMPLER, - descriptor_count: MAX_MATERIALS as u32, - }, - ]; - - let pool_info = vk::DescriptorPoolCreateInfo::default() - .pool_sizes(&pool_sizes) - .max_sets(MAX_FRAMES_IN_FLIGHT as u32 + MAX_MATERIALS as u32); - - let descriptor_pool = unsafe { device.raw().create_descriptor_pool(&pool_info, None)? }; - - Ok(descriptor_pool) - } - - fn create_descriptor_set( - device: &Arc, - descriptor_set_layouts: &[vk::DescriptorSetLayout], - descriptor_pool: vk::DescriptorPool, - ) -> Result { - let alloc_info = vk::DescriptorSetAllocateInfo::default() - .descriptor_pool(descriptor_pool) - .set_layouts(descriptor_set_layouts); - - let descriptor_set = unsafe { device.raw().allocate_descriptor_sets(&alloc_info)? }[0]; - - Ok(descriptor_set) - } - - fn create_uniform_buffer( - device: &Arc, - resource_manager: &Arc, - ) -> Result<(vk::Buffer, Allocation, *mut std::ffi::c_void), RendererError> { - let buffer_size = mem::size_of::() as vk::DeviceSize; - - let buffer_info = vk::BufferCreateInfo::default() - .size(buffer_size) - .usage(vk::BufferUsageFlags::UNIFORM_BUFFER) - .sharing_mode(vk::SharingMode::EXCLUSIVE); - - let allocation = resource_manager - .allocator() - .lock()? - .allocate(&AllocationCreateDesc { - name: "Uniform Buffer", - requirements: unsafe { - { - let temp_buffer = device.raw().create_buffer(&buffer_info, None)?; - let req = device.raw().get_buffer_memory_requirements(temp_buffer); - - device.raw().destroy_buffer(temp_buffer, None); - req - } - }, - location: MemoryLocation::CpuToGpu, - linear: true, - allocation_scheme: gpu_allocator::vulkan::AllocationScheme::GpuAllocatorManaged, - })?; - - let buffer = unsafe { device.raw().create_buffer(&buffer_info, None)? }; - tracing::info!("Created uniform buffer {:?}", buffer); - - unsafe { - device - .raw() - .bind_buffer_memory(buffer, allocation.memory(), allocation.offset())?; - } - - let mapped_ptr = allocation - .mapped_ptr() - .ok_or_else(|| { - error!("Failed to get mapped pointer for CPU->GPU uniform buffer"); - ResourceManagerError::Other("Failed to map uniform buffer".to_string()) - })? - .as_ptr(); - - Ok((buffer, allocation, mapped_ptr)) - } - - fn update_descriptor_set( - device: Arc, - descriptor_set: vk::DescriptorSet, - buffer: vk::Buffer, - ) { - let buffer_info = vk::DescriptorBufferInfo::default() - .buffer(buffer) - .offset(0) - .range(mem::size_of::() as vk::DeviceSize); - - let descriptor_write = vk::WriteDescriptorSet::default() - .dst_set(descriptor_set) - .dst_binding(0) - .dst_array_element(0) - .descriptor_type(vk::DescriptorType::UNIFORM_BUFFER) - .buffer_info(std::slice::from_ref(&buffer_info)); - - unsafe { - device - .raw() - .update_descriptor_sets(std::slice::from_ref(&descriptor_write), &[]); - } - } - - fn update_uniform_buffer(&mut self, camera_info: CameraInfo) -> Result<(), RendererError> { - let frame_data = &mut self.frames_data[self.current_frame]; - - let ubo = calculate_ubo(camera_info, self.swapchain_extent); - - if frame_data.uniform_buffer_object != ubo { - let ptr = frame_data.uniform_buffer_mapped_ptr; - unsafe { - let aligned_ptr = ptr as *mut UniformBufferObject; - aligned_ptr.write(ubo); - } - } - - Ok(()) - } -} - -fn calculate_ubo(camera_info: CameraInfo, swapchain_extent: vk::Extent2D) -> UniformBufferObject { - let view = Mat4::look_at_rh(camera_info.camera_pos, camera_info.camera_target, Vec3::Y); - - let mut proj = Mat4::perspective_rh( - camera_info.camera_fov.to_radians(), - swapchain_extent.width as f32 / swapchain_extent.height as f32, - 0.1, - 1000.0, - ); - - proj.y_axis.y *= -1.0; - - UniformBufferObject { view, proj } } // --- Drop Implementation --- @@ -1454,39 +962,16 @@ impl Drop for Renderer { unsafe { self.device .raw() - .destroy_pipeline(self.model_pipeline, None); + .destroy_pipeline(self.triangle_pipeline, None); self.device .raw() - .destroy_pipeline_layout(self.model_pipeline_layout, None); - } - - unsafe { - self.device - .raw() - .destroy_descriptor_pool(self.descriptor_pool, None); - self.device - .raw() - .destroy_descriptor_set_layout(self.descriptor_set_layout, None); + .destroy_pipeline_layout(self.triangle_pipeline_layout, None); } // Destroy frame data (fences, semaphores, command pools) // Fences/Semaphores are handled by gfx_hal::Drop // Command buffers are freed with the pool for frame_data in self.frames_data.drain(..) { - unsafe { - self.device - .raw() - .destroy_buffer(frame_data.uniform_buffer, None); - - let mut allocator = self - .allocator - .lock() - .expect("Allocator Mutex to not be poisoned."); - allocator - .free(frame_data.uniform_buffer_allocation) - .expect("Allocator to be able to free an allocation"); - } - unsafe { self.device .raw() diff --git a/crates/resource_manager/Cargo.toml b/crates/resource_manager/Cargo.toml index bde4cc1..73c615a 100644 --- a/crates/resource_manager/Cargo.toml +++ b/crates/resource_manager/Cargo.toml @@ -7,8 +7,7 @@ edition = "2021" ash.workspace = true gpu-allocator.workspace = true thiserror.workspace = true +parking_lot.workspace = true tracing.workspace = true -gltf.workspace = true gfx_hal = { path = "../gfx_hal" } -image = { version = "0.25.6", features = ["rayon"] } diff --git a/crates/resource_manager/src/error.rs b/crates/resource_manager/src/error.rs index 96906d6..669427d 100644 --- a/crates/resource_manager/src/error.rs +++ b/crates/resource_manager/src/error.rs @@ -34,12 +34,6 @@ pub enum ResourceManagerError { #[error("Error occurred in GfxHal: {0}")] GfxHalError(#[from] gfx_hal::error::GfxHalError), - #[error("I/O Error occurred: {0}")] - Io(#[from] std::io::Error), - - #[error("Image Error occurred: {0}")] - ImageError(#[from] image::ImageError), - #[error("An unexpected error occurred: {0}")] Other(String), } diff --git a/crates/resource_manager/src/geo.rs b/crates/resource_manager/src/geo.rs deleted file mode 100644 index c78c467..0000000 --- a/crates/resource_manager/src/geo.rs +++ /dev/null @@ -1,175 +0,0 @@ -use std::sync::Arc; - -use ash::vk; -use gpu_allocator::MemoryLocation; -use tracing::{debug, trace}; - -use crate::{BufferHandle, ResourceManager, ResourceManagerError, Result}; - -// Helper to safely get a byte slice from structured data -unsafe fn as_byte_slice(data: &[T]) -> &[u8] { - std::slice::from_raw_parts(data.as_ptr() as *const u8, std::mem::size_of_val(data)) -} - -/// Represents geometry data (verticies and indicies) stored in GPU buffers managed by -/// ResourceManager. Handles automatic cleanup via a `Drop` implementation. -#[derive(Clone)] -pub struct Geometry { - resource_manager: Arc, - pub vertex_buffer: BufferHandle, - pub index_buffer: BufferHandle, - pub index_count: u32, -} - -impl Geometry { - /// Creates new GPU buffers for the given vetex and index data using `ResourceManager`. - /// - /// # Arguments - /// - /// * `resource_manager` - An Arc reference to the ResourceManager. - /// * `vertices` - A slice of vertex data. - /// * `indices` - A slice of index data (u32) - /// - /// # Errors - /// - /// Returns a new `ResourceManagerError` if buffer creation or data upload fails. - pub fn new( - resource_manager: Arc, - vertices: &[V], - indicies: &[u32], - ) -> Result { - trace!( - "Creating Geometry: {} vertices, {} indicies", - vertices.len(), - indicies.len() - ); - - if vertices.is_empty() || indicies.is_empty() { - return Err(ResourceManagerError::Other( - "Cannot create Geometry with empty vertices or indicies.".to_string(), - )); - } - - let vertex_buffer = resource_manager.create_buffer_init( - vk::BufferUsageFlags::VERTEX_BUFFER, - MemoryLocation::GpuOnly, - unsafe { as_byte_slice(vertices) }, - )?; - trace!("Vertex buffer created: handle={:?}", vertex_buffer); - - let index_buffer = resource_manager.create_buffer_init( - vk::BufferUsageFlags::INDEX_BUFFER, - MemoryLocation::GpuOnly, - unsafe { as_byte_slice(indicies) }, - )?; - trace!("Index buffer created: handle={:?}", index_buffer); - - let index_count = indicies.len() as u32; - - debug!( - "Geometry created successfully: VB={:?}, IB={:?}, Indices={}", - vertex_buffer, index_buffer, index_count - ); - - Ok(Self { - resource_manager, - vertex_buffer, - index_buffer, - index_count, - // vertex_count, - }) - } - - /// Binds the vertex and index buffers for drawing. - /// - /// # Arguments - /// - /// * `device` - Raw `ash::Device` handle. - /// * `command_buffer` - The command buffer to record binding commands into. - /// - /// # Errors - /// - /// Returns `ResourceManagerError` if buffer info cannot be retrieved. - pub fn bind(&self, device: &ash::Device, command_buffer: vk::CommandBuffer) -> Result<()> { - trace!( - "Binding geometry: VB={:?}, IB={:?}", - self.vertex_buffer, - self.index_buffer - ); - // Get buffer info (locks resource manager map briefly) - let vb_info = self.resource_manager.get_buffer_info(self.vertex_buffer)?; - let ib_info = self.resource_manager.get_buffer_info(self.index_buffer)?; - - let vk_vertex_buffers = [vb_info.buffer]; - let offsets = [0_u64]; // Use vk::DeviceSize (u64) - - unsafe { - device.cmd_bind_vertex_buffers( - command_buffer, - 0, // binding = 0 - &vk_vertex_buffers, - &offsets, - ); - device.cmd_bind_index_buffer( - command_buffer, - ib_info.buffer, - 0, // offset = 0 - vk::IndexType::UINT32, - ); - } - Ok(()) - } - - /// Binds the geometry buffers and issues an indexed draw command. - /// - /// # Arguments - /// - /// * `device` - Raw `ash::Device` handle. - /// * `command_buffer` - The command buffer to record commands into. - /// - /// # Errors - /// - /// Returns `ResourceManagerError` if binding fails. - pub fn draw(&self, device: &ash::Device, command_buffer: vk::CommandBuffer) -> Result<()> { - self.bind(device, command_buffer)?; // Bind first - trace!("Drawing geometry: {} indices", self.index_count); - unsafe { - device.cmd_draw_indexed( - command_buffer, - self.index_count, // Use stored index count - 1, // instance_count - 0, // first_index - 0, // vertex_offset - 0, // first_instance - ); - } - Ok(()) - } -} - -impl Drop for Geometry { - fn drop(&mut self) { - debug!( - "Dropping Geometry: VB={:?}, IB={:?}", - self.vertex_buffer, self.index_buffer - ); - // Request destruction from the resource manager. - // Ignore errors during drop, but log them. - if let Err(e) = self.resource_manager.destroy_buffer(self.vertex_buffer) { - tracing::error!( - "Failed to destroy vertex buffer {:?} during Geometry drop: {}", - self.vertex_buffer, - e - ); - } - - if let Err(e) = self.resource_manager.destroy_buffer(self.index_buffer) { - tracing::error!( - "Failed to destroy index buffer {:?} during Geometry drop: {}", - self.index_buffer, - e - ); - } - // The Arc reference count decreases automatically. - } -} diff --git a/crates/resource_manager/src/lib.rs b/crates/resource_manager/src/lib.rs index 4a3ec7a..bec4110 100644 --- a/crates/resource_manager/src/lib.rs +++ b/crates/resource_manager/src/lib.rs @@ -1,30 +1,24 @@ mod error; -mod geo; -mod texture; use std::{ collections::HashMap, - fs, hash::Hash, - path::{Path, PathBuf}, sync::{ atomic::{AtomicU64, Ordering}, - Arc, Mutex, + Arc, }, }; use ash::vk; -use gfx_hal::{device::Device, instance::Instance, queue::Queue, Fence}; +use gfx_hal::{device::Device, instance::Instance, queue::Queue}; use tracing::{debug, error, trace, warn}; pub use error::{ResourceManagerError, Result}; -pub use geo::Geometry; -pub use texture::{Material, SamplerDesc, Texture}; - use gpu_allocator::{ vulkan::{Allocation, AllocationCreateDesc, Allocator, AllocatorCreateDesc}, MemoryLocation, }; +use parking_lot::Mutex; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct BufferHandle(u64); @@ -32,12 +26,6 @@ pub struct BufferHandle(u64); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct ImageHandle(u64); -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] // New Handle -pub struct ImageViewHandle(u64); - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct SamplerHandle(u64); - #[derive(Debug, Clone)] pub struct BufferInfo { pub handle: BufferHandle, @@ -50,21 +38,14 @@ pub struct BufferInfo { #[derive(Debug, Clone)] pub struct ImageInfo { pub handle: ImageHandle, + /// Non-owning handle. pub image: vk::Image, - // pub view: vk::ImageView, // Removed raw view - pub default_view_handle: Option, // Added handle to default view + /// Non-owning handle. + pub view: vk::ImageView, pub format: vk::Format, pub extent: vk::Extent3D, pub usage: vk::ImageUsageFlags, pub layout: vk::ImageLayout, - pub mapped_ptr: Option<*mut u8>, -} - -#[derive(Debug, Clone)] -pub struct SamplerInfo { - pub handle: SamplerHandle, - pub sampler: vk::Sampler, - pub desc: SamplerDesc, // Include desc if useful } struct InternalBufferInfo { @@ -74,6 +55,7 @@ struct InternalBufferInfo { allocation: Option, // Option because it's taken in Drop size: vk::DeviceSize, usage: vk::BufferUsageFlags, + mapped_ptr: Option<*mut u8>, handle: BufferHandle, } @@ -81,7 +63,7 @@ impl Drop for InternalBufferInfo { fn drop(&mut self) { trace!("Dropping InternalBufferInfo for handle: {:?}", self.handle); if let Some(allocation) = self.allocation.take() { - let mut allc = self.allocator.lock().expect("to acquire mutex lock"); + let mut allc = self.allocator.lock(); if let Err(e) = allc.free(allocation) { error!( "Failed to free allocation for buffer handle {:?}, {}", @@ -99,12 +81,11 @@ impl Drop for InternalBufferInfo { } struct InternalImageInfo { - device: Arc, - allocator: Arc>, + device: Arc, // Keep device alive for Drop + allocator: Arc>, // Needed for Drop image: vk::Image, - // view: vk::ImageView, // Removed raw view - default_view_handle: Option, // Added handle - allocation: Option, + view: vk::ImageView, + allocation: Option, // Option because it's taken in Drop format: vk::Format, extent: vk::Extent3D, usage: vk::ImageUsageFlags, @@ -115,10 +96,13 @@ struct InternalImageInfo { impl Drop for InternalImageInfo { fn drop(&mut self) { trace!("Dropping InternalImageInfo for handle {:?}", self.handle); - + // Destroy view first + unsafe { + self.device.raw().destroy_image_view(self.view, None); + } // Then free memory if let Some(allocation) = self.allocation.take() { - let mut allocator = self.allocator.lock().expect("to acquire mutex lock"); + let mut allocator = self.allocator.lock(); if let Err(e) = allocator.free(allocation) { error!( "Failed to free allocation for image handle {:?}: {}", @@ -139,69 +123,20 @@ impl Drop for InternalImageInfo { } } -struct InternalSamplerInfo { - device: Arc, - sampler: vk::Sampler, - handle: SamplerHandle, - desc: SamplerDesc, -} - -struct InternalImageViewInfo { - device: Arc, // Keep device alive for Drop - view: vk::ImageView, - handle: ImageViewHandle, - // Optional: Store the ImageHandle this view belongs to for debugging/validation - // image_handle: ImageHandle, -} - -#[derive(Debug, Clone)] -pub struct ImageViewInfo { - pub handle: ImageViewHandle, - pub view: vk::ImageView, - // Could add format, subresource range etc. if needed frequently -} - -impl Drop for InternalImageViewInfo { - fn drop(&mut self) { - trace!( - "Dropping InternalImageViewInfo for handle {:?}", - self.handle - ); - unsafe { - self.device.raw().destroy_image_view(self.view, None); - } - trace!("Destroyed vk::ImageView for handle {:?}", self.handle); - } -} - -impl Drop for InternalSamplerInfo { - fn drop(&mut self) { - trace!("Dropping InternalSamplerInfo for handle {:?}", self.handle); - unsafe { - self.device.raw().destroy_sampler(self.sampler, None); - } - trace!("Destroyed vk::Sampler for handle {:?}", self.handle); - } -} - struct TransferSetup { command_pool: vk::CommandPool, queue: Arc, - fence: Fence, + fence: vk::Fence, } pub struct ResourceManager { _instance: Arc, device: Arc, allocator: Arc>, - buffers: Arc>>, - images: Arc>>, - image_views: Arc>>, - samplers: Arc>>, - sampler_cache_by_desc: Arc>>, - texture_cache_uri: Arc>>>, + buffers: Mutex>, + images: Mutex>, next_id: AtomicU64, - transfer_setup: Arc>, + transfer_setup: Mutex>, } impl ResourceManager { @@ -218,40 +153,14 @@ impl ResourceManager { })?; debug!("GPU Allocator created."); - let queue_family_index = device - .transfer_queue_family_index() - .or(device.compute_queue_family_index()) // Try compute as fallback - .unwrap_or(device.graphics_queue_family_index()); // Graphics as last resort - - let queue = device.get_queue(queue_family_index, 0)?; - - // Create command pool for transfer commands - let pool_info = vk::CommandPoolCreateInfo::default() - .flags(vk::CommandPoolCreateFlags::TRANSIENT) // Hint that buffers are short-lived - .queue_family_index(queue_family_index); - let command_pool = unsafe { device.raw().create_command_pool(&pool_info, None)? }; - - // Create a fence for waiting - let fence = Fence::new(device.clone(), false)?; - - let new_setup = TransferSetup { - command_pool, - queue, - fence, - }; - Ok(Self { _instance: instance, device, allocator: Arc::new(Mutex::new(allocator)), - buffers: Arc::new(Mutex::new(HashMap::new())), - images: Arc::new(Mutex::new(HashMap::new())), - image_views: Arc::new(Mutex::new(HashMap::new())), // Initialize view map - samplers: Arc::new(Mutex::new(HashMap::new())), - sampler_cache_by_desc: Arc::new(Mutex::new(HashMap::new())), - texture_cache_uri: Arc::new(Mutex::new(HashMap::new())), + buffers: Mutex::new(HashMap::new()), + images: Mutex::new(HashMap::new()), next_id: AtomicU64::new(1), - transfer_setup: Arc::new(Mutex::new(new_setup)), + transfer_setup: Mutex::new(None), }) } @@ -260,59 +169,117 @@ impl ResourceManager { self.allocator.clone() } - /// Helper to allocate, begin, end, submit, and wait for a single command buffer - /// using the provided TransferSetup. + /// Gets or initializes the TransferSetup resources. + fn get_transfer_setup(&self) -> Result { + let mut setup_guard = self.transfer_setup.lock(); + + if let Some(setup) = setup_guard.as_ref() { + // Simple check: Reset fence before reusing + unsafe { self.device.raw().reset_fences(&[setup.fence])? }; + return Ok(TransferSetup { + // Return a copy/clone + command_pool: setup.command_pool, + queue: setup.queue.clone(), + fence: setup.fence, + }); + } + + debug!("Initializing TransferSetup..."); + // Find a queue that supports transfer (prefer dedicated, fallback to graphics) + let queue_family_index = self + .device + .transfer_queue_family_index() + .or(self.device.compute_queue_family_index()) // Try compute as fallback + .unwrap_or(self.device.graphics_queue_family_index()); // Graphics as last resort + + let queue = self + .device + .get_queue(queue_family_index, 0) + .ok_or(ResourceManagerError::NoTransferQueue)?; + + // Create command pool for transfer commands + let pool_info = vk::CommandPoolCreateInfo::default() + .flags(vk::CommandPoolCreateFlags::TRANSIENT) // Hint that buffers are short-lived + .queue_family_index(queue_family_index); + let command_pool = unsafe { self.device.raw().create_command_pool(&pool_info, None)? }; + + // Create a fence for waiting + let fence_info = vk::FenceCreateInfo::default(); + let fence = unsafe { self.device.raw().create_fence(&fence_info, None)? }; + + let new_setup = TransferSetup { + command_pool, + queue, + fence, + }; + *setup_guard = Some(new_setup); // Store it + debug!("TransferSetup initialized."); + + // Return a new copy for use + Ok(TransferSetup { + command_pool: setup_guard.as_ref().unwrap().command_pool, + queue: setup_guard.as_ref().unwrap().queue.clone(), + fence: setup_guard.as_ref().unwrap().fence, + }) + } + + /// Helper to allocate, begin, end, submit, and wait for a single command buffer. unsafe fn submit_commands_and_wait( &self, - transfer_setup: &TransferSetup, // Use the cloned setup + transfer_setup: &TransferSetup, record_fn: F, ) -> Result<()> where - F: FnOnce(vk::CommandBuffer) -> Result<()>, // Closure records commands + F: FnOnce(vk::CommandBuffer) -> Result<()>, { - let device_raw = self.device.raw(); // Get raw ash::Device + let device = self.device.raw(); // Allocate command buffer let alloc_info = vk::CommandBufferAllocateInfo::default() .command_pool(transfer_setup.command_pool) .level(vk::CommandBufferLevel::PRIMARY) .command_buffer_count(1); - let command_buffer = device_raw.allocate_command_buffers(&alloc_info)?[0]; - tracing::info!("Allocated command_buffer: {:?}", command_buffer); - trace!("Allocated temporary command buffer for transfer."); + let command_buffer = device.allocate_command_buffers(&alloc_info)?[0]; // Begin recording let begin_info = vk::CommandBufferBeginInfo::default() .flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT); - device_raw.begin_command_buffer(command_buffer, &begin_info)?; + device.begin_command_buffer(command_buffer, &begin_info)?; - // --- Record user commands --- + // Record user commands let record_result = record_fn(command_buffer); - // --- End Recording --- - // Always end buffer, even if recording failed, to allow cleanup - device_raw.end_command_buffer(command_buffer)?; + + // End recording (even if user function failed, to allow cleanup) + device.end_command_buffer(command_buffer)?; // Check user function result *after* ending buffer record_result?; - trace!("Transfer commands recorded."); - // Submit to the transfer queue - let submits = - [vk::SubmitInfo::default().command_buffers(std::slice::from_ref(&command_buffer))]; - // Use the queue from the TransferSetup. Assuming Queue::submit handles locking. + let binding = [command_buffer]; + // Submit + let submits = [vk::SubmitInfo::default().command_buffers(&binding)]; + // Use the transfer queue and fence transfer_setup .queue - .submit(device_raw, &submits, Some(&transfer_setup.fence))?; // Submit WITH fence - trace!("Transfer command buffer submitted."); + .submit(self.device.raw(), &submits, None)?; // Submit without fence initially - // Wait for completion using the fence - transfer_setup.fence.wait(None)?; + // Wait for completion using a separate wait call + // This avoids holding the queue's internal submit lock during the wait. + let fences = [transfer_setup.fence]; + match device.wait_for_fences(&fences, true, u64::MAX) { + Ok(_) => {} + Err(vk::Result::TIMEOUT) => { + // Should not happen with u64::MAX + warn!("Transfer fence wait timed out unexpectedly."); + return Err(ResourceManagerError::TransferFailed( + "Fence wait timeout".to_string(), + )); + } + Err(e) => return Err(e.into()), + } - // Free command buffer *after* successful wait - device_raw.free_command_buffers(transfer_setup.command_pool, &[command_buffer]); - trace!("Temporary command buffer freed."); - - transfer_setup.fence.reset()?; + // Free command buffer + device.free_command_buffers(transfer_setup.command_pool, &[command_buffer]); Ok(()) } @@ -339,7 +306,7 @@ impl ResourceManager { let requirements = unsafe { self.device.raw().get_buffer_memory_requirements(buffer) }; - let allocation = self.allocator.lock()?.allocate(&AllocationCreateDesc { + let allocation = self.allocator.lock().allocate(&AllocationCreateDesc { name: &format!("buffer_usage_{:?}_loc_{:?}", usage, location), requirements, location, @@ -356,6 +323,11 @@ impl ResourceManager { } trace!("Buffer memory bound."); + let mapped_ptr = allocation.mapped_ptr().map(|p| p.as_ptr() as *mut u8); + if mapped_ptr.is_some() { + trace!("Buffer memory is mapped."); + } + let id = self.next_id.fetch_add(1, Ordering::Relaxed); let handle = BufferHandle(id); @@ -366,19 +338,20 @@ impl ResourceManager { allocation: Some(allocation), size, usage, + mapped_ptr, handle, }; - self.buffers.lock()?.insert(id, internal_info); + self.buffers.lock().insert(id, internal_info); debug!("Buffer created successfully: handle={:?}", handle); Ok(handle) } - // Make sure create_buffer_init is correct and doesn't call itself + /// Creates a buffer, allocates memory, and uploads initial data using a staging buffer. pub fn create_buffer_init( &self, - usage: vk::BufferUsageFlags, - location: MemoryLocation, + usage: vk::BufferUsageFlags, // Usage for the *final* buffer + location: MemoryLocation, // Memory location for the *final* buffer data: &[u8], ) -> Result { let size = data.len() as vk::DeviceSize; @@ -392,16 +365,14 @@ impl ResourceManager { size, usage, location ); - // 1. Create Staging Buffer (CPU accessible) - let staging_handle = self.create_buffer( - // Call create_buffer, NOT create_buffer_init - size, - vk::BufferUsageFlags::TRANSFER_SRC, - MemoryLocation::CpuToGpu, - )?; + // 1. Create Staging Buffer + let staging_usage = vk::BufferUsageFlags::TRANSFER_SRC; + let staging_location = MemoryLocation::CpuToGpu; // Mapped memory for upload + let staging_handle = self.create_buffer(size, staging_usage, staging_location)?; // 2. Map & Copy data to staging buffer { + // Scope for buffer info and mapping pointer let staging_info = self.get_buffer_info(staging_handle)?; let mapping = staging_info .mapped_ptr @@ -409,45 +380,42 @@ impl ResourceManager { unsafe { std::ptr::copy_nonoverlapping(data.as_ptr(), mapping, data.len()); } - // Optional: Flush - trace!("Data copied to staging buffer handle {:?}", staging_handle); - } + // If memory is not HOST_COHERENT, need to flush here: + // let mem_range = vk::MappedMemoryRange::builder().memory(...).offset(...).size(size); + // unsafe { self.device.raw().flush_mapped_memory_ranges(&[mem_range])? }; + trace!("Data copied to staging buffer."); + } // staging_info goes out of scope // 3. Create Destination Buffer - let final_usage = usage | vk::BufferUsageFlags::TRANSFER_DST; - let dest_handle = self.create_buffer(size, final_usage, location)?; // Call create_buffer + let final_usage = usage | vk::BufferUsageFlags::TRANSFER_DST; // Add transfer dest usage + let dest_handle = self.create_buffer(size, final_usage, location)?; - // 4. Perform Copy via Command Buffer - { - let transfer_setup_locked = self.transfer_setup.lock()?; - let buffers_locked = self.buffers.lock()?; + // 4. Record and submit transfer command + let transfer_setup = self.get_transfer_setup()?; + let dest_info = self.get_buffer_info(dest_handle)?; // Get info for vk::Buffer handle + let staging_info_for_copy = self.get_buffer_info(staging_handle)?; // Get info again - let dest_internal = buffers_locked - .get(&dest_handle.0) - .ok_or(ResourceManagerError::HandleNotFound(dest_handle.0))?; - let staging_internal = buffers_locked - .get(&staging_handle.0) - .ok_or(ResourceManagerError::HandleNotFound(staging_handle.0))?; - - trace!("Submitting buffer copy command..."); - unsafe { - Self::submit_commands_and_wait(self, &transfer_setup_locked, |cmd| { - let region = vk::BufferCopy::default().size(size); - self.device.raw().cmd_copy_buffer( - cmd, - staging_internal.buffer, - dest_internal.buffer, - &[region], - ); - Ok(()) - })?; - } - trace!("Buffer copy command finished."); + trace!("Submitting buffer copy command..."); + unsafe { + self.submit_commands_and_wait(&transfer_setup, |cmd| { + let region = vk::BufferCopy::default() + .src_offset(0) + .dst_offset(0) + .size(size); + self.device.raw().cmd_copy_buffer( + cmd, + staging_info_for_copy.buffer, // Use raw handle from info struct + dest_info.buffer, // Use raw handle from info struct + &[region], + ); + Ok(()) // Return Ok inside the closure + })?; } + trace!("Buffer copy command finished."); // 5. Cleanup staging buffer - self.destroy_buffer(staging_handle)?; - debug!("Staging buffer destroyed: handle={:?}", staging_handle); + self.destroy_buffer(staging_handle)?; // This frees memory and destroys buffer + debug!("Staging buffer destroyed."); Ok(dest_handle) } @@ -470,8 +438,10 @@ impl ResourceManager { ); let image = unsafe { self.device.raw().create_image(create_info, None)? }; + let requirements = unsafe { self.device.raw().get_image_memory_requirements(image) }; - let allocation = self.allocator.lock()?.allocate(&AllocationCreateDesc { + + let allocation = self.allocator.lock().allocate(&AllocationCreateDesc { name: &format!( "image_fmt_{:?}_usage_{:?}", create_info.format, create_info.usage @@ -481,6 +451,7 @@ impl ResourceManager { linear: create_info.tiling == vk::ImageTiling::LINEAR, allocation_scheme: gpu_allocator::vulkan::AllocationScheme::GpuAllocatorManaged, })?; + unsafe { self.device .raw() @@ -488,17 +459,22 @@ impl ResourceManager { } trace!("Image memory bound."); - // 2. Create the *default* Image View using the new method - let default_view_create_info = Self::build_default_view_info(create_info, aspect_flags); - // Use internal helper to avoid locking images map again if called from create_image_view - let default_view_handle = - self.create_image_view_internal(image, &default_view_create_info)?; - trace!( - "Default image view created: handle={:?}", - default_view_handle - ); + // Create a default image view + // TODO: Make view creation more flexible (allow different subresource ranges, types) + let view_info = vk::ImageViewCreateInfo::default() + .image(image) + .view_type(vk::ImageViewType::TYPE_2D) // Assuming 2D, adjust based on create_info + .format(create_info.format) + .subresource_range(vk::ImageSubresourceRange { + aspect_mask: aspect_flags, + base_mip_level: 0, + level_count: create_info.mip_levels, + base_array_layer: 0, + layer_count: create_info.array_layers, + }); + let view = unsafe { self.device.raw().create_image_view(&view_info, None)? }; + trace!("Default image view created."); - // 3. Store InternalImageInfo let id = self.next_id.fetch_add(1, Ordering::Relaxed); let handle = ImageHandle(id); @@ -506,677 +482,26 @@ impl ResourceManager { device: self.device.clone(), allocator: self.allocator.clone(), image, - default_view_handle: Some(default_view_handle), // Store handle + view, allocation: Some(allocation), format: create_info.format, extent: create_info.extent, usage: create_info.usage, - layout: create_info.initial_layout, + layout: create_info.initial_layout, // Store initial layout handle, }; - self.images.lock()?.insert(id, internal_info); + self.images.lock().insert(id, internal_info); debug!("Image created successfully: handle={:?}", handle); Ok(handle) } - fn build_default_view_info<'a>( - image_create_info: &vk::ImageCreateInfo, - aspect_flags: vk::ImageAspectFlags, - ) -> vk::ImageViewCreateInfo<'a> { - let view_type = match image_create_info.image_type { - vk::ImageType::TYPE_1D => { - if image_create_info.array_layers > 1 { - vk::ImageViewType::TYPE_1D_ARRAY - } else { - vk::ImageViewType::TYPE_1D - } - } - vk::ImageType::TYPE_3D => vk::ImageViewType::TYPE_3D, - _ => { - // TYPE_2D - if image_create_info - .flags - .contains(vk::ImageCreateFlags::CUBE_COMPATIBLE) - { - if image_create_info.array_layers > 6 { - vk::ImageViewType::CUBE_ARRAY - } else { - vk::ImageViewType::CUBE - } // Assumes 6 layers - } else if image_create_info.array_layers > 1 { - vk::ImageViewType::TYPE_2D_ARRAY - } else { - vk::ImageViewType::TYPE_2D - } - } - }; - - vk::ImageViewCreateInfo::default() - // .image(image) // Image is set by create_image_view_internal - .view_type(view_type) - .format(image_create_info.format) - .subresource_range( - vk::ImageSubresourceRange::default() - .aspect_mask(aspect_flags) - .base_mip_level(0) - .level_count(image_create_info.mip_levels) - .base_array_layer(0) - .layer_count(image_create_info.array_layers), - ) - // .components(...) // Default components usually fine - } - - /// Creates a new Vulkan ImageView for an existing Image. - /// The view's lifetime is managed by the ResourceManager. - pub fn create_image_view( - &self, - image_handle: ImageHandle, - view_create_info: &vk::ImageViewCreateInfo, // User provides desired view settings - ) -> Result { - trace!("Request to create image view for image {:?}", image_handle); - // 1. Get the vk::Image handle from the InternalImageInfo - let image_vk_handle = { - // Scope for images lock - let images_map = self.images.lock()?; - let internal_image_info = images_map - .get(&image_handle.0) - .ok_or(ResourceManagerError::HandleNotFound(image_handle.0))?; - internal_image_info.image // Copy the vk::Image handle - }; // Release images lock - - // 2. Call internal helper to create the view and manage it - self.create_image_view_internal(image_vk_handle, view_create_info) - } - - /// Internal helper to create and register an image view. - /// Takes the raw vk::Image to avoid re-locking the images map. - fn create_image_view_internal( - &self, - image: vk::Image, // The actual Vulkan image handle - view_create_info: &vk::ImageViewCreateInfo, - ) -> Result { - // Ensure the create info points to the correct image - let final_view_info = (*view_create_info).image(image); - - let view = unsafe { - self.device - .raw() - .create_image_view(&final_view_info, None)? - }; - trace!("vk::ImageView created."); - - let id = self.next_id.fetch_add(1, Ordering::Relaxed); - let handle = ImageViewHandle(id); - - let internal_view_info = InternalImageViewInfo { - device: self.device.clone(), - view, - handle, - // image_handle: image_handle, // Optional: Store originating image handle - }; - - // Add to the image_views map - self.image_views.lock()?.insert(id, internal_view_info); - debug!("Image view registered: handle={:?}", handle); - - Ok(handle) - } - - /// Creates an image, uploads data from a buffer, and transitions layout. - pub fn create_image_init( - &self, - create_info: &vk::ImageCreateInfo, // Must have usage TRANSFER_DST - location: MemoryLocation, // Usually GpuOnly for textures - aspect_flags: vk::ImageAspectFlags, - data: &[u8], - ) -> Result { - if data.is_empty() { - return Err(ResourceManagerError::Other( - "Cannot create image with empty data".to_string(), - )); - } - if !create_info - .usage - .contains(vk::ImageUsageFlags::TRANSFER_DST) - { - return Err(ResourceManagerError::Other( - "Image create info must include TRANSFER_DST usage for init".to_string(), - )); - } - // It's okay if initialLayout is not UNDEFINED, we override it for the creation step - // but the user might have specified it for other reasons. We just ensure the - // internal creation uses UNDEFINED. - // if create_info.initial_layout != vk::ImageLayout::UNDEFINED { - // warn!( - // "create_image_init expects initial_layout UNDEFINED, overriding." - // ); - // } - - let data_size = data.len() as vk::DeviceSize; - debug!( - "Creating image with init data: size={}, format={:?}, extent={:?}", - data_size, create_info.format, create_info.extent - ); - - // --- Corrected Flow --- - - // 1. Create Staging Buffer (CPU accessible for copy) - // Use create_buffer directly, then map and copy. - let staging_handle = self.create_buffer( - data_size, - vk::BufferUsageFlags::TRANSFER_SRC, - MemoryLocation::CpuToGpu, // Mapped memory for upload - )?; - // Map & Copy data to staging buffer - { - // Scope for buffer info and mapping pointer - let staging_info = self.get_buffer_info(staging_handle)?; // Lock buffers map - let mapping = staging_info - .mapped_ptr - .ok_or(ResourceManagerError::MappingFailed)?; - unsafe { - std::ptr::copy_nonoverlapping(data.as_ptr(), mapping, data.len()); - } - // Optional: Flush if memory is not HOST_COHERENT - // Check allocation properties if needed and flush - trace!("Data copied to staging buffer handle {:?}", staging_handle); - } // staging_info goes out of scope, unlocks buffers map - - // 2. Create Destination Image (ensure layout is UNDEFINED initially) - let mut final_create_info = *create_info; - final_create_info.initial_layout = vk::ImageLayout::UNDEFINED; // MUST start as undefined for transition - let image_handle = self.create_image(&final_create_info, location, aspect_flags)?; - - // 3. Perform Layout Transition (Undefined -> TransferDst) & Copy - { - let transfer_setup_locked = self.transfer_setup.lock()?; - let buffers_locked = self.buffers.lock()?; - let mut images_locked = self.images.lock()?; // Mut needed to update layout - - let image_internal = images_locked - .get_mut(&image_handle.0) // Get mut ref - .ok_or(ResourceManagerError::HandleNotFound(image_handle.0))?; - // Get the *correct* staging buffer info - let staging_internal = buffers_locked - .get(&staging_handle.0) // Use the handle created in step 1 - .ok_or(ResourceManagerError::HandleNotFound(staging_handle.0))?; - - let subresource_layers = vk::ImageSubresourceLayers::default() - .aspect_mask(aspect_flags) - .mip_level(0) - .base_array_layer(0) - .layer_count(create_info.array_layers); - - let copy_region = vk::BufferImageCopy::default() - .buffer_offset(0) - .buffer_row_length(0) // 0 means tightly packed - .buffer_image_height(0) // 0 means tightly packed - .image_subresource(subresource_layers) - .image_offset(vk::Offset3D::default()) - .image_extent(create_info.extent); - - trace!("Submitting image transition and copy command..."); - unsafe { - Self::submit_commands_and_wait(self, &transfer_setup_locked, |cmd| { - // Barrier 1: Undefined -> TransferDstOptimal - let (src_access, dst_access, src_stage, dst_stage) = Self::get_barrier_params( - vk::ImageLayout::UNDEFINED, - vk::ImageLayout::TRANSFER_DST_OPTIMAL, - ); - let barrier1 = vk::ImageMemoryBarrier::default() - .old_layout(vk::ImageLayout::UNDEFINED) - .new_layout(vk::ImageLayout::TRANSFER_DST_OPTIMAL) - .src_queue_family_index(vk::QUEUE_FAMILY_IGNORED) - .dst_queue_family_index(vk::QUEUE_FAMILY_IGNORED) - .image(image_internal.image) - .subresource_range( - vk::ImageSubresourceRange::default() - .aspect_mask(aspect_flags) - .base_mip_level(0) - .level_count(create_info.mip_levels) - .base_array_layer(0) - .layer_count(create_info.array_layers), - ) - .src_access_mask(src_access) - .dst_access_mask(dst_access); - - self.device.raw().cmd_pipeline_barrier( - cmd, - src_stage, - dst_stage, - vk::DependencyFlags::empty(), - &[], - &[], - &[barrier1], - ); - - // Copy Command (using correct staging buffer) - self.device.raw().cmd_copy_buffer_to_image( - cmd, - staging_internal.buffer, // Use buffer from staging_handle - image_internal.image, - vk::ImageLayout::TRANSFER_DST_OPTIMAL, // Layout during copy - &[copy_region], - ); - - // Barrier 2: TransferDstOptimal -> ShaderReadOnlyOptimal - let final_layout = vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL; - let (src_access, dst_access, src_stage, dst_stage) = Self::get_barrier_params( - vk::ImageLayout::TRANSFER_DST_OPTIMAL, - final_layout, - ); - let barrier2 = vk::ImageMemoryBarrier::default() - .old_layout(vk::ImageLayout::TRANSFER_DST_OPTIMAL) - .new_layout(final_layout) - .src_queue_family_index(vk::QUEUE_FAMILY_IGNORED) - .dst_queue_family_index(vk::QUEUE_FAMILY_IGNORED) - .image(image_internal.image) - .subresource_range( - vk::ImageSubresourceRange::default() - .aspect_mask(aspect_flags) - .base_mip_level(0) - .level_count(create_info.mip_levels) - .base_array_layer(0) - .layer_count(create_info.array_layers), - ) - .src_access_mask(src_access) - .dst_access_mask(dst_access); - - self.device.raw().cmd_pipeline_barrier( - cmd, - src_stage, - dst_stage, - vk::DependencyFlags::empty(), - &[], - &[], - &[barrier2], - ); - - Ok(()) // Return Ok from the closure - })?; // End submit_commands_and_wait - } // Locks released (transfer_setup, buffers, images) - - drop(images_locked); - - let mut images_locked_update = self.images.lock()?; // Use different name to avoid confusion - if let Some(info) = images_locked_update.get_mut(&image_handle.0) { - info.layout = vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL; // Update to final layout - trace!( - "Image {:?} layout updated internally to {:?}", - image_handle, - info.layout - ); - } else { - warn!( - "Image {:?} disappeared after creation during init!", - image_handle - ); - } - } // Scope for locks ends here - - // 4. Cleanup staging buffer (the one created in step 1) - self.destroy_buffer(staging_handle)?; // Destroy the correct handle - debug!( - "Staging buffer destroyed for image init: handle={:?}", - staging_handle - ); // Log handle - - tracing::info!( - "Image created and initialized successfully: handle={:?}", - image_handle - ); - Ok(image_handle) - } - - /// Gets non-owning information about a sampler. - pub fn get_sampler_info(&self, handle: SamplerHandle) -> Result { - let samplers_map = self - .samplers - .lock() - .map_err(|_| ResourceManagerError::Other("Sampler map mutex poisoned".to_string()))?; - samplers_map - .get(&handle.0) - .map(|internal| SamplerInfo { - handle: internal.handle, - sampler: internal.sampler, - desc: internal.desc.clone(), - }) - .ok_or(ResourceManagerError::HandleNotFound(handle.0)) - } - - /// Gets or creates a Vulkan sampler based on the description. - /// Uses caching to avoid creating duplicate samplers. - pub fn get_or_create_sampler(&self, desc: &SamplerDesc) -> Result { - let mut cache = self.sampler_cache_by_desc.lock()?; - if let Some(handle) = cache.get(desc) { - if self.samplers.lock()?.contains_key(&handle.0) { - trace!("Using cached sampler for desc: {:?}", desc); - return Ok(*handle); - } else { - warn!( - "Sampler handle {:?} found in cache but not main map. Removing from cache.", - handle - ); - cache.remove(desc); - } - } - - drop(cache); - - trace!("Creating a new sampler for desc: {:?}", desc); - let sampler_info = vk::SamplerCreateInfo::default() - .mag_filter(desc.mag_filter) - .min_filter(desc.min_filter) - .mipmap_mode(desc.mipmap_mode) - .address_mode_u(desc.address_mode_u) - .address_mode_v(desc.address_mode_v) - .address_mode_w(desc.address_mode_w) - .mip_lod_bias(0.0) - .anisotropy_enable(false) // TODO: Expose anisotropy in SamplerDesc? - .max_anisotropy(1.0) - .compare_enable(false) // TODO: Expose compare op? - .compare_op(vk::CompareOp::ALWAYS) - .min_lod(0.0) - .max_lod(vk::LOD_CLAMP_NONE) // TODO: Allow setting max LOD (e.g., for mipmapping) - .border_color(vk::BorderColor::INT_OPAQUE_BLACK) // TODO: Expose border color? - .unnormalized_coordinates(false); - - let vk_sampler = unsafe { self.device.raw().create_sampler(&sampler_info, None)? }; - - let id = self.next_id.fetch_add(1, Ordering::Relaxed); - let handle = SamplerHandle(id); - - let internal_info = InternalSamplerInfo { - device: self.device.clone(), - sampler: vk_sampler, - handle, - desc: desc.clone(), - }; - - self.samplers.lock()?.insert(id, internal_info); - self.sampler_cache_by_desc - .lock()? - .insert(desc.clone(), handle); - - debug!("Sampler created successfully: handle={:?}", handle); - Ok(handle) - } - - pub fn destroy_sampler(&self, handle: SamplerHandle) -> Result<()> { - debug!("Requesting destroy for sampler handle {:?}", handle); - let mut samplers_map = self.samplers.lock()?; - if let Some(internal_info) = samplers_map.remove(&handle.0) { - self.sampler_cache_by_desc - .lock()? - .remove(&internal_info.desc); - debug!("Sampler handle {:?} removed for destruction.", handle); - Ok(()) - } else { - warn!( - "Attempted to destroy non-existent sampler handle {:?}", - handle - ); - Err(ResourceManagerError::HandleNotFound(handle.0)) - } - } - - /// Loads a texture from a file path or embedded data using glTF info. - /// Handles image decoding, resource creation, upload and caching. - pub fn load_texture( - &self, - gltf_image: &gltf::Image, - gltf_source: &gltf::image::Source, - base_path: &Path, - buffers: &[gltf::buffer::Data], - usage: vk::ImageUsageFlags, - ) -> Result> { - let cache_key_path: Option = match gltf_source { - gltf::image::Source::View { view, mime_type } => todo!(), - gltf::image::Source::Uri { uri, mime_type } => { - let image_path = base_path.join(uri); - match fs::canonicalize(&image_path) { - Ok(canon_path) => Some(canon_path), - Err(e) => { - warn!( - "Failed to canonicalize image path {:?}: {} Skipping cache lookup", - image_path, e - ); - None - } - } - } - }; - - if let Some(ref path_key) = cache_key_path { - let uri_cache = self.texture_cache_uri.lock()?; - if let Some(cached_texture) = uri_cache.get(path_key) { - if self.images.lock()?.contains_key(&cached_texture.handle.0) { - trace!("Using cached texture (URI): {:?}", path_key); - return Ok(cached_texture.clone()); - } else { - warn!( - "Texture hadnle {:?} found in URI cache but not in main map. Will reload.", - cached_texture.handle - ); - } - } - } - - let (image_data, _format_hint) = match gltf_source { - gltf::image::Source::Uri { uri, mime_type } => { - let image_path = base_path.join(uri); - debug!("Loading texture from URI: {:?}", image_path); - let bytes = fs::read(&image_path).map_err(|e| { - error!("Failed to read image file {:?}: {}", image_path, e); - ResourceManagerError::Io(e) - })?; - (bytes, mime_type.map(|s| s.to_string())) - } - gltf::image::Source::View { view, mime_type } => { - debug!( - "Loading texture from buffer view: index={}, offset={}, length={}", - view.buffer().index(), - view.offset(), - view.length() - ); - let buffer_data = &buffers[view.buffer().index()]; - let start = view.offset(); - let end = start + view.length(); - if end > buffer_data.len() { - return Err(ResourceManagerError::Other(format!( - "Buffer view out of bounds for image: view index {}, buffer index {}", - view.index(), - view.buffer().index() - ))); - } - let bytes: Vec = buffer_data[start..end].to_vec(); // Clone data - (bytes, Some(mime_type.to_string())) // mime_type is required for View - } - }; - - let img = image::load_from_memory(&image_data)?; - - let rgba_image = img.to_rgba8(); - let (width, height) = rgba_image.dimensions(); - let raw_pixels = rgba_image.into_raw(); - - let vk_format = vk::Format::R8G8B8A8_SRGB; - - let extent = vk::Extent3D { - width, - height, - depth: 1, - }; - let image_create_info = vk::ImageCreateInfo::default() - .image_type(vk::ImageType::TYPE_2D) - .format(vk_format) - .extent(extent) - .mip_levels(1) // TODO: Add mipmap generation - .array_layers(1) - .samples(vk::SampleCountFlags::TYPE_1) - .tiling(vk::ImageTiling::OPTIMAL) // Textures should be optimal - .usage(usage | vk::ImageUsageFlags::TRANSFER_DST | vk::ImageUsageFlags::SAMPLED) // Ensure needed usages - .sharing_mode(vk::SharingMode::EXCLUSIVE) - .initial_layout(vk::ImageLayout::UNDEFINED); // create_image_init handles transition - - let image_handle = self.create_image_init( - &image_create_info, - MemoryLocation::GpuOnly, // Textures usually live on GPU - vk::ImageAspectFlags::COLOR, - &raw_pixels, - )?; - - let app_texture = Arc::new(Texture { - handle: image_handle, - format: vk_format, - extent, - }); - - if let Some(path_key) = cache_key_path { - self.texture_cache_uri - .lock()? - .insert(path_key, app_texture.clone()); - trace!("Texture added to URI cache."); - } - - Ok(app_texture) - } - - /// Transitions the layout of an image using a command buffer. - /// Updates the internal layout state. - pub fn transition_image_layout( - &self, - image_handle: ImageHandle, - new_layout: vk::ImageLayout, - ) -> Result<()> { - let transfer_setup_locked = self.transfer_setup.lock()?; - let mut images_locked = self.images.lock()?; - - let internal_info = images_locked - .get_mut(&image_handle.0) - .ok_or(ResourceManagerError::HandleNotFound(image_handle.0))?; - - let old_layout = internal_info.layout; - if old_layout == new_layout { - trace!( - "Image {:?} already in layout {:?}. Skipping transition.", - image_handle, - new_layout - ); - return Ok(()); - } - - trace!( - "Transitioning image {:?} layout {:?} -> {:?}", - image_handle, - old_layout, - new_layout - ); - - let aspect_mask = if new_layout == vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL - || old_layout == vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL - { - vk::ImageAspectFlags::DEPTH - } else { - vk::ImageAspectFlags::COLOR - }; - - let subresource_range = vk::ImageSubresourceRange::default() - .aspect_mask(aspect_mask) - .base_mip_level(0) - .level_count(1) - .base_array_layer(0) - .layer_count(1); - - unsafe { - Self::submit_commands_and_wait(self, &transfer_setup_locked, |cmd| { - let (src_access_mask, dst_access_mask, src_stage, dst_stage) = - Self::get_barrier_params(old_layout, new_layout); - - let barrier = vk::ImageMemoryBarrier::default() - .old_layout(old_layout) - .new_layout(new_layout) - .src_queue_family_index(vk::QUEUE_FAMILY_IGNORED) - .dst_queue_family_index(vk::QUEUE_FAMILY_IGNORED) - .image(internal_info.image) - .subresource_range(subresource_range) - .src_access_mask(src_access_mask) - .dst_access_mask(dst_access_mask); - - self.device.raw().cmd_pipeline_barrier( - cmd, - src_stage, - dst_stage, - vk::DependencyFlags::empty(), - &[], - &[], - &[barrier], - ); - Ok(()) - })?; - } - - internal_info.layout = new_layout; - debug!( - "Image {:?} layout transitioned to {:?} 🏳️‍⚧️", - image_handle, new_layout - ); - Ok(()) - } - - fn get_barrier_params( - old_layout: vk::ImageLayout, - new_layout: vk::ImageLayout, - ) -> ( - vk::AccessFlags, - vk::AccessFlags, - vk::PipelineStageFlags, - vk::PipelineStageFlags, - ) { - let src_access_mask; - let dst_access_mask; - let src_stage; - let dst_stage; - - match (old_layout, new_layout) { - (vk::ImageLayout::UNDEFINED, vk::ImageLayout::TRANSFER_DST_OPTIMAL) => { - src_access_mask = vk::AccessFlags::empty(); - dst_access_mask = vk::AccessFlags::TRANSFER_WRITE; - src_stage = vk::PipelineStageFlags::TOP_OF_PIPE; - dst_stage = vk::PipelineStageFlags::TRANSFER; - } - (vk::ImageLayout::TRANSFER_DST_OPTIMAL, vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL) => { - src_access_mask = vk::AccessFlags::TRANSFER_WRITE; - dst_access_mask = vk::AccessFlags::SHADER_READ; - src_stage = vk::PipelineStageFlags::TRANSFER; - dst_stage = vk::PipelineStageFlags::FRAGMENT_SHADER; - } - (vk::ImageLayout::UNDEFINED, vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL) => { - src_access_mask = vk::AccessFlags::empty(); - dst_access_mask = vk::AccessFlags::SHADER_READ; - src_stage = vk::PipelineStageFlags::TOP_OF_PIPE; - dst_stage = vk::PipelineStageFlags::FRAGMENT_SHADER; - } - _ => { - warn!( - "Unsupported layout trasnition: {:?} -> {:?}", - old_layout, new_layout - ); - src_access_mask = vk::AccessFlags::MEMORY_WRITE; - dst_access_mask = vk::AccessFlags::MEMORY_READ; - src_stage = vk::PipelineStageFlags::ALL_COMMANDS; - dst_stage = vk::PipelineStageFlags::ALL_COMMANDS; - } - } - - (src_access_mask, dst_access_mask, src_stage, dst_stage) - } + // TODO: Implement create_image_init (similar to create_buffer_init but uses vkCmdCopyBufferToImage and layout transitions) /// Destroys a buffer and frees its memory. pub fn destroy_buffer(&self, handle: BufferHandle) -> Result<()> { debug!("Requesting destroy for buffer handle {:?}", handle); - let mut buffers_map = self.buffers.lock()?; + let mut buffers_map = self.buffers.lock(); // Remove the entry. The Drop impl of InternalBufferInfo handles the cleanup. if buffers_map.remove(&handle.0).is_some() { debug!("Buffer handle {:?} removed for destruction.", handle); @@ -1193,7 +518,7 @@ impl ResourceManager { /// Destroys an image, its view, and frees its memory. pub fn destroy_image(&self, handle: ImageHandle) -> Result<()> { debug!("Requesting destroy for image handle {:?}", handle); - let mut images_map = self.images.lock()?; + let mut images_map = self.images.lock(); // Remove the entry. The Drop impl of InternalImageInfo handles the cleanup. if images_map.remove(&handle.0).is_some() { debug!("Image handle {:?} removed for destruction.", handle); @@ -1209,67 +534,36 @@ impl ResourceManager { /// Gets non-owning information about a buffer. pub fn get_buffer_info(&self, handle: BufferHandle) -> Result { - let buffers_map = self.buffers.lock()?; + let buffers_map = self.buffers.lock(); buffers_map .get(&handle.0) - .map(|internal| { - let mapped_ptr = internal - .allocation - .as_ref() - .and_then(|a| a.mapped_ptr().map(|p| p.as_ptr() as *mut u8)); - - BufferInfo { - handle: internal.handle, - buffer: internal.buffer, - size: internal.size, - usage: internal.usage, - mapped_ptr, - } + .map(|internal| BufferInfo { + handle: internal.handle, + buffer: internal.buffer, + size: internal.size, + usage: internal.usage, + mapped_ptr: internal.mapped_ptr, }) .ok_or(ResourceManagerError::HandleNotFound(handle.0)) } + /// Gets non-owning information about an image. pub fn get_image_info(&self, handle: ImageHandle) -> Result { - let images_map = self - .images - .lock() - .map_err(|_| ResourceManagerError::Other("Image map mutex poisoned".to_string()))?; + let images_map = self.images.lock(); images_map .get(&handle.0) - .map(|internal| { - let mapped_ptr = internal - .allocation - .as_ref() - .and_then(|a| a.mapped_ptr().map(|p| p.as_ptr() as *mut u8)); - - ImageInfo { - handle: internal.handle, - image: internal.image, - default_view_handle: internal.default_view_handle, // Return handle - format: internal.format, - extent: internal.extent, - usage: internal.usage, - layout: internal.layout, - mapped_ptr, - } + .map(|internal| ImageInfo { + handle: internal.handle, + image: internal.image, + view: internal.view, + format: internal.format, + extent: internal.extent, + usage: internal.usage, + layout: internal.layout, // Note: Layout tracking is basic here }) .ok_or(ResourceManagerError::HandleNotFound(handle.0)) } - /// Gets non-owning information about a specific image view. - pub fn get_image_view_info(&self, handle: ImageViewHandle) -> Result { - let views_map = self.image_views.lock().map_err(|_| { - ResourceManagerError::Other("Image view map mutex poisoned".to_string()) - })?; - views_map - .get(&handle.0) - .map(|internal| ImageViewInfo { - handle: internal.handle, - view: internal.view, - }) - .ok_or(ResourceManagerError::HandleNotFound(handle.0)) // Use handle.0 - } - /// Explicitly waits for the device to be idle. Useful before shutdown. pub fn wait_device_idle(&self) -> Result<(), ResourceManagerError> { self.device @@ -1281,66 +575,42 @@ impl ResourceManager { impl Drop for ResourceManager { fn drop(&mut self) { debug!("Destroying ResourceManager..."); - // Wait for idle BEFORE locking/clearing maps - if let Err(e) = unsafe { self.device.raw().device_wait_idle() } { + // Ensure all GPU operations are finished before freeing memory/destroying resources + if let Err(e) = self.device.wait_idle() { error!( "Failed to wait for device idle during ResourceManager drop: {}", e ); - // Proceeding, but cleanup might be unsafe + // Proceeding with cleanup, but resources might still be in use! } - // Clear resource maps. This triggers the Drop impl for each Internal*Info. - if let Ok(mut buffers_map) = self.buffers.lock() { - debug!("Clearing {} buffer entries...", buffers_map.len()); - buffers_map.clear(); - } else { - error!("Buffer map mutex poisoned during drop."); - } - - if let Ok(mut images_map) = self.images.lock() { - debug!("Clearing {} image entries...", images_map.len()); - images_map.clear(); - } else { - error!("Image map mutex poisoned during drop."); - } - - if let Ok(mut samplers_map) = self.samplers.lock() { - debug!("Clearing {} sampler entries...", samplers_map.len()); - samplers_map.clear(); - } else { - error!("Sampler map mutex poisoned during drop."); - } - - // Clear caches (Arc drops will happen naturally) - if let Ok(mut sampler_cache) = self.sampler_cache_by_desc.lock() { - sampler_cache.clear(); - } else { - error!("Sampler cache mutex poisoned during drop."); - } - if let Ok(mut texture_cache) = self.texture_cache_uri.lock() { - texture_cache.clear(); - } else { - error!("Texture URI cache mutex poisoned during drop."); - } - // Clear other caches... + // Clear resource maps. This triggers the Drop impl for each Internal*Info, + // which frees allocations and destroys Vulkan objects. + let mut buffers_map = self.buffers.lock(); + debug!("Clearing {} buffer entries...", buffers_map.len()); + buffers_map.clear(); + let mut images_map = self.images.lock(); + debug!("Clearing {} image entries...", images_map.len()); + images_map.clear(); // Destroy transfer setup resources - if let Ok(setup) = self.transfer_setup.lock() { + let mut setup_guard = self.transfer_setup.lock(); + if let Some(setup) = setup_guard.take() { + // take() removes it from the Option debug!("Destroying TransferSetup resources..."); unsafe { + self.device.raw().destroy_fence(setup.fence, None); self.device .raw() .destroy_command_pool(setup.command_pool, None); } debug!("TransferSetup resources destroyed."); - } else { - error!("TransferSetup mutex poisoned during drop."); } - // Allocator Drop: gpu-allocator's Allocator doesn't do anything in drop. - // Memory is freed via allocator.free() called by Internal*Info drops. - // The Arc> will be dropped when the last reference goes away. + // The Allocator is wrapped in an Arc>, so its Drop will be handled + // when the last Arc reference (including those held by Internal*Info) is dropped. + // gpu-allocator's Allocator Drop implementation should be empty, as memory + // is freed via allocator.free(). debug!("ResourceManager destroyed."); } diff --git a/crates/resource_manager/src/texture.rs b/crates/resource_manager/src/texture.rs deleted file mode 100644 index 857e0f5..0000000 --- a/crates/resource_manager/src/texture.rs +++ /dev/null @@ -1,59 +0,0 @@ -use std::sync::Arc; - -use ash::vk; - -use crate::{ImageHandle, SamplerHandle}; - -#[derive(Debug, Clone)] -pub struct Texture { - pub handle: ImageHandle, - - pub format: vk::Format, - pub extent: vk::Extent3D, -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct SamplerDesc { - pub mag_filter: vk::Filter, - pub min_filter: vk::Filter, - pub mipmap_mode: vk::SamplerMipmapMode, - pub address_mode_u: vk::SamplerAddressMode, - pub address_mode_v: vk::SamplerAddressMode, - pub address_mode_w: vk::SamplerAddressMode, -} - -impl Default for SamplerDesc { - fn default() -> Self { - Self { - mag_filter: vk::Filter::LINEAR, - min_filter: vk::Filter::LINEAR, - mipmap_mode: vk::SamplerMipmapMode::LINEAR, - address_mode_u: vk::SamplerAddressMode::REPEAT, - address_mode_v: vk::SamplerAddressMode::REPEAT, - address_mode_w: vk::SamplerAddressMode::REPEAT, - } - } -} - -#[derive(Debug, Clone)] -pub struct Material { - pub name: String, - pub base_color_texture: Option>, - pub base_color_sampler: Option, - pub base_color_factor: [f32; 4], - pub metallic_factor: f32, - pub roughness_factor: f32, - // TODO: Add other PBR properties: - // pub metallic_roughness_texture: Option>, - // pub metallic_roughness_sampler: Option, - // pub normal_texture: Option>, - // pub normal_sampler: Option, - // pub occlusion_texture: Option>, - // pub occlusion_sampler: Option, - // pub emissive_texture: Option>, - // pub emissive_sampler: Option, - // pub emissive_factor: [f32; 3], - // pub alpha_mode: gltf::material::AlphaMode, - // pub alpha_cutoff: f32, - // pub double_sided: bool, -} diff --git a/crates/scene/Cargo.toml b/crates/scene/Cargo.toml deleted file mode 100644 index 6a67b50..0000000 --- a/crates/scene/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "scene" -version = "0.1.0" -edition = "2021" - -[dependencies] -ash.workspace = true -thiserror.workspace = true -tracing.workspace = true -glam.workspace = true -gltf.workspace = true - -shared = { path = "../shared" } -resource_manager = { path = "../resource_manager" } diff --git a/crates/scene/src/error.rs b/crates/scene/src/error.rs deleted file mode 100644 index b052c9c..0000000 --- a/crates/scene/src/error.rs +++ /dev/null @@ -1,16 +0,0 @@ -use thiserror::Error; - -/// Any errors that can be returned from this crate. -#[derive(Error, Debug)] -pub enum SceneError { - #[error("Error from ResourceManager: {0}")] - ResourceManagerError(#[from] resource_manager::ResourceManagerError), - - #[error("Error from GLTF: {0}")] - GltfError(#[from] gltf::Error), - - #[error("InconsistentData: {0}")] - InconsistentData(String), -} - -pub type Result = std::result::Result; diff --git a/crates/scene/src/lib.rs b/crates/scene/src/lib.rs deleted file mode 100644 index fd672ac..0000000 --- a/crates/scene/src/lib.rs +++ /dev/null @@ -1,411 +0,0 @@ -mod error; - -use ash::vk; -pub use error::{Result, SceneError}; -use glam::Mat4; -use shared::Vertex; - -use std::{collections::HashMap, path::Path, sync::Arc}; - -use resource_manager::{Geometry, Material, ResourceManager, SamplerDesc, SamplerHandle, Texture}; - -/// Represents a drawable entity in the scene, storing geometry with its transform. -#[derive(Clone)] -pub struct Mesh { - pub name: String, - pub material: Arc, - pub geometry: Arc, - pub transform: Mat4, -} - -/// Stores all objects to be rendered by the renderer. -pub struct Scene { - pub name: String, - pub meshes: Vec, -} - -fn sampler_desc_from_gltf(g_sampler: &gltf::texture::Sampler) -> SamplerDesc { - let wrap_s = g_sampler.wrap_s(); - let wrap_t = g_sampler.wrap_t(); - - SamplerDesc { - mag_filter: g_sampler - .mag_filter() - .map_or(vk::Filter::LINEAR, |mf| match mf { - gltf::texture::MagFilter::Nearest => vk::Filter::NEAREST, - gltf::texture::MagFilter::Linear => vk::Filter::LINEAR, - }), - min_filter: g_sampler - .min_filter() - .map_or(vk::Filter::LINEAR, |mf| match mf { - gltf::texture::MinFilter::Nearest - | gltf::texture::MinFilter::NearestMipmapNearest - | gltf::texture::MinFilter::NearestMipmapLinear => vk::Filter::NEAREST, - gltf::texture::MinFilter::Linear - | gltf::texture::MinFilter::LinearMipmapNearest - | gltf::texture::MinFilter::LinearMipmapLinear => vk::Filter::LINEAR, - }), - mipmap_mode: g_sampler - .min_filter() - .map_or(vk::SamplerMipmapMode::LINEAR, |mf| match mf { - gltf::texture::MinFilter::NearestMipmapNearest - | gltf::texture::MinFilter::LinearMipmapNearest => vk::SamplerMipmapMode::NEAREST, - gltf::texture::MinFilter::NearestMipmapLinear - | gltf::texture::MinFilter::LinearMipmapLinear => vk::SamplerMipmapMode::LINEAR, - _ => vk::SamplerMipmapMode::LINEAR, // Default if no mipmapping - }), - address_mode_u: vk_address_mode(wrap_s), - address_mode_v: vk_address_mode(wrap_t), - address_mode_w: vk::SamplerAddressMode::REPEAT, // glTF doesn't define wrapR - } -} - -fn vk_address_mode(g_mode: gltf::texture::WrappingMode) -> vk::SamplerAddressMode { - match g_mode { - gltf::texture::WrappingMode::ClampToEdge => vk::SamplerAddressMode::CLAMP_TO_EDGE, - gltf::texture::WrappingMode::MirroredRepeat => vk::SamplerAddressMode::MIRRORED_REPEAT, - gltf::texture::WrappingMode::Repeat => vk::SamplerAddressMode::REPEAT, - } -} - -impl Scene { - /// Takes a glTF file and returns a `Scene`. - pub fn from_gltf(path: T, resource_manager: Arc) -> Result - where - T: AsRef, - { - let path_ref = path.as_ref(); - let base_path = path_ref.parent().unwrap_or_else(|| Path::new("")); - tracing::info!("Loading glTF from: {:?}", path_ref); - tracing::info!("Base path for resources: {:?}", base_path); - - // Import images as well - let (doc, buffers, images) = gltf::import(path_ref)?; - tracing::info!( - "glTF Stats: {} scenes, {} nodes, {} meshes, {} materials, {} textures, {} images", - doc.scenes().len(), - doc.nodes().len(), - doc.meshes().len(), - doc.materials().len(), - doc.textures().len(), - doc.images().len() - ); - - let mut meshes = Vec::new(); - // Cache Geometry: Key = (mesh_index, primitive_index) - let mut geometry_cache: HashMap<(usize, usize), Arc> = HashMap::new(); - // Cache Materials: Key = glTF material index (usize::MAX for default) - let mut material_cache: HashMap> = HashMap::new(); - // Cache default sampler handle to avoid repeated lookups - let default_sampler_handle = - resource_manager.get_or_create_sampler(&SamplerDesc::default())?; - - let scene_to_load = doc - .default_scene() - .unwrap_or_else(|| doc.scenes().next().expect("No scenes found in glTF")); - - let scene_name = scene_to_load - .name() - .unwrap_or("") - .to_string(); - tracing::info!( - "Processing scene '{}' ({})", - scene_name, - scene_to_load.index() - ); - - // Create a context struct to pass around common data - let mut load_ctx = LoadContext { - doc: &doc, - buffers: &buffers, - images: &images, - base_path, - resource_manager, - geometry_cache: &mut geometry_cache, - material_cache: &mut material_cache, - default_sampler_handle, - meshes: &mut meshes, - }; - - for node in scene_to_load.nodes() { - Self::process_node(&node, &Mat4::IDENTITY, &mut load_ctx)?; - } - - tracing::info!("Successfully loaded {} render meshes.", meshes.len()); - - Ok(Self { - name: scene_name, - meshes, - }) - } - - /// Recursively processes a glTF node. - fn process_node( - node: &gltf::Node, - parent_transform: &Mat4, - ctx: &mut LoadContext, // Pass context mutably for caches - ) -> Result<()> { - let local_transform = Mat4::from_cols_array_2d(&node.transform().matrix()); - let world_transform = *parent_transform * local_transform; - let node_name = node.name().unwrap_or(""); - - if let Some(mesh) = node.mesh() { - let mesh_index = mesh.index(); - let mesh_name = mesh.name().unwrap_or(""); - tracing::debug!( - "Node '{}' ({}) has Mesh '{}' ({})", - node_name, - node.index(), - mesh_name, - mesh_index - ); - - // Process mesh primitives - for (primitive_index, primitive) in mesh.primitives().enumerate() { - // Generate a name for the Mesh object - let primitive_name = format!("{}_prim{}", mesh_name, primitive_index); - - Self::process_primitive( - &primitive, - mesh_index, - primitive_index, - &primitive_name, // Pass name - world_transform, - ctx, // Pass context - )?; - } - } else { - tracing::trace!("Node '{}' ({}) has no mesh.", node_name, node.index()); - } - - // Recursively process child nodes - for child_node in node.children() { - Self::process_node( - &child_node, - &world_transform, // Pass current world transform - ctx, // Pass context - )?; - } - - Ok(()) - } - - /// Processes a single glTF primitive, creating Geometry, Material, and Mesh. - fn process_primitive( - primitive: &gltf::Primitive, - mesh_index: usize, - primitive_index: usize, - mesh_name: &str, // Name for the final Mesh object - world_transform: Mat4, - ctx: &mut LoadContext, // Use context - ) -> Result<()> { - let geometry_cache_key = (mesh_index, primitive_index); - - // --- Get or Create Geometry --- - let geometry = if let Some(cached_geo) = ctx.geometry_cache.get(&geometry_cache_key) { - tracing::trace!("Using cached Geometry for key {:?}", geometry_cache_key); - cached_geo.clone() - } else { - tracing::trace!("Creating new Geometry for key {:?}", geometry_cache_key); - let reader = primitive.reader(|buffer| Some(&ctx.buffers[buffer.index()])); - - let Some(pos_iter) = reader.read_positions() else { - tracing::warn!( - "Primitive {:?} missing positions. Skipping.", - geometry_cache_key - ); - return Ok(()); // Skip this primitive - }; - let positions: Vec<[f32; 3]> = pos_iter.collect(); - let vertex_count = positions.len(); - - if vertex_count == 0 { - tracing::warn!( - "Primitive {:?} has no vertices. Skipping.", - geometry_cache_key - ); - return Ok(()); - } - - let normals: Vec<[f32; 3]> = reader - .read_normals() - .map(|iter| iter.collect()) - .unwrap_or_else(|| { - tracing::debug!( - "Primitive {:?} missing normals, using default.", - geometry_cache_key - ); - vec![[0.0, 1.0, 0.0]; vertex_count] - }); - - // Read Texture Coordinates (Set 0) - needed for vertex struct regardless of material - let tex_coords: Vec<[f32; 2]> = reader - .read_tex_coords(0) // Read UV set 0 - .map(|iter| iter.into_f32().collect()) - .unwrap_or_else(|| { - tracing::trace!( - "Primitive {:?} missing tex_coords (set 0), using default.", - geometry_cache_key - ); - vec![[0.0, 0.0]; vertex_count] - }); - - if normals.len() != vertex_count || tex_coords.len() != vertex_count { - return Err(SceneError::InconsistentData(format!( - "Attribute count mismatch for Primitive {:?} (Pos: {}, Norm: {}, TexCoord0: {}).", - geometry_cache_key, vertex_count, normals.len(), tex_coords.len() - ))); - } - - let vertices: Vec = positions - .into_iter() - .zip(normals) - .zip(tex_coords) - .map(|((pos, normal), tex_coord)| Vertex { - pos, - normal, - tex_coord, - }) - .collect(); - - let indices: Vec = reader - .read_indices() - .map(|read_indices| read_indices.into_u32().collect()) - .unwrap_or_else(|| (0..vertex_count as u32).collect()); - - if indices.is_empty() && vertex_count > 0 { - tracing::warn!( - "Primitive {:?} has vertices but no indices. Skipping.", - geometry_cache_key - ); - return Ok(()); - } - - let new_geo = Arc::new(Geometry::new( - ctx.resource_manager.clone(), - &vertices, - &indices, - )?); - ctx.geometry_cache - .insert(geometry_cache_key, new_geo.clone()); - new_geo - }; - - // --- Get or Create Material --- - let g_material = primitive.material(); - // Use index usize::MAX as key for default material if index() is None - let material_cache_key = g_material.index().unwrap_or(usize::MAX); - let material_name = g_material.name().unwrap_or(""); - - let material = if let Some(cached_mat) = ctx.material_cache.get(&material_cache_key) { - tracing::trace!( - "Using cached Material index {} ('{}')", - material_cache_key, - material_name - ); - cached_mat.clone() - } else { - tracing::trace!( - "Creating new Material for index {} ('{}')", - material_cache_key, - material_name - ); - let pbr = g_material.pbr_metallic_roughness(); - - let base_color_factor = pbr.base_color_factor(); - let metallic_factor = pbr.metallic_factor(); - let roughness_factor = pbr.roughness_factor(); - - let mut loaded_base_color_texture: Option> = None; - let mut loaded_base_color_sampler: Option = None; - - // --- Load Base Color Texture (if it exists) --- - if let Some(color_info) = pbr.base_color_texture() { - let tex_coord_set = color_info.tex_coord(); - if tex_coord_set != 0 { - tracing::warn!( - "Material '{}' requests tex_coord set {}, but only set 0 is currently loaded. Texture ignored.", - material_name, tex_coord_set - ); - // Fall through, texture won't be loaded - } else { - let g_texture = color_info.texture(); - let g_sampler = g_texture.sampler(); - let g_image = g_texture.source(); // This is the gltf::Image - - tracing::debug!( - "Material '{}' uses Texture index {}, Sampler index {:?}, Image index {}", - material_name, - g_texture.index(), - g_sampler.index(), - g_image.index() - ); - - // Get or create sampler - let sampler_desc = sampler_desc_from_gltf(&g_sampler); - let sampler_handle = - ctx.resource_manager.get_or_create_sampler(&sampler_desc)?; - loaded_base_color_sampler = Some(sampler_handle); - - // Load texture image data via ResourceManager - // Pass the correct gltf::Image using its index - let texture = ctx.resource_manager.load_texture( - &ctx.doc - .images() - .nth(g_image.index()) - .expect("Image index out of bounds"), // Get gltf::Image - &g_image.source(), // Get gltf::image::Source - ctx.base_path, - ctx.buffers, - vk::ImageUsageFlags::SAMPLED, // Standard usage for textures - )?; - loaded_base_color_texture = Some(texture); // Store Arc - } - } - - // Assign default sampler if none was loaded via texture info - if loaded_base_color_sampler.is_none() { - loaded_base_color_sampler = Some(ctx.default_sampler_handle); - tracing::trace!("Material '{}' using default sampler.", material_name); - } - - // Create the application Material struct - let new_mat = Arc::new(Material { - name: material_name.to_string(), - base_color_texture: loaded_base_color_texture, - base_color_sampler: loaded_base_color_sampler, - base_color_factor, - metallic_factor, - roughness_factor, - // Initialize other material properties here... - }); - - ctx.material_cache - .insert(material_cache_key, new_mat.clone()); - new_mat - }; - - // Create the final Mesh object - ctx.meshes.push(Mesh { - name: mesh_name.to_string(), - geometry, - material, // Assign the Arc - transform: world_transform, - }); - - Ok(()) - } -} - -// Context struct to avoid passing too many arguments -struct LoadContext<'a> { - doc: &'a gltf::Document, - buffers: &'a [gltf::buffer::Data], - images: &'a [gltf::image::Data], // Keep image data accessible if needed by RM - base_path: &'a Path, - resource_manager: Arc, - geometry_cache: &'a mut HashMap<(usize, usize), Arc>, - material_cache: &'a mut HashMap>, - default_sampler_handle: SamplerHandle, // Store the default sampler - meshes: &'a mut Vec, // Store results directly -} diff --git a/crates/shared/Cargo.toml b/crates/shared/Cargo.toml deleted file mode 100644 index 3e93fdc..0000000 --- a/crates/shared/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "shared" -version = "0.1.0" -edition = "2021" - -[dependencies] -glam.workspace = true -ash.workspace = true -bytemuck.workspace = true -memoffset = "0.9.1" -derive_builder = "0.20.2" diff --git a/crates/shared/src/lib.rs b/crates/shared/src/lib.rs deleted file mode 100644 index 120f579..0000000 --- a/crates/shared/src/lib.rs +++ /dev/null @@ -1,70 +0,0 @@ -use ash::vk; -use glam::{Mat4, Vec3}; - -use core::f32; -use std::mem::size_of; - -mod material; - -#[repr(C)] -#[derive(Clone, Debug, Copy)] -pub struct Vertex { - pub pos: [f32; 3], - pub normal: [f32; 3], - pub tex_coord: [f32; 2], -} - -impl Vertex { - pub fn get_binding_decription() -> vk::VertexInputBindingDescription { - vk::VertexInputBindingDescription::default() - .binding(0) - .stride(size_of::() as u32) - .input_rate(vk::VertexInputRate::VERTEX) - } - - pub fn get_attribute_descriptions() -> [vk::VertexInputAttributeDescription; 3] { - [ - vk::VertexInputAttributeDescription::default() - .location(0) - .binding(0) - .format(vk::Format::R32G32B32_SFLOAT) - .offset(memoffset::offset_of!(Vertex, pos) as u32), - vk::VertexInputAttributeDescription::default() - .location(1) - .binding(0) - .format(vk::Format::R32G32B32_SFLOAT) - .offset(memoffset::offset_of!(Vertex, normal) as u32), - vk::VertexInputAttributeDescription::default() - .location(2) - .binding(0) - .format(vk::Format::R32G32_SFLOAT) - .offset(memoffset::offset_of!(Vertex, tex_coord) as u32), - ] - } -} - -#[repr(C)] -#[derive(Clone, Debug, Copy, PartialEq)] -pub struct UniformBufferObject { - pub view: Mat4, - pub proj: Mat4, -} - -#[derive(Clone, Debug, Copy, PartialEq)] -pub struct CameraInfo { - pub camera_pos: Vec3, - pub camera_target: Vec3, - pub camera_up: Vec3, - pub camera_fov: f32, -} - -impl Default for CameraInfo { - fn default() -> Self { - Self { - camera_pos: Vec3::new(10.0, 10.0, 10.0), - camera_target: Vec3::new(0.0, 0.0, 0.0), - camera_up: Vec3::Y, - camera_fov: 45.0, - } - } -} diff --git a/crates/shared/src/material.rs b/crates/shared/src/material.rs deleted file mode 100644 index e69de29..0000000 diff --git a/flake.lock b/flake.lock index f777db0..a74e166 100644 --- a/flake.lock +++ b/flake.lock @@ -20,11 +20,11 @@ "nixpkgs-lib": "nixpkgs-lib" }, "locked": { - "lastModified": 1743550720, - "narHash": "sha256-hIshGgKZCgWh6AYJpJmRgFdR3WUbkY04o82X05xqQiY=", + "lastModified": 1733312601, + "narHash": "sha256-4pDvzqnegAfRkPwO3wmwBhVi/Sye1mzps0zHWYnP88c=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "c621e8422220273271f52058f618c94e405bb0f5", + "rev": "205b12d8b7cd4802fbcb8e8ef6a0f1408781a4f9", "type": "github" }, "original": { @@ -51,26 +51,23 @@ }, "nixpkgs-lib": { "locked": { - "lastModified": 1743296961, - "narHash": "sha256-b1EdN3cULCqtorQ4QeWgLMrd5ZGOjLSLemfa00heasc=", - "owner": "nix-community", - "repo": "nixpkgs.lib", - "rev": "e4822aea2a6d1cdd36653c134cacfd64c97ff4fa", - "type": "github" + "lastModified": 1733096140, + "narHash": "sha256-1qRH7uAUsyQI7R1Uwl4T+XvdNv778H0Nb5njNrqvylY=", + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/5487e69da40cbd611ab2cadee0b4637225f7cfae.tar.gz" }, "original": { - "owner": "nix-community", - "repo": "nixpkgs.lib", - "type": "github" + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/5487e69da40cbd611ab2cadee0b4637225f7cfae.tar.gz" } }, "nixpkgs_2": { "locked": { - "lastModified": 1736320768, - "narHash": "sha256-nIYdTAiKIGnFNugbomgBJR+Xv5F1ZQU+HfaBqJKroC0=", + "lastModified": 1728538411, + "narHash": "sha256-f0SBJz1eZ2yOuKUr5CA9BHULGXVSn6miBuUWdTyhUhU=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "4bc9c909d9ac828a039f288cf872d16d38185db8", + "rev": "b69de56fac8c2b6f8fd27f2eca01dcda8e0a4221", "type": "github" }, "original": { @@ -82,11 +79,11 @@ }, "nixpkgs_3": { "locked": { - "lastModified": 1735554305, - "narHash": "sha256-zExSA1i/b+1NMRhGGLtNfFGXgLtgo+dcuzHzaWA6w3Q=", + "lastModified": 1733097829, + "narHash": "sha256-9hbb1rqGelllb4kVUCZ307G2k3/UhmA8PPGBoyuWaSw=", "owner": "nixos", "repo": "nixpkgs", - "rev": "0e82ab234249d8eee3e8c91437802b32c74bb3fd", + "rev": "2c15aa59df0017ca140d9ba302412298ab4bf22a", "type": "github" }, "original": { @@ -111,11 +108,11 @@ "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1743820323, - "narHash": "sha256-UXxJogXhPhBFaX4uxmMudcD/x3sEGFtoSc4busTcftY=", + "lastModified": 1735266518, + "narHash": "sha256-2XkWYGgT+911gOLjgBj+8W8ZJk6P0qHJNz8RfKgT/5o=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "b4734ce867252f92cdc7d25f8cc3b7cef153e703", + "rev": "e0b3654b716098b47f3643c65fbb75ef49c033e1", "type": "github" }, "original": { @@ -144,11 +141,11 @@ "nixpkgs": "nixpkgs_3" }, "locked": { - "lastModified": 1743748085, - "narHash": "sha256-uhjnlaVTWo5iD3LXics1rp9gaKgDRQj6660+gbUU3cE=", + "lastModified": 1735135567, + "narHash": "sha256-8T3K5amndEavxnludPyfj3Z1IkcFdRpR23q+T0BVeZE=", "owner": "numtide", "repo": "treefmt-nix", - "rev": "815e4121d6a5d504c0f96e5be2dd7f871e4fd99d", + "rev": "9e09d30a644c57257715902efbb3adc56c79cf28", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 3991877..71450ae 100644 --- a/flake.nix +++ b/flake.nix @@ -35,12 +35,11 @@ commonArgs, ... }: { - _module.args = rec { + _module.args = { pkgs = import nixpkgs { inherit system; overlays = [inputs.rust-overlay.overlays.default]; }; - craneLib = (inputs.crane.mkLib pkgs).overrideToolchain ( pkgs: pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml ); diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 30f36be..551cee7 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,11 +1,6 @@ [toolchain] channel = "nightly-2024-11-22" -components = [ - "rust-src", - "rustc-dev", - "llvm-tools", - "rustc-codegen-cranelift-preview", -] +components = ["rust-src", "rustc-dev", "llvm-tools"] # commit_hash = b19329a37cedf2027517ae22c87cf201f93d776e # Whenever changing the nightly channel, update the commit hash above, and make diff --git a/shaders/frag.glsl.frag b/shaders/frag.glsl.frag index 3e46886..fe7b418 100644 --- a/shaders/frag.glsl.frag +++ b/shaders/frag.glsl.frag @@ -1,34 +1,7 @@ - #version 450 -// Input from vertex shader -layout(location = 0) in vec3 fragNormal; // Receive normal -layout(location = 1) in vec2 fragTexCoord; // Receive texture coordinates - -// Output color layout(location = 0) out vec4 outColor; -// Descriptor set for material properties (Set 1) -layout(set = 1, binding = 0) uniform sampler2D baseColorSampler; - -// Optional: Pass material factors via another UBO or Push Constants if needed -// layout(set = 1, binding = 1) uniform MaterialFactors { -// vec4 baseColorFactor; -// } materialFactors; - void main() { - // Sample the texture - vec4 texColor = texture(baseColorSampler, fragTexCoord); - - // Use the texture color - // You might multiply by baseColorFactor here if you pass it - // outColor = texColor * materialFactors.baseColorFactor; - outColor = texColor; - - // Basic fallback if texture alpha is zero (or use baseColorFactor) - if (outColor.a == 0.0) { - outColor = vec4(0.8, 0.8, 0.8, 1.0); // Default grey - } - - // You could add basic lighting using fragNormal here later + outColor = vec4(1.0, 0.5, 0.0, 1.0); // Orange } diff --git a/shaders/vert.glsl.vert b/shaders/vert.glsl.vert index a2053d6..f114dbb 100644 --- a/shaders/vert.glsl.vert +++ b/shaders/vert.glsl.vert @@ -1,38 +1,10 @@ #version 450 - -// INPUTS from Vertex Buffer (matching Vertex struct) -layout(location = 0) in vec3 inPosition; -layout(location = 1) in vec3 inNormal; -layout(location = 2) in vec2 inTexCoord; // <<< MUST be vec2 - -// UNIFORMS (Set 0) -layout(set = 0, binding = 0) uniform UniformBufferObject { - mat4 view; - mat4 proj; -} ubo; - -// PUSH CONSTANTS -layout(push_constant) uniform PushConstants { - mat4 model; -} pushConstants; - -// OUTPUTS to Fragment Shader -layout(location = 0) out vec3 fragNormal; // Location 0 for Normal -layout(location = 1) out vec2 fragTexCoord; // Location 1 for TexCoord +vec2 positions[3] = vec2[]( + vec2(0.0, -0.5), + vec2(0.5, 0.5), + vec2(-0.5, 0.5) + ); void main() { - vec4 worldPos = pushConstants.model * vec4(inPosition, 1.0); - - // Calculate final position - gl_Position = ubo.proj * ubo.view * worldPos; - - // --- Pass attributes to Fragment Shader --- - - // Pass world-space normal (adjust calculation if needed) - // Ensure fragNormal is assigned a vec3 - fragNormal = normalize(mat3(transpose(inverse(pushConstants.model))) * inNormal); - - // Pass texture coordinates (ensure inTexCoord is vec2) - // Ensure fragTexCoord is assigned a vec2 - fragTexCoord = inTexCoord; + gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); }