diff --git a/Cargo.lock b/Cargo.lock index e5cdc3e..3951f9f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,11 +8,20 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9fe5e32de01730eb1f6b7f5b51c17e03e2325bf40a74f754f04f130043affff" +[[package]] +name = "addr2line" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a2e47a1fbe209ee101dd6d61285226744c6c8d3c21c8dc878ba6cb9f467f3a" +dependencies = [ + "gimli", +] + [[package]] name = "adler" -version = "0.2.3" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "adler32" @@ -53,24 +62,24 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.40" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" +checksum = "595d3cfa7a60d4555cb5067b99f07142a08ea778de5cf993f7b75c7d8fabc486" [[package]] name = "ash" -version = "0.31.0" +version = "0.33.0+1.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c69a8137596e84c22d57f3da1b5de1d4230b1742a710091c85f4d7ce50f00f38" +checksum = "a2142f1fa77cc4d24ffd2f24dc84f88ce5b1e588d524f10fb473a04b93aef14f" dependencies = [ - "libloading", + "libloading 0.7.0", ] [[package]] name = "ash-window" -version = "0.5.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "905c4ca25f752e7ab3c3e8f2882625f876e4c3ea5feffbc83f81d697e043afd6" +checksum = "12f91ce4c6be1a2ba99d3d6cd57d5bae9ac6d6f903b5ae53d6b1dee2edf872af" dependencies = [ "ash", "raw-window-handle", @@ -94,21 +103,35 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +[[package]] +name = "backtrace" +version = "0.3.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4717cfcbfaa661a0fd48f8453951837ae7e8f81e481fbb136e3202d72805a744" +dependencies = [ + "addr2line", + "cc", + "cfg-if 1.0.0", + "libc", + "miniz_oxide 0.4.4", + "object", + "rustc-demangle", +] + [[package]] name = "bincode" -version = "1.3.2" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d175dfa69e619905c4c3cdb7c3c203fa3bdd5d51184e3afdb2742c0280493772" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" dependencies = [ - "byteorder", "serde", ] [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +checksum = "2da1976d75adbe5fbc88130ecd119529cf1cc6a93ae1546d8696ee66f0d21af1" [[package]] name = "block" @@ -118,21 +141,21 @@ checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" [[package]] name = "bumpalo" -version = "3.6.1" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe" +checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631" [[package]] name = "bytemuck" -version = "1.5.0" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a4bad0c5981acc24bc09e532f35160f952e35422603f0563cd7a73c2c2e65a0" +checksum = "72957246c41db82b8ef88a5486143830adeb8227ef9837740bdec67724cf2c5b" [[package]] name = "byteorder" -version = "1.3.4" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "calloop" @@ -141,14 +164,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b036167e76041694579972c28cf4877b4f92da222560ddb49008937b6a6727c" dependencies = [ "log", - "nix", + "nix 0.18.0", ] [[package]] name = "cc" -version = "1.0.66" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" +checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2" dependencies = [ "jobserver", ] @@ -217,12 +240,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" -[[package]] -name = "const_fn" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b9d6de7f49e22cf97ad17fc4036ece69300032f45f78f30b4a4482cdc3f4a6" - [[package]] name = "core-foundation" version = "0.7.0" @@ -316,9 +333,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775" +checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" dependencies = [ "cfg-if 1.0.0", "crossbeam-utils", @@ -326,9 +343,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" dependencies = [ "cfg-if 1.0.0", "crossbeam-epoch", @@ -337,12 +354,11 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.1" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1aaa739f95311c2c7887a76863f500026092fb1dce0161dab577e559ef3569d" +checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" dependencies = [ "cfg-if 1.0.0", - "const_fn", "crossbeam-utils", "lazy_static", "memoffset", @@ -351,11 +367,10 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.1" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d" +checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" dependencies = [ - "autocfg", "cfg-if 1.0.0", "lazy_static", ] @@ -436,7 +451,16 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b11f15d1e3268f140f68d390637d5e76d849782d971ae7063e0da69fe9709a76" dependencies = [ - "libloading", + "libloading 0.6.7", +] + +[[package]] +name = "dlib" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac1b7517328c04c2aa68422fc60a41b92208182142ed04a25879c26c8f878794" +dependencies = [ + "libloading 0.7.0", ] [[package]] @@ -453,9 +477,9 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "env_logger" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17392a012ea30ef05a610aa97dfb49496e71c9f676b27879922ea5bdf60d9d3f" +checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" dependencies = [ "atty", "humantime", @@ -503,28 +527,45 @@ checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" [[package]] name = "gif" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02efba560f227847cb41463a7395c514d127d4f74fff12ef0137fff1b84b96c4" +checksum = "5a668f699973d0f573d15749b7002a9ac9e1f9c6b220e7b165601334c173d8de" dependencies = [ "color_quant", "weezl", ] +[[package]] +name = "gimli" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189" + +[[package]] +name = "gpu-allocator" +version = "0.8.0" +source = "git+https://github.com/Traverse-Research/gpu-allocator#e66d062cbd73a6c98834fc3e3acef98318097156" +dependencies = [ + "ash", + "backtrace", + "log", + "thiserror", +] + [[package]] name = "heck" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" dependencies = [ "unicode-segmentation", ] [[package]] name = "hermit-abi" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "libc", ] @@ -543,9 +584,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "image" -version = "0.23.13" +version = "0.23.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "293f07a1875fa7e9c5897b51aa68b2d8ed8271b87e1a44cb64b9c3d98aabbc0d" +checksum = "24ffcb7e7244a9bf19d35bf2883b9c080c4ced3c07a9895572178cdb8f13f6a1" dependencies = [ "bytemuck", "byteorder", @@ -562,9 +603,9 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" +checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d" dependencies = [ "cfg-if 1.0.0", ] @@ -586,9 +627,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.21" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c71313ebb9439f74b00d9d2dcec36440beaf57a6aa0623068441dd7cd81a7f2" +checksum = "f5ca711fd837261e14ec9e674f092cbb931d3fa1482b017ae59328ddc6f3212b" dependencies = [ "libc", ] @@ -604,9 +645,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.49" +version = "0.3.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc15e39392125075f60c95ba416f5381ff6c3a948ff02ab12464715adf56c821" +checksum = "ce791b7ca6638aae45be056e068fc756d871eb3b3b10b8efa62d1c9cec616752" dependencies = [ "wasm-bindgen", ] @@ -635,9 +676,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.86" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c" +checksum = "a7f823d141fe0a24df1e23b4af4e3c7ba9e5966ec514ea068c93024aa7deb765" [[package]] name = "libloading" @@ -649,11 +690,21 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "libloading" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f84d96438c15fcd6c3f244c8fce01d1e2b9c6b5623e9c711dc9286d8fc92d6a" +dependencies = [ + "cfg-if 1.0.0", + "winapi 0.3.9", +] + [[package]] name = "lock_api" -version = "0.4.2" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312" +checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb" dependencies = [ "scopeguard", ] @@ -699,9 +750,9 @@ dependencies = [ [[package]] name = "memoffset" -version = "0.6.1" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87" +checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" dependencies = [ "autocfg", ] @@ -717,9 +768,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" dependencies = [ "adler", "autocfg", @@ -836,11 +887,23 @@ dependencies = [ "libc", ] +[[package]] +name = "nix" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a" +dependencies = [ + "bitflags", + "cc", + "cfg-if 1.0.0", + "libc", +] + [[package]] name = "nom" -version = "6.1.0" +version = "6.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab6f70b46d6325aa300f1c7bb3d470127dfc27806d8ea6bf294ee0ce643ce2b1" +checksum = "9c5c51b9083a3c620fa67a2a635d1ce7d95b897e957d6b28ff9a5da960a103a6" dependencies = [ "memchr", "version_check", @@ -928,11 +991,17 @@ dependencies = [ "malloc_buf", ] +[[package]] +name = "object" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5b3dd1c072ee7963717671d1ca129f1048fda25edea6b752bfc71ac8854170" + [[package]] name = "once_cell" -version = "1.5.2" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" [[package]] name = "owned_ttf_parser" @@ -1027,9 +1096,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.24" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612" dependencies = [ "unicode-xid", ] @@ -1066,9 +1135,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674" +checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" dependencies = [ "autocfg", "crossbeam-deque", @@ -1078,9 +1147,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.9.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a" +checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -1091,30 +1160,35 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.4" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ec8ca9416c5ea37062b502703cd7fcb207736bc294f6e0cf367ac6fc234570" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.4.3" +version = "1.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a" +checksum = "2a26af418b574bd56588335b3a3659a65725d4e636eb1016c2f9e3b38c7cc759" dependencies = [ "aho-corasick", "memchr", "regex-syntax", - "thread_local", ] [[package]] name = "regex-syntax" -version = "0.6.22" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + +[[package]] +name = "rustc-demangle" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581" +checksum = "dead70b0b5e03e9c814bcb6b01e03e68f7c57a80aa48c72ec92152ab3e818d49" [[package]] name = "rusttype" @@ -1155,18 +1229,18 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "serde" -version = "1.0.123" +version = "1.0.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae" +checksum = "f03b9878abf6d14e6779d3f24f07b2cfa90352cfec4acc5aab8f1ac7f146fae8" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.123" +version = "1.0.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31" +checksum = "a024926d3432516606328597e0f224a51355a493b49fdd67e9209187cbe55ecc" dependencies = [ "proc-macro2", "quote", @@ -1175,9 +1249,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.2" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590" [[package]] name = "smallvec" @@ -1187,18 +1261,18 @@ checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] name = "smithay-client-toolkit" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "316e13a3eb853ce7bf72ad3530dc186cb2005c57c521ef5f4ada5ee4eed74de6" +checksum = "4750c76fd5d3ac95fa3ed80fe667d6a3d8590a960e5b575b98eea93339a80b80" dependencies = [ "andrew", "bitflags", "calloop", - "dlib", + "dlib 0.4.2", "lazy_static", "log", "memmap2", - "nix", + "nix 0.18.0", "wayland-client", "wayland-cursor", "wayland-protocols", @@ -1228,9 +1302,9 @@ checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" [[package]] name = "structopt" -version = "0.3.21" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5277acd7ee46e63e5168a80734c9f6ee81b1367a7d8772a2d765df2a3705d28c" +checksum = "69b041cdcb67226aca307e6e7be44c8806423d83e018bd662360a93dabce4d71" dependencies = [ "clap", "lazy_static", @@ -1239,9 +1313,9 @@ dependencies = [ [[package]] name = "structopt-derive" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ba9cdfda491b814720b6b06e0cac513d922fc407582032e8706e9f137976f90" +checksum = "7813934aecf5f51a54775e00068c237de98489463968231a51746bbbc03f9c10" dependencies = [ "heck", "proc-macro-error", @@ -1252,9 +1326,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.60" +version = "1.0.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" +checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c" dependencies = [ "proc-macro2", "quote", @@ -1281,33 +1355,24 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.24" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" +checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.24" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" +checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745" dependencies = [ "proc-macro2", "quote", "syn", ] -[[package]] -name = "thread_local" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd" -dependencies = [ - "once_cell", -] - [[package]] name = "tiff" version = "0.6.1" @@ -1315,7 +1380,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a53f4706d65497df0c4349241deddf35f84cee19c87ed86ea8ca590f4464437" dependencies = [ "jpeg-decoder", - "miniz_oxide 0.4.3", + "miniz_oxide 0.4.4", "weezl", ] @@ -1336,9 +1401,9 @@ checksum = "3e5d7cd7ab3e47dda6e56542f4bbf3824c15234958c6e1bd6aaa347e93499fdc" [[package]] name = "unicode-segmentation" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" [[package]] name = "unicode-width" @@ -1348,9 +1413,9 @@ checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" [[package]] name = "unicode-xid" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "ve-shader-reflect" @@ -1394,19 +1459,9 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "version_check" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" - -[[package]] -name = "vk-mem" -version = "0.2.3" -source = "git+https://github.com/gwihlidal/vk-mem-rs#ec2772294fcded340d663487503fd356b70bc3a3" -dependencies = [ - "ash", - "bitflags", - "cc", -] +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" [[package]] name = "vulkan_engine" @@ -1417,20 +1472,20 @@ dependencies = [ "ash-window", "crystal", "env_logger", + "gpu-allocator", "image", "log", "thiserror", "ve-shader-reflect", "ve_format", - "vk-mem", "winit", ] [[package]] name = "walkdir" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" dependencies = [ "same-file", "winapi 0.3.9", @@ -1439,9 +1494,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.72" +version = "0.2.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fe8f61dba8e5d645a4d8132dc7a0a66861ed5e1045d2c0ed940fab33bac0fbe" +checksum = "b608ecc8f4198fe8680e2ed18eccab5f0cd4caaf3d83516fa5fb2e927fda2586" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -1449,9 +1504,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.72" +version = "0.2.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046ceba58ff062da072c7cb4ba5b22a37f00a302483f7e2a6cdc18fedbdc1fd3" +checksum = "580aa3a91a63d23aac5b6b267e2d13cb4f363e31dce6c352fca4752ae12e479f" dependencies = [ "bumpalo", "lazy_static", @@ -1464,9 +1519,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.72" +version = "0.2.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9aa01d36cda046f797c57959ff5f3c615c9cc63997a8d545831ec7976819b" +checksum = "171ebf0ed9e1458810dfcb31f2e766ad6b3a89dbda42d8901f2b268277e5f09c" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1474,9 +1529,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.72" +version = "0.2.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96eb45c1b2ee33545a813a92dbb53856418bf7eb54ab34f7f7ff1448a5b3735d" +checksum = "6c2657dd393f03aa2a659c25c6ae18a13a4048cebd220e147933ea837efc589f" dependencies = [ "proc-macro2", "quote", @@ -1487,20 +1542,20 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.72" +version = "0.2.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7148f4696fb4960a346eaa60bbfb42a1ac4ebba21f750f75fc1375b098d5ffa" +checksum = "2e0c4a743a309662d45f4ede961d7afa4ba4131a59a639f29b0069c3798bbcc2" [[package]] name = "wayland-client" -version = "0.28.3" +version = "0.28.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdbdbe01d03b2267809f3ed99495b37395387fde789e0f2ebb78e8b43f75b6d7" +checksum = "e3ab332350e502f159382201394a78e3cc12d0f04db863429260164ea40e0355" dependencies = [ "bitflags", "downcast-rs", "libc", - "nix", + "nix 0.20.0", "scoped-tls", "wayland-commons", "wayland-scanner", @@ -1509,11 +1564,11 @@ dependencies = [ [[package]] name = "wayland-commons" -version = "0.28.3" +version = "0.28.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "480450f76717edd64ad04a4426280d737fc3d10a236b982df7b1aee19f0e2d56" +checksum = "a21817947c7011bbd0a27e11b17b337bfd022e8544b071a2641232047966fbda" dependencies = [ - "nix", + "nix 0.20.0", "once_cell", "smallvec", "wayland-sys", @@ -1521,20 +1576,20 @@ dependencies = [ [[package]] name = "wayland-cursor" -version = "0.28.3" +version = "0.28.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6eb122c160223a7660feeaf949d0100281d1279acaaed3720eb3c9894496e5f" +checksum = "be610084edd1586d45e7bdd275fe345c7c1873598caa464c4fb835dee70fa65a" dependencies = [ - "nix", + "nix 0.20.0", "wayland-client", "xcursor", ] [[package]] name = "wayland-protocols" -version = "0.28.3" +version = "0.28.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "319a82b4d3054dd25acc32d9aee0f84fa95b63bc983fffe4703b6b8d47e01a30" +checksum = "286620ea4d803bacf61fa087a4242ee316693099ee5a140796aaba02b29f861f" dependencies = [ "bitflags", "wayland-client", @@ -1544,9 +1599,9 @@ dependencies = [ [[package]] name = "wayland-scanner" -version = "0.28.3" +version = "0.28.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7010ba5767b3fcd350decc59055390b4ebe6bd1b9279a9feb1f1888987f1133d" +checksum = "ce923eb2deb61de332d1f356ec7b6bf37094dc5573952e1c8936db03b54c03f1" dependencies = [ "proc-macro2", "quote", @@ -1555,20 +1610,20 @@ dependencies = [ [[package]] name = "wayland-sys" -version = "0.28.3" +version = "0.28.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6793834e0c35d11fd96a97297abe03d37be627e1847da52e17d7e0e3b51cc099" +checksum = "d841fca9aed7febf9bed2e9796c49bf58d4152ceda8ac949ebe00868d8f0feb8" dependencies = [ - "dlib", + "dlib 0.5.0", "lazy_static", "pkg-config", ] [[package]] name = "weezl" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a32b378380f4e9869b22f0b5177c68a5519f03b3454fde0b291455ddbae266c" +checksum = "d8b77fdfd5a253be4ab714e4ffa3c49caf146b4de743e97510c0656cf90f1e8e" [[package]] name = "winapi" @@ -1683,6 +1738,6 @@ checksum = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57" [[package]] name = "xml-rs" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a" +checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" diff --git a/Cargo.toml b/Cargo.toml index d1f4bea..adaf8b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,9 +20,9 @@ env_logger = "0.8.2" log = "0.4.14" thiserror = "1.0.23" anyhow = "1.0.40" -ash = "0.31.0" -ash-window = "0.5.0" -vk-mem = { git = "https://github.com/gwihlidal/vk-mem-rs", version = "0.2.3" } +ash = "0.33.0" +ash-window = "0.7.0" +gpu-allocator = { git="https://github.com/Traverse-Research/gpu-allocator" } winit = "0.24.0" image = "0.23.13" crystal = { path = "crystal" } diff --git a/crystal/src/matrix.rs b/crystal/src/matrix.rs index 3a90d03..701b7ae 100644 --- a/crystal/src/matrix.rs +++ b/crystal/src/matrix.rs @@ -22,8 +22,9 @@ impl Matrix { (R, C) } + #[allow(clippy::uninit_assumed_init)] pub(crate) unsafe fn uninitialized() -> Matrix { - Self::from_data(std::mem::MaybeUninit::uninit().assume_init()) + Self::from_data(std::mem::MaybeUninit::uninit().assume_init()) // TODO: undefined behavior } pub fn get(&self, index: I) -> Option<&I::Output> diff --git a/examples/brdf/main.rs b/examples/brdf/main.rs index 49b507d..0b46b67 100644 --- a/examples/brdf/main.rs +++ b/examples/brdf/main.rs @@ -107,6 +107,11 @@ fn setup(engine: &mut Engine) { mesh_data_sphere_smooth, (*engine.vulkan_manager.allocator).clone(), &mut engine.vulkan_manager.uploader, + engine + .vulkan_manager + .rtx_data + .as_ref() + .map(|rtx_data| rtx_data.acc_ext.clone()), ) .unwrap(); diff --git a/examples/mesh/main.rs b/examples/mesh/main.rs index 6553106..346e4c1 100644 --- a/examples/mesh/main.rs +++ b/examples/mesh/main.rs @@ -113,6 +113,11 @@ fn setup(engine: &mut Engine) { mesh_data, (*engine.vulkan_manager.allocator).clone(), &mut engine.vulkan_manager.uploader, + engine + .vulkan_manager + .rtx_data + .as_ref() + .map(|rtx_data| rtx_data.acc_ext.clone()), ) .expect("Error baking mesh!"); diff --git a/examples/minimal/main.rs b/examples/minimal/main.rs index 2bf7008..eeaa29d 100644 --- a/examples/minimal/main.rs +++ b/examples/minimal/main.rs @@ -119,6 +119,11 @@ fn setup(engine: &mut Engine) { mesh_data, (*engine.vulkan_manager.allocator).clone(), &mut engine.vulkan_manager.uploader, + engine + .vulkan_manager + .rtx_data + .as_ref() + .map(|rtx_data| rtx_data.acc_ext.clone()), ) .unwrap(); diff --git a/examples/textured_material/main.rs b/examples/textured_material/main.rs index 39f4d2c..0965fc1 100644 --- a/examples/textured_material/main.rs +++ b/examples/textured_material/main.rs @@ -108,8 +108,7 @@ fn setup(engine: &mut Engine) { (*engine.vulkan_manager.allocator).clone(), &mut engine.vulkan_manager.uploader, engine.vulkan_manager.device.clone(), - ) - .unwrap(); + ); let material0 = pipeline.create_material().unwrap(); material0.set_float("metallic", 0.0).unwrap(); @@ -147,6 +146,11 @@ fn setup(engine: &mut Engine) { mesh_data, (*engine.vulkan_manager.allocator).clone(), &mut engine.vulkan_manager.uploader, + engine + .vulkan_manager + .rtx_data + .as_ref() + .map(|rtx_data| rtx_data.acc_ext.clone()), ) .unwrap(); diff --git a/shaders/brdf.hlslh b/shaders/brdf.hlslh new file mode 100644 index 0000000..e5876a7 --- /dev/null +++ b/shaders/brdf.hlslh @@ -0,0 +1,63 @@ + + +static const float PI = 3.1415926535897932384626433832795; + +// Schlicks approximation (approximates r_0 = ((n_1 - n_2)/(n_1 + n_2))^2) +float3 schlick(float3 r0, float cosTheta) { + // we could use pow, but then it do all the float checks - which we don't need + return r0 + (1.0 - r0) * (1.0 - cosTheta) * (1.0 - cosTheta) * (1.0 - cosTheta) * (1.0 - cosTheta) * (1.0 - cosTheta); +} + +// normal distribution function: Trowbridge-Reitz GGX +float distributionGGX(float3 normal, float3 halfVector, float roughness) { + float a = roughness * roughness; // rougness apparently looks more "correct", when beeing squared (according to Disney) + float a2 = a * a; + float nDotH = max(dot(normal, halfVector), 0.0); + float nDotH2 = nDotH * nDotH; + + float denom = (nDotH2 * (a2 - 1.0) + 1.0); + denom = PI * denom * denom; + + return a2 / denom; +} + +// geometry function: Schlick-GGX +float geometrySchlickGGX(float vec, float roughness) { + float r = roughness + 1.0; + float k = (r * r) / 8.0; + + float denom = vec * (1.0 - k) + k; + + return vec / denom; +} + +// approximate geometry: account for view dir and light dir: Smith's method +float geometrySmith(float nDotV, float nDotL, float roughness) { + return geometrySchlickGGX(nDotL, roughness) * geometrySchlickGGX(nDotV, roughness); +} + +float3 computeRadiance(float3 irradiance, float3 lightDirection, float3 normal, float3 cameraDirection, float3 surfaceColor, float metallic, float roughness) { + // utils + float3 halfVector = normalize(cameraDirection + lightDirection); + float nDotH = max(dot(normal, halfVector), 0.0); + float nDotL = max(dot(normal, lightDirection), 0.0); + float hDotV = max(dot(halfVector, cameraDirection), 0.0); + float nDotV = max(dot(normal, cameraDirection), 0.0); + + float3 f0 = lerp(float3(0.04), surfaceColor, float3(metallic)); // base relectivity: use 0.04 for non-metallic/dialectic materials else use the surface color + float3 f = schlick(f0, hDotV); + + float ndf = distributionGGX(normal, halfVector, roughness); + float geometry = geometrySmith(nDotV, nDotL, roughness); + + // Cook-Torrance BRDF + float3 numerator = ndf * geometry * f; + float denominator = 4.0 * nDotV * nDotL; + float3 specular = numerator / max(denominator, 0.001); + + float3 kS = f; // energy of light that gets reflected + float3 kD = float3(1.0) - kS; // remaining light that gets refracted + kD *= 1.0 - metallic; // metalls don't refract, so set it to 0 if it's a metal + + return (kD * surfaceColor / PI + specular) * irradiance * nDotL; +} diff --git a/shaders/build.sh b/shaders/build.sh new file mode 100644 index 0000000..3f2001c --- /dev/null +++ b/shaders/build.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +for src in *.hlsl; do + echo Compiling Vulkan HLSL shader $src + glslc.exe --target-env=vulkan1.2 -fauto-combined-image-sampler -fshader-stage=vert -fentry-point=vert $src -o ../assets/shaders/$(basename $src .hlsl)-vert.spv + glslc.exe --target-env=vulkan1.2 -fauto-combined-image-sampler -fshader-stage=frag -fentry-point=frag $src -o ../assets/shaders/$(basename $src .hlsl)-frag.spv +done + +for src in *.rgen.glsl; do + [ -f "$src" ] || continue + echo Compiling Raygen shader $src + glslc.exe --target-env=vulkan1.2 -fshader-stage=rgen $src -o ../assets/shaders/$(basename $src .glsl).spv +done + +for src in *.rchit.glsl; do + [ -f "$src" ] || continue + echo Compiling Ray closest-hit shader $src + glslc.exe --target-env=vulkan1.2 -fshader-stage=rchit $src -o ../assets/shaders/$(basename $src .glsl).spv +done + +for src in *.rmiss.glsl; do + [ -f "$src" ] || continue + echo Compiling Ray miss shader $src + glslc.exe --target-env=vulkan1.2 -fshader-stage=rmiss $src -o ../assets/shaders/$(basename $src .glsl).spv +done diff --git a/shaders/common.hlslh b/shaders/common.hlslh new file mode 100644 index 0000000..cd6686f --- /dev/null +++ b/shaders/common.hlslh @@ -0,0 +1,10 @@ + +struct Cam { + float4x4 viewMatrix; + float4x4 projMatrix; + float4x4 invViewMatrix; + float4x4 invProjMatrix; + float3 position; +}; + +#define CAM_BINDING [[vk::binding(0, 0)]] diff --git a/shaders/deferred_directional_brdf.hlsl b/shaders/deferred_directional_brdf.hlsl new file mode 100644 index 0000000..6a571a3 --- /dev/null +++ b/shaders/deferred_directional_brdf.hlsl @@ -0,0 +1,40 @@ +#include "resolve.hlslh" +#include "brdf.hlslh" + +struct Frag { + float4 color : SV_TARGET0; +}; + +DEFAULT_VERTEX_SHADER + +GBUF0_BINDING SubpassInput in_AlbedoRoughness; +GBUF1_BINDING SubpassInput in_NormalMetallic; +GBUF_DEPTH_BINDING SubpassInput in_Depth; + +CAM_BINDING ConstantBuffer u_Cam; +LIGHT_BINDING ConstantBuffer u_Light; + +Frag frag(V2F fIn) { + Frag res; + + float4 albedoRoughness = in_AlbedoRoughness.SubpassLoad(); + float4 normalMetallic = in_NormalMetallic.SubpassLoad(); + float depth = in_Depth.SubpassLoad().r; + + float3 albedo = albedoRoughness.rgb; + float roughness = albedoRoughness.a; + float3 worldNormal = normalize(normalMetallic.rgb); + float metallic = normalMetallic.a; + + CALC_WORLD_POS(fIn.uv, depth, u_Cam.invProjMatrix, u_Cam.invViewMatrix); + + float3 dirToCam = normalize(u_Cam.position - worldPos); + + float3 dirToLight = u_Light.directionToLight.xyz; + float3 irradiance = u_Light.irradiance.rgb; + + float3 radiance = computeRadiance(irradiance, normalize(dirToLight), worldNormal, dirToCam, albedo, metallic, roughness); + res.color = float4(radiance, 1.0); + + return res; +} diff --git a/shaders/deferred_point_brdf.hlsl b/shaders/deferred_point_brdf.hlsl new file mode 100644 index 0000000..2cd249a --- /dev/null +++ b/shaders/deferred_point_brdf.hlsl @@ -0,0 +1,41 @@ +#include "resolve.hlslh" +#include "brdf.hlslh" + +struct Frag { + float4 color : SV_TARGET0; +}; + +DEFAULT_VERTEX_SHADER + +GBUF0_BINDING SubpassInput in_AlbedoRoughness; +GBUF1_BINDING SubpassInput in_NormalMetallic; +GBUF_DEPTH_BINDING SubpassInput in_Depth; + +CAM_BINDING ConstantBuffer u_Cam; +LIGHT_BINDING ConstantBuffer u_Light; + +Frag frag(V2F fIn) { + Frag res; + + float4 albedoRoughness = in_AlbedoRoughness.SubpassLoad(); + float4 normalMetallic = in_NormalMetallic.SubpassLoad(); + float depth = in_Depth.SubpassLoad().r; + + float3 albedo = albedoRoughness.rgb; + float roughness = albedoRoughness.a; + float3 worldNormal = normalize(normalMetallic.rgb); + float metallic = normalMetallic.a; + + CALC_WORLD_POS(fIn.uv, depth, u_Cam.invProjMatrix, u_Cam.invViewMatrix); + + float3 dirToCam = normalize(u_Cam.position - worldPos); + + float3 dirToLight = normalize(u_Light.position.xyz - worldPos); + float d = length(worldPos - u_Light.position); + float3 irradiance = u_Light.luminousFlux.rgb / (4.0 * PI * d * d); + + float3 radiance = computeRadiance(irradiance, dirToLight, worldNormal, dirToCam, albedo, metallic, roughness); + + res.color = float4(radiance, 1.0); + return res; +} diff --git a/shaders/deferred_unlit.hlsl b/shaders/deferred_unlit.hlsl new file mode 100644 index 0000000..9605509 --- /dev/null +++ b/shaders/deferred_unlit.hlsl @@ -0,0 +1,25 @@ +#include "resolve.hlslh" + +struct Frag { + float4 color : SV_TARGET0; +}; + +CAM_BINDING ConstantBuffer u_Cam; +GBUF0_BINDING SubpassInput in_AlbedoRoughness; +GBUF1_BINDING SubpassInput in_NormalMetallic; +GBUF_DEPTH_BINDING SubpassInput in_Depth; + +DEFAULT_VERTEX_SHADER + +Frag frag(V2F fIn) { + Frag res; + + float4 albedoRoughness = in_AlbedoRoughness.SubpassLoad(); + float4 normalMetallic = in_NormalMetallic.SubpassLoad(); + float depth = in_Depth.SubpassLoad().r; + + float3 albedo = albedoRoughness.rgb; + res.color = float4(albedo, 1.0); + + return res; +} diff --git a/shaders/gpass.hlslh b/shaders/gpass.hlslh new file mode 100644 index 0000000..54ec32a --- /dev/null +++ b/shaders/gpass.hlslh @@ -0,0 +1,18 @@ + +#include "common.hlslh" + +struct Vert { + float3 position; + float3 color; + float3 normal; + float2 uv; +}; + +struct Transform { + float4x4 modelMatrix; + float4x4 invModelMatrix; +}; + +#define TRANSFORM_BINDING [[vk::push_constant]] + +#define MATERIAL_BINDING(bind) [[vk::binding(bind, 1)]] diff --git a/shaders/material_albedo_tex.hlsl b/shaders/material_albedo_tex.hlsl new file mode 100644 index 0000000..65e301b --- /dev/null +++ b/shaders/material_albedo_tex.hlsl @@ -0,0 +1,46 @@ +#include "gpass.hlslh" + +CAM_BINDING ConstantBuffer u_Cam; +TRANSFORM_BINDING ConstantBuffer u_Transform; + +struct V2F { + float4 position : SV_POSITION; + float3 worldNormal; + float2 uv; +}; + +struct Frag { + float4 albedoRoughness : SV_TARGET0; + float4 normalMetallic : SV_TARGET1; +}; + +struct MaterialData { + float metallic; + float roughness; +}; + +MATERIAL_BINDING(0) ConstantBuffer u_Material; +MATERIAL_BINDING(1) Texture2D u_AlbedoTex; + +SamplerState s; + +V2F vert(Vert vIn) { + V2F vOut; + + vOut.position = float4(vIn.position, 1.0) * u_Transform.modelMatrix * u_Cam.viewMatrix * u_Cam.projMatrix; + vOut.worldNormal = (float4(vIn.normal, 0.0) * transpose(u_Transform.invModelMatrix)).xyz; + vOut.uv = vIn.uv; + + return vOut; +} + +Frag frag(V2F fIn) { + Frag fOut; + + float3 albedo = u_AlbedoTex.Sample(s, fIn.uv).rgb; + + fOut.albedoRoughness = float4(albedo, u_Material.roughness); + fOut.normalMetallic = float4(fIn.worldNormal, u_Material.metallic); + + return fOut; +} diff --git a/shaders/material_solid_color.hlsl b/shaders/material_solid_color.hlsl new file mode 100644 index 0000000..136a69b --- /dev/null +++ b/shaders/material_solid_color.hlsl @@ -0,0 +1,40 @@ +#include "gpass.hlslh" + +CAM_BINDING ConstantBuffer u_Cam; +TRANSFORM_BINDING ConstantBuffer u_Transform; + +struct V2F { + float4 position : SV_POSITION; + float3 worldNormal; +}; + +struct Frag { + float4 albedoRoughness : SV_TARGET0; + float4 normalMetallic : SV_TARGET1; +}; + +struct MaterialData { + float4 albedo; + float metallic; + float roughness; +}; + +MATERIAL_BINDING(0) ConstantBuffer u_Material; + +V2F vert(Vert vIn) { + V2F vOut; + + vOut.position = float4(vIn.position, 1.0) * u_Transform.modelMatrix * u_Cam.viewMatrix * u_Cam.projMatrix; + vOut.worldNormal = (float4(vIn.normal, 0.0) * transpose(u_Transform.invModelMatrix)).xyz; + + return vOut; +} + +Frag frag(V2F fIn) { + Frag fOut; + + fOut.albedoRoughness = float4(u_Material.albedo.rgb, u_Material.roughness); + fOut.normalMetallic = float4(fIn.worldNormal, u_Material.metallic); + + return fOut; +} diff --git a/shaders/pp.hlslh b/shaders/pp.hlslh new file mode 100644 index 0000000..eb61512 --- /dev/null +++ b/shaders/pp.hlslh @@ -0,0 +1,38 @@ +#include "common.hlslh" + +#define DEFAULT_VERTEX_SHADER \ + static const float3 g_Vertices[] = { \ + float3(-1.0, -1.0, 0.0), \ + float3(1.0, 1.0, 0.0), \ + float3(-1.0, 1.0, 0.0), \ + \ + float3(-1.0, -1.0, 0.0), \ + float3(1.0, -1.0, 0.0), \ + float3(1.0, 1.0, 0.0), \ + }; \ + \ + static const float2 g_UVs[] = { \ + float2(0.0, 1.0), \ + float2(1.0, 0.0), \ + float2(0.0, 0.0), \ + \ + float2(0.0, 1.0), \ + float2(1.0, 1.0), \ + float2(1.0, 0.0), \ + }; \ + \ + struct V2F { \ + float4 position : SV_POSITION; \ + float2 uv; \ + }; \ + \ + V2F vert(int index : SV_VERTEXID) { \ + V2F res; \ + \ + res.position = float4(g_Vertices[index], 1.0); \ + res.uv = g_UVs[index]; \ + \ + return res; \ + } + +#define SRC_IMAGE_BINDING [[vk::binding(0, 0)]] diff --git a/shaders/resolve.hlslh b/shaders/resolve.hlslh new file mode 100644 index 0000000..b7044a3 --- /dev/null +++ b/shaders/resolve.hlslh @@ -0,0 +1,61 @@ +#include "common.hlslh" + +#define DEFAULT_VERTEX_SHADER \ + static const float3 g_Vertices[] = { \ + float3(-1.0, -1.0, 0.0), \ + float3(1.0, 1.0, 0.0), \ + float3(-1.0, 1.0, 0.0), \ + \ + float3(-1.0, -1.0, 0.0), \ + float3(1.0, -1.0, 0.0), \ + float3(1.0, 1.0, 0.0), \ + }; \ + \ + static const float2 g_UVs[] = { \ + float2(-1.0, -1.0), \ + float2(1.0, 1.0), \ + float2(-1.0, 1.0), \ + \ + float2(-1.0, -1.0), \ + float2(1.0, -1.0), \ + float2(1.0, 1.0), \ + }; \ + \ + struct V2F { \ + float4 position : SV_POSITION; \ + float2 uv; \ + }; \ + \ + V2F vert(int index : SV_VERTEXID) { \ + V2F res; \ + \ + res.position = float4(g_Vertices[index], 1.0); \ + res.uv = g_UVs[index]; \ + \ + return res; \ + } + +#define GBUF0_BINDING [[vk::binding(1, 0)]] [[vk::input_attachment_index(0)]] +#define GBUF1_BINDING [[vk::binding(2, 0)]] [[vk::input_attachment_index(1)]] +#define GBUF_DEPTH_BINDING [[vk::binding(3, 0)]] [[vk::input_attachment_index(2)]] + +#define CALC_WORLD_POS(uv, depth, invProj, invView) \ + float3 worldPos; \ + { \ + float4 clipPos = float4((uv).xy, (depth), 1.0); \ + float4 viewPos = clipPos * invProj; \ + viewPos /= viewPos.w; \ + worldPos = (viewPos * invView).xyz; \ + } + +struct PointLight { + float4 position; + float4 luminousFlux; +}; + +struct DirLight { + float4 directionToLight; + float4 irradiance; +}; + +#define LIGHT_BINDING [[vk::push_constant]] diff --git a/shaders/rtx_test.rchit.glsl b/shaders/rtx_test.rchit.glsl new file mode 100644 index 0000000..26f2c90 --- /dev/null +++ b/shaders/rtx_test.rchit.glsl @@ -0,0 +1,13 @@ +#version 460 +#extension GL_EXT_ray_tracing : enable +#extension GL_EXT_buffer_reference : enable +#extension GL_EXT_scalar_block_layout : enable + +layout(location=0) rayPayloadInEXT vec3 hitColor; + +hitAttributeEXT vec3 attribs; + +void main() { + const vec3 baryCoords = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y); + hitColor = baryCoords; +} diff --git a/shaders/rtx_test.rgen.glsl b/shaders/rtx_test.rgen.glsl new file mode 100644 index 0000000..2d501cc --- /dev/null +++ b/shaders/rtx_test.rgen.glsl @@ -0,0 +1,29 @@ +#version 460 +#extension GL_EXT_ray_tracing : enable + +layout(set=0, binding=0) uniform accelerationStructureEXT u_Scene; +layout(set=0, binding=1, rgba16f) uniform image2D u_Image; + +layout(set=0, binding=2) uniform Cam { + mat4 viewMatrix; + mat4 projMatrix; + mat4 invViewMatrix; + mat4 invProjMatrix; + vec3 position; +} u_Camera; + +layout(location=0) rayPayloadEXT vec3 hitColor; + +void main() { + const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + vec2(0.5, 0.5); + const vec2 clipPos = pixelCenter / vec2(gl_LaunchSizeEXT.xy) * 2.0 - 1.0; + + vec3 origin = u_Camera.position; + vec3 direction = normalize(u_Camera.invProjMatrix * vec4(clipPos, 1, 1)).xyz; + direction = (u_Camera.invViewMatrix * vec4(direction, 0.0)).xyz; + + hitColor = vec3(0, 0, 0); + traceRayEXT(u_Scene, gl_RayFlagsOpaqueEXT, 0xFF, 0, 0, 0, origin, 0.001, direction, 1000.0, 0); + + imageStore(u_Image, ivec2(gl_LaunchIDEXT.xy), vec4(hitColor, 1.0)); +} diff --git a/shaders/tone_map.hlsl b/shaders/tone_map.hlsl new file mode 100644 index 0000000..4b25c0e --- /dev/null +++ b/shaders/tone_map.hlsl @@ -0,0 +1,21 @@ +#include "pp.hlslh" + +struct Frag { + float4 color : SV_TARGET0; +}; + +DEFAULT_VERTEX_SHADER + +SRC_IMAGE_BINDING Texture2D u_SrcImage; +SamplerState s; + +Frag frag(V2F fIn) { + Frag res; + + float3 src = u_SrcImage.Sample(s, fIn.uv).rgb; + + float3 toneMapped = src / (float3(1.0) + src); + res.color = float4(toneMapped, 1.0); + + return res; +} diff --git a/shaders/vertex_unlit.hlsl b/shaders/vertex_unlit.hlsl new file mode 100644 index 0000000..453764c --- /dev/null +++ b/shaders/vertex_unlit.hlsl @@ -0,0 +1,30 @@ +#include "gpass.hlslh" + +struct V2F { + float4 position : SV_POSITION; + float3 vertexColor; +}; + +struct Frag { + float4 vertexColor : SV_TARGET0; +}; + +CAM_BINDING ConstantBuffer u_Cam; +TRANSFORM_BINDING ConstantBuffer u_Transform; + +V2F vert(Vert vIn) { + V2F res; + + res.position = float4(vIn.position, 1.0) * u_Transform.modelMatrix * u_Cam.viewMatrix * u_Cam.projMatrix; + res.vertexColor = vIn.color; + + return res; +} + +Frag frag(V2F fIn) { + Frag res; + + res.vertexColor = float4(fIn.vertexColor, 0.0); + + return res; +} diff --git a/src/assets/shader.rs b/src/assets/shader.rs index 93e3293..f0b91a5 100644 --- a/src/assets/shader.rs +++ b/src/assets/shader.rs @@ -31,7 +31,16 @@ pub fn load(name: &str, kind: ShaderKind, code_ref: &mut Vec) -> vk::Shader get_file_as_bytes(file, code_ref); - *vk::ShaderModuleCreateInfo::builder().code(&code_ref) + *vk::ShaderModuleCreateInfo::builder().code(code_ref) +} + +pub fn load_single(name: String, code_ref: &mut Vec) -> vk::ShaderModuleCreateInfo { + let folder = Path::new(FOLDER); + let file = folder.join(name); + + get_file_as_bytes(file, code_ref); + + *vk::ShaderModuleCreateInfo::builder().code(code_ref) } fn get_file_as_bytes(file: PathBuf, dst: &mut Vec) { diff --git a/src/core/camera.rs b/src/core/camera.rs index 0f2f3d0..a0d3479 100644 --- a/src/core/camera.rs +++ b/src/core/camera.rs @@ -3,7 +3,10 @@ use std::time::Instant; use crystal::prelude::*; use winit::event::VirtualKeyCode; -use crate::vulkan::buffer::{self, MutableBuffer}; +use crate::vulkan::{ + allocator::Allocator, + buffer::{self, MutableBuffer}, +}; use super::input::Input; @@ -35,7 +38,7 @@ pub struct Camera { impl Camera { pub fn update_buffer( &self, - allocator: &vk_mem::Allocator, + allocator: &Allocator, buffer: &mut buffer::PerFrameUniformBuffer, current_frame_index: u8, ) { @@ -46,9 +49,7 @@ impl Camera { inv_projection_matrix: self.inv_projection_matrix.into(), pos: self.position.into(), }; - buffer - .set_data(allocator, &cam_data, current_frame_index) - .unwrap(); + buffer.set_data(allocator, &cam_data, current_frame_index); } fn update_projection_matrix(&mut self) { diff --git a/src/scene/material/material_compiler.rs b/src/scene/material/material_compiler.rs index 9f2525a..e410165 100644 --- a/src/scene/material/material_compiler.rs +++ b/src/scene/material/material_compiler.rs @@ -1,6 +1,7 @@ -use ash::{version::DeviceV1_0, vk}; +use ash::vk; +use gpu_allocator::SubAllocation; -use crate::vulkan::descriptor_manager::DescriptorData; +use crate::vulkan::{allocator::Allocator, descriptor_manager::DescriptorData}; pub fn compile_descriptor_set_layout( device: &ash::Device, @@ -56,8 +57,8 @@ pub fn compile_pipeline_layout( pub fn compile_resources( data: &[DescriptorData], - allocator: &vk_mem::Allocator, -) -> Result<(Vec, Vec), vk_mem::Error> { + allocator: &Allocator, +) -> (Vec, Vec) { let mut resources = Vec::with_capacity(data.len()); let mut allocations = Vec::with_capacity(data.len()); @@ -68,16 +69,11 @@ pub fn compile_resources( offset: _, size, } => { - let buffer_info = vk::BufferCreateInfo::builder() - .usage(vk::BufferUsageFlags::UNIFORM_BUFFER) - .size(*size) - .sharing_mode(vk::SharingMode::EXCLUSIVE) - .build(); - let alloc_info = vk_mem::AllocationCreateInfo { - usage: vk_mem::MemoryUsage::CpuToGpu, - ..Default::default() - }; - let (buffer, alloc, _) = allocator.create_buffer(&buffer_info, &alloc_info)?; + let (buffer, alloc) = allocator.create_buffer( + *size, + vk::BufferUsageFlags::UNIFORM_BUFFER, + gpu_allocator::MemoryLocation::CpuToGpu, + ); allocations.push(alloc); resources.push(DescriptorData::UniformBuffer { @@ -97,5 +93,5 @@ pub fn compile_resources( } } - Ok((resources, allocations)) + (resources, allocations) } diff --git a/src/scene/material/mod.rs b/src/scene/material/mod.rs index 5078b79..47267c2 100644 --- a/src/scene/material/mod.rs +++ b/src/scene/material/mod.rs @@ -1,8 +1,10 @@ -use ash::{version::DeviceV1_0, vk}; +use ash::vk; use crystal::prelude::{Vec2, Vec3, Vec4}; +use gpu_allocator::SubAllocation; use std::{cell::RefCell, collections::HashMap, mem::size_of, rc::Rc}; use crate::vulkan::{ + allocator::Allocator, descriptor_manager::DescriptorData, error::{GraphicsError, GraphicsResult}, lighting_pipeline::LightingPipeline, @@ -43,7 +45,7 @@ enum MaterialProperty { /// This means, multiple variables with the same name in different uniform blocks will clash in the material properties. pub struct MaterialPipeline { device: Rc, - allocator: Rc, + allocator: Rc, pipeline: vk::Pipeline, pipeline_wireframe: vk::Pipeline, pipeline_layout: vk::PipelineLayout, @@ -66,7 +68,7 @@ impl MaterialPipeline { /// - `lighing_pipeline`: The [LightingPipeline] which will be used in the Deferred Resolve Pass for Materials created with this MaterialPipeline pub fn new( device: Rc, - allocator: Rc, + allocator: Rc, shader: &str, frame_data_layout: vk::DescriptorSetLayout, renderpass: vk::RenderPass, @@ -234,7 +236,7 @@ impl MaterialPipeline { /// Creates a new [`Material`] from the given MaterialPipeline. pub fn create_material(self: &Rc) -> GraphicsResult> { let (resources, allocations) = - material_compiler::compile_resources(&self.resource_infos, self.allocator.as_ref())?; + material_compiler::compile_resources(&self.resource_infos, self.allocator.as_ref()); Ok(Rc::new(Material { pipeline: self.clone(), @@ -265,26 +267,17 @@ impl Drop for MaterialPipeline { pub struct Material { pipeline: Rc, resources: RefCell>, - allocations: Vec, + allocations: Vec, textures: RefCell>>, } impl Material { - fn set_uniform_property( - &self, - alloc: &vk_mem::Allocation, - offset: u64, - size: u64, - data: *const u8, - ) -> Result<(), vk_mem::Error> { - let map = self.pipeline.allocator.map_memory(alloc)?; + fn set_uniform_property(&self, alloc: &SubAllocation, offset: u64, size: u64, data: *const u8) { + let map = Allocator::get_ptr(alloc) as *mut u8; unsafe { map.offset(offset as isize) .copy_from_nonoverlapping(data, size as usize); } - self.pipeline.allocator.unmap_memory(alloc); - - Ok(()) } /// Sets a MaterialProperty of type float @@ -308,7 +301,7 @@ impl Material { *offset as u64, size_of::() as u64, &val as *const f32 as *const u8, - )?; + ); } _ => return Err(GraphicsError::InvalidMaterialPropertyType(name.to_owned())), } @@ -337,7 +330,7 @@ impl Material { *offset as u64, size_of::>() as u64, &val as *const Vec2 as *const u8, - )?; + ); } _ => return Err(GraphicsError::InvalidMaterialPropertyType(name.to_owned())), } @@ -366,7 +359,7 @@ impl Material { *offset as u64, size_of::>() as u64, &val as *const Vec3 as *const u8, - )?; + ); } _ => return Err(GraphicsError::InvalidMaterialPropertyType(name.to_owned())), } @@ -395,7 +388,7 @@ impl Material { *offset as u64, size_of::>() as u64, &val as *const Vec4 as *const u8, - )?; + ); } _ => return Err(GraphicsError::InvalidMaterialPropertyType(name.to_owned())), } @@ -479,7 +472,7 @@ impl Drop for Material { } } for a in &self.allocations { - self.pipeline.allocator.free_memory(a); + self.pipeline.allocator.free(a); } } } diff --git a/src/scene/model/mesh.rs b/src/scene/model/mesh.rs index 292c731..b127969 100644 --- a/src/scene/model/mesh.rs +++ b/src/scene/model/mesh.rs @@ -1,16 +1,27 @@ use std::{mem::size_of, rc::Rc}; -use ash::vk; +use ash::{extensions::khr, vk}; +use gpu_allocator::SubAllocation; use ve_format::mesh::{Face, MeshData, Vertex}; -use crate::vulkan::uploader::Uploader; +use crate::vulkan::{allocator::Allocator, uploader::Uploader}; + +pub struct MeshRtxData { + pub acc_struct: vk::AccelerationStructureKHR, + pub buffer: vk::Buffer, + pub buffer_alloc: gpu_allocator::SubAllocation, + rtx_ext: Rc, +} + pub struct Mesh { - allocator: Rc, + allocator: Rc, pub vertex_buffer: vk::Buffer, - pub vertex_buffer_alloc: vk_mem::Allocation, + pub vertex_buffer_alloc: SubAllocation, pub index_buffer: vk::Buffer, - pub index_buffer_alloc: vk_mem::Allocation, + pub index_buffer_alloc: SubAllocation, pub submeshes: Vec<(u32, u32)>, + + pub rtx_data: Option, } impl Drop for Mesh { @@ -19,43 +30,49 @@ impl Drop for Mesh { .destroy_buffer(self.vertex_buffer, &self.vertex_buffer_alloc); self.allocator .destroy_buffer(self.index_buffer, &self.index_buffer_alloc); + + if let Some(rtx_data) = &self.rtx_data { + unsafe { + rtx_data + .rtx_ext + .destroy_acceleration_structure(rtx_data.acc_struct, None) + }; + self.allocator + .destroy_buffer(rtx_data.buffer, &rtx_data.buffer_alloc); + } } } impl Mesh { pub fn bake( mesh_data: MeshData, - allocator: Rc, + allocator: Rc, uploader: &mut Uploader, - ) -> Result, vk_mem::Error> { - let vertex_buffer_size = mesh_data.vertices.len() * size_of::(); - let vertex_buffer_info = vk::BufferCreateInfo::builder() - .sharing_mode(vk::SharingMode::EXCLUSIVE) - .size(vertex_buffer_size as u64) - .usage(vk::BufferUsageFlags::VERTEX_BUFFER | vk::BufferUsageFlags::TRANSFER_DST) - .build(); - let vertex_buffer_alloc_info = vk_mem::AllocationCreateInfo { - usage: vk_mem::MemoryUsage::GpuOnly, - ..Default::default() + rtx_ext: Option>, + ) -> Result, bool> { + let extra_flags = if rtx_ext.is_some() { + vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS + | vk::BufferUsageFlags::ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_KHR + } else { + vk::BufferUsageFlags::empty() }; - let (vertex_buffer, vertex_buffer_alloc, _) = - allocator.create_buffer(&vertex_buffer_info, &vertex_buffer_alloc_info)?; + + let vertex_buffer_size = mesh_data.vertices.len() * size_of::(); + let (vertex_buffer, vertex_buffer_alloc) = allocator.create_buffer( + vertex_buffer_size as u64, + vk::BufferUsageFlags::VERTEX_BUFFER | vk::BufferUsageFlags::TRANSFER_DST | extra_flags, + gpu_allocator::MemoryLocation::GpuOnly, + ); let mut index_buffer_size = 0u64; for sm in &mesh_data.submeshes { index_buffer_size += (sm.faces.len() * size_of::()) as u64; } - let index_buffer_info = vk::BufferCreateInfo::builder() - .sharing_mode(vk::SharingMode::EXCLUSIVE) - .size(index_buffer_size) - .usage(vk::BufferUsageFlags::INDEX_BUFFER | vk::BufferUsageFlags::TRANSFER_DST) - .build(); - let index_buffer_alloc_info = vk_mem::AllocationCreateInfo { - usage: vk_mem::MemoryUsage::GpuOnly, - ..Default::default() - }; - let (index_buffer, index_buffer_alloc, _) = - allocator.create_buffer(&index_buffer_info, &index_buffer_alloc_info)?; + let (index_buffer, index_buffer_alloc) = allocator.create_buffer( + index_buffer_size as u64, + vk::BufferUsageFlags::INDEX_BUFFER | vk::BufferUsageFlags::TRANSFER_DST | extra_flags, + gpu_allocator::MemoryLocation::GpuOnly, + ); uploader.enqueue_buffer_upload(vertex_buffer, 0, &mesh_data.vertices); @@ -72,6 +89,22 @@ impl Mesh { start_index += sm.faces.len() as u32 * 3; } + let rtx_data = rtx_ext.map(|rtx_ext| { + let (acc, acc_buf, acc_alloc) = uploader.enqueue_acc_struct_build( + rtx_ext.clone(), + vertex_buffer, + index_buffer, + &submeshes, + mesh_data.vertices.len() as u32, + ); + MeshRtxData { + acc_struct: acc, + buffer: acc_buf, + buffer_alloc: acc_alloc, + rtx_ext, + } + }); + Ok(Rc::new(Mesh { allocator, vertex_buffer, @@ -79,6 +112,8 @@ impl Mesh { index_buffer, index_buffer_alloc, submeshes, + + rtx_data, })) } } diff --git a/src/vulkan/allocator.rs b/src/vulkan/allocator.rs new file mode 100644 index 0000000..682d62d --- /dev/null +++ b/src/vulkan/allocator.rs @@ -0,0 +1,157 @@ +use std::{cell::RefCell, ffi::c_void, rc::Rc}; + +use ash::vk; +use gpu_allocator::{ + AllocationCreateDesc, AllocatorDebugSettings, MemoryLocation, VulkanAllocator, + VulkanAllocatorCreateDesc, +}; + +pub use gpu_allocator::SubAllocation; + +pub struct Allocator { + alloc: RefCell, + device: Rc, +} + +impl Allocator { + pub fn new( + instance: ash::Instance, + device: Rc, + physical_device: vk::PhysicalDevice, + buffer_device_address: bool, + ) -> Self { + let alloc = VulkanAllocator::new(&VulkanAllocatorCreateDesc { + instance, + device: (*device).clone(), + physical_device, + debug_settings: AllocatorDebugSettings { + log_memory_information: true, + log_leaks_on_shutdown: true, + store_stack_traces: false, + log_allocations: false, + log_frees: false, + log_stack_traces: false, + }, + buffer_device_address, + }); + + Self { + alloc: alloc.into(), + device, + } + } + + pub fn create_buffer( + &self, + size: vk::DeviceSize, + usage: vk::BufferUsageFlags, + location: MemoryLocation, + ) -> (vk::Buffer, SubAllocation) { + let buffer = unsafe { + self.device.create_buffer( + &vk::BufferCreateInfo::builder() + .size(size) + .usage(usage) + .sharing_mode(vk::SharingMode::EXCLUSIVE) + .build(), + None, + ) + } + .unwrap(); + + let req = unsafe { self.device.get_buffer_memory_requirements(buffer) }; + + let alloc = self + .alloc + .borrow_mut() + .allocate(&AllocationCreateDesc { + name: "buffer", + requirements: req, + location, + linear: true, + }) + .unwrap(); + + unsafe { + self.device + .bind_buffer_memory(buffer, alloc.memory(), alloc.offset()) + .unwrap(); + } + + (buffer, alloc) + } + + pub fn destroy_buffer(&self, buffer: vk::Buffer, alloc: &SubAllocation) { + self.alloc.borrow_mut().free(alloc.clone()).unwrap(); + unsafe { + self.device.destroy_buffer(buffer, None); + } + } + + pub fn create_image( + &self, + width: u32, + height: u32, + usage: vk::ImageUsageFlags, + format: vk::Format, + ) -> (vk::Image, SubAllocation) { + let image = unsafe { + self.device.create_image( + &vk::ImageCreateInfo::builder() + .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(usage) + .sharing_mode(vk::SharingMode::EXCLUSIVE) + .initial_layout(vk::ImageLayout::UNDEFINED) + .build(), + None, + ) + } + .unwrap(); + + let req = unsafe { self.device.get_image_memory_requirements(image) }; + + let alloc = self + .alloc + .borrow_mut() + .allocate(&AllocationCreateDesc { + name: "image", + requirements: req, + location: MemoryLocation::GpuOnly, + linear: false, + }) + .unwrap(); + + unsafe { + self.device + .bind_image_memory(image, alloc.memory(), alloc.offset()) + .unwrap(); + } + + (image, alloc) + } + + pub fn destroy_image(&self, image: vk::Image, alloc: &SubAllocation) { + self.alloc.borrow_mut().free(alloc.clone()).unwrap(); + unsafe { + self.device.destroy_image(image, None); + } + } + + pub fn free(&self, alloc: &SubAllocation) { + self.alloc.borrow_mut().free(alloc.clone()).unwrap(); + } + + pub fn get_ptr(alloc: &SubAllocation) -> *mut c_void { + alloc.mapped_ptr().unwrap().as_ptr() + } +} diff --git a/src/vulkan/buffer.rs b/src/vulkan/buffer.rs index f177929..3a6ea8d 100644 --- a/src/vulkan/buffer.rs +++ b/src/vulkan/buffer.rs @@ -1,6 +1,9 @@ use std::{mem, ops::Deref}; use ash::vk; +use gpu_allocator::{MemoryLocation, SubAllocation}; + +use super::allocator::Allocator; pub trait VulkanBuffer { fn get_size(&self) -> u64; @@ -9,21 +12,16 @@ pub trait VulkanBuffer { } pub trait MutableBuffer: VulkanBuffer { - fn set_data( - &mut self, - allocator: &vk_mem::Allocator, - data: &T, - current_frame_index: u8, - ) -> Result<(), vk_mem::error::Error>; + fn set_data(&mut self, allocator: &Allocator, data: &T, current_frame_index: u8); } pub trait ResizableBuffer: MutableBuffer { - fn resize(new_size: u64) -> Result<(), vk_mem::error::Error>; + fn resize(new_size: u64); } pub struct PerFrameUniformBuffer { buffer: vk::Buffer, - allocation: vk_mem::Allocation, + allocation: SubAllocation, data_size: u64, aligned_data_size: u64, mapping: *mut T, @@ -32,39 +30,32 @@ pub struct PerFrameUniformBuffer { impl PerFrameUniformBuffer { pub fn new( phys_props: &vk::PhysicalDeviceProperties, - allocator: &vk_mem::Allocator, + allocator: &Allocator, num_frames: u64, buffer_usage: vk::BufferUsageFlags, - ) -> Result { + ) -> Self { let alignment = phys_props.limits.min_uniform_buffer_offset_alignment; let data_size = mem::size_of::() as u64; let aligned_data_size = (data_size + alignment - 1) / alignment * alignment; - let buffer_info = vk::BufferCreateInfo::builder() - .size(aligned_data_size * num_frames) - .usage(buffer_usage) - .sharing_mode(vk::SharingMode::EXCLUSIVE) - .build(); - let alloc_info = vk_mem::AllocationCreateInfo { - usage: vk_mem::MemoryUsage::CpuToGpu, - ..Default::default() - }; - - let (buffer, allocation, _) = allocator.create_buffer(&buffer_info, &alloc_info)?; + let (buffer, allocation) = allocator.create_buffer( + aligned_data_size * num_frames, + buffer_usage, + gpu_allocator::MemoryLocation::CpuToGpu, + ); - let mapping = allocator.map_memory(&allocation)? as *mut T; + let mapping = Allocator::get_ptr(&allocation) as *mut T; - Ok(Self { + Self { buffer, allocation, data_size, aligned_data_size, mapping, - }) + } } - pub fn destroy(&self, allocator: &vk_mem::Allocator) { - allocator.unmap_memory(&self.allocation); + pub fn destroy(&self, allocator: &Allocator) { allocator.destroy_buffer(self.buffer, &self.allocation); } } @@ -84,107 +75,76 @@ impl VulkanBuffer for PerFrameUniformBuffer { } impl MutableBuffer for PerFrameUniformBuffer { - fn set_data( - &mut self, - _: &vk_mem::Allocator, - data: &T, - current_frame_index: u8, - ) -> Result<(), vk_mem::Error> { + fn set_data(&mut self, _: &Allocator, data: &T, current_frame_index: u8) { let offset = current_frame_index as u64 * self.aligned_data_size; unsafe { let ptr = (self.mapping as *mut u8).offset(offset as isize) as *mut T; ptr.copy_from_nonoverlapping(data, 1); } - - Ok(()) } } #[allow(dead_code)] pub struct BufferWrapper { pub buffer: vk::Buffer, - allocation: vk_mem::Allocation, - allocation_info: vk_mem::AllocationInfo, + allocation: SubAllocation, capacity: u64, size: u64, buffer_usage: vk::BufferUsageFlags, - memory_usage: vk_mem::MemoryUsage, + memory_usage: MemoryLocation, } #[allow(dead_code)] impl BufferWrapper { pub fn new( - allocator: &vk_mem::Allocator, + allocator: &Allocator, capacity: u64, buffer_usage: vk::BufferUsageFlags, - memory_usage: vk_mem::MemoryUsage, - ) -> Result { - let allocation_create_info = vk_mem::AllocationCreateInfo { - usage: memory_usage, - ..Default::default() - }; + memory_usage: MemoryLocation, + ) -> Self { + let (buffer, allocation) = allocator.create_buffer(capacity, buffer_usage, memory_usage); - let (buffer, allocation, allocation_info) = allocator.create_buffer( - &vk::BufferCreateInfo::builder() - .size(capacity) - .usage(buffer_usage) - .build(), - &allocation_create_info, - )?; - - Ok(Self { + Self { buffer, allocation, - allocation_info, capacity, size: 0, buffer_usage, memory_usage, - }) + } } - pub fn fill( - &mut self, - allocator: &vk_mem::Allocator, - data: &[T], - ) -> Result<(), vk_mem::error::Error> { + pub fn fill(&mut self, allocator: &Allocator, data: &[T]) { let bytes_to_write = (data.len() * std::mem::size_of::()) as u64; if bytes_to_write > self.capacity { log::warn!("Not enough memory allocated in buffer; Resizing"); - self.resize(allocator, bytes_to_write)?; + self.resize(allocator, bytes_to_write); } - let data_ptr = allocator.map_memory(&self.allocation)? as *mut T; + let data_ptr = Allocator::get_ptr(&self.allocation) as *mut T; unsafe { data_ptr.copy_from_nonoverlapping(data.as_ptr(), data.len()); }; - allocator.unmap_memory(&self.allocation); self.size = bytes_to_write; - Ok(()) } pub fn get_size(&self) -> u64 { self.size } - fn resize( - &mut self, - allocator: &vk_mem::Allocator, - new_capacity: u64, - ) -> Result<(), vk_mem::error::Error> { + fn resize(&mut self, allocator: &Allocator, new_capacity: u64) { allocator.destroy_buffer(self.buffer, &self.allocation); let new_buffer = BufferWrapper::new( allocator, new_capacity, self.buffer_usage, self.memory_usage, - )?; + ); *self = new_buffer; - Ok(()) } - pub fn cleanup(&mut self, allocator: &vk_mem::Allocator) { + pub fn cleanup(&mut self, allocator: &Allocator) { allocator.destroy_buffer(self.buffer, &self.allocation) } } diff --git a/src/vulkan/debug.rs b/src/vulkan/debug.rs index e1180c5..beae163 100644 --- a/src/vulkan/debug.rs +++ b/src/vulkan/debug.rs @@ -1,4 +1,4 @@ -use ash::{extensions::ext, version::EntryV1_0, vk}; +use ash::{extensions::ext, vk}; use std::{ffi::c_void, os::raw::c_char}; use std::{ ffi::{CStr, CString}, diff --git a/src/vulkan/descriptor_manager.rs b/src/vulkan/descriptor_manager.rs index 9abb6d6..3f8fcf4 100644 --- a/src/vulkan/descriptor_manager.rs +++ b/src/vulkan/descriptor_manager.rs @@ -4,7 +4,7 @@ use std::{ slice, }; -use ash::{version::DeviceV1_0, vk}; +use ash::vk; /// This enum holds the necessary state for a single DescriptorSet binding. /// For usage, see [`DescriptorManager`] @@ -112,7 +112,11 @@ impl DescriptorManager { for s in &self.frame_sets[self.frame_index as usize] { let removed = self.set_cache.remove(s); if let Some(removed) = removed { - unsafe { self.device.free_descriptor_sets(self.pool, &[removed.set]) }; + unsafe { + self.device + .free_descriptor_sets(self.pool, &[removed.set]) + .unwrap() + }; } } self.frame_sets[self.frame_index as usize].clear(); diff --git a/src/vulkan/device.rs b/src/vulkan/device.rs index 920db45..8b00b45 100644 --- a/src/vulkan/device.rs +++ b/src/vulkan/device.rs @@ -1,6 +1,6 @@ use std::collections::BTreeMap; -use ash::{version::InstanceV1_0, vk}; +use ash::vk; use super::error::{GraphicsError, GraphicsResult}; @@ -39,8 +39,8 @@ pub fn select_physical_device( log::info!("GPU detected: {}", name); } - if vk::version_major(properties.api_version) != VULKAN_VERSION.0 - || vk::version_minor(properties.api_version) < VULKAN_VERSION.1 + if vk::api_version_major(properties.api_version) != VULKAN_VERSION.0 + || vk::api_version_minor(properties.api_version) < VULKAN_VERSION.1 { continue; } diff --git a/src/vulkan/error.rs b/src/vulkan/error.rs index 92b5af4..3779d0c 100644 --- a/src/vulkan/error.rs +++ b/src/vulkan/error.rs @@ -7,11 +7,6 @@ pub enum GraphicsError { /// General Vulkan API errors #[error("Vulkan API error: {0}")] Vk(#[from] vk::Result), - /// Vulkan memory allocator errors - /// - /// [`vk_mem::ErrorKind::Vulkan`] will be converted to [`GraphicsError::Vk`]. - #[error("vk_mem error: {0}")] - VkMem(vk_mem::Error), /// Error during shader property discovery #[error("Shader reflection error: {0}")] ShaderReflect(#[from] ve_shader_reflect::Error), @@ -32,13 +27,4 @@ pub enum GraphicsError { Other(#[from] anyhow::Error), } -impl From for GraphicsError { - fn from(err: vk_mem::Error) -> Self { - match err.kind() { - vk_mem::ErrorKind::Vulkan(code) => GraphicsError::Vk(*code), - _ => GraphicsError::VkMem(err), - } - } -} - pub type GraphicsResult = Result; diff --git a/src/vulkan/lighting_pipeline.rs b/src/vulkan/lighting_pipeline.rs index 33ae85c..273974f 100644 --- a/src/vulkan/lighting_pipeline.rs +++ b/src/vulkan/lighting_pipeline.rs @@ -1,6 +1,6 @@ use std::rc::Rc; -use ash::{version::DeviceV1_0, vk}; +use ash::vk; use super::pipeline; diff --git a/src/vulkan/mod.rs b/src/vulkan/mod.rs index 983b30c..b01572a 100644 --- a/src/vulkan/mod.rs +++ b/src/vulkan/mod.rs @@ -1,3 +1,4 @@ +pub mod allocator; pub(crate) mod buffer; mod debug; pub mod descriptor_manager; @@ -16,10 +17,10 @@ pub mod uploader; use std::{ffi::CString, mem::size_of, ptr::null, rc::Rc, slice}; use ash::{ - extensions::ext, - version::{DeviceV1_0, EntryV1_0, InstanceV1_0}, + extensions::{ext, khr}, vk::{self, Handle}, }; +use gpu_allocator::SubAllocation; use crate::{ core::camera::{self, CamData}, @@ -33,6 +34,7 @@ use crate::{ }; use self::{ + allocator::Allocator, buffer::{PerFrameUniformBuffer, VulkanBuffer}, debug::DebugMessenger, descriptor_manager::{DescriptorData, DescriptorManager}, @@ -49,7 +51,7 @@ pub struct VulkanManager { #[allow(dead_code)] entry: ash::Entry, instance: ash::Instance, - pub allocator: std::mem::ManuallyDrop>, + pub allocator: std::mem::ManuallyDrop>, pub device: Rc, debug: std::mem::ManuallyDrop, @@ -81,6 +83,32 @@ pub struct VulkanManager { pp_effects: Vec>, pub uploader: std::mem::ManuallyDrop, pub enable_wireframe: bool, + + pub rtx_data: Option, +} + +pub struct RtxData { + pub acc_ext: Rc, + pub rtx_ext: Rc, + pub scene_acc_buffer: vk::Buffer, + pub scene_acc_buffer_alloc: SubAllocation, + pub scene_acc: vk::AccelerationStructureKHR, + + pub rtx_set_layout: vk::DescriptorSetLayout, + pub rtx_pipe_layout: vk::PipelineLayout, + pub rtx_pipe: vk::Pipeline, + pub rtx_pool: vk::DescriptorPool, + pub rtx_set: vk::DescriptorSet, + + pub rtx_sbt_gen_alloc: SubAllocation, + pub rtx_sbt_gen: vk::Buffer, + pub rtx_sbt_gen_addr: vk::DeviceAddress, + pub rtx_sbt_chit_alloc: SubAllocation, + pub rtx_sbt_chit: vk::Buffer, + pub rtx_sbt_chit_addr: vk::DeviceAddress, + pub rtx_sbt_miss_alloc: SubAllocation, + pub rtx_sbt_miss: vk::Buffer, + pub rtx_sbt_miss_addr: vk::DeviceAddress, } impl VulkanManager { @@ -89,29 +117,28 @@ impl VulkanManager { window: &winit::window::Window, max_frames_in_flight: u8, ) -> GraphicsResult { - let entry = ash::Entry::new().map_err(anyhow::Error::from)?; - let instance = VulkanManager::init_instance(engine_info, &entry, &window)?; + let entry = unsafe { ash::Entry::new().map_err(anyhow::Error::from)? }; + let instance = VulkanManager::init_instance(engine_info, &entry, window)?; let debug = DebugMessenger::init(&entry, &instance)?; - let surface = SurfaceWrapper::init(&window, &entry, &instance); + let surface = SurfaceWrapper::init(window, &entry, &instance); let (physical_device, physical_device_properties, _physical_device_features) = device::select_physical_device(&instance)?; let queue_families = QueueFamilies::init(&instance, physical_device, &surface)?; - let (logical_device, queues) = + let (logical_device, queues, raytracing_supported) = queue::init_device_and_queues(&instance, physical_device, &queue_families)?; let logical_device = Rc::new(logical_device); - let allocator_create_info = vk_mem::AllocatorCreateInfo { + let allocator = Rc::new(Allocator::new( + instance.clone(), + logical_device.clone(), physical_device, - device: (*logical_device).clone(), - instance: instance.clone(), - ..Default::default() - }; - let allocator = Rc::new(vk_mem::Allocator::new(&allocator_create_info)?); + raytracing_supported, + )); let mut swapchain = SwapchainWrapper::init( &instance, @@ -170,7 +197,7 @@ impl VulkanManager { &allocator, max_frames_in_flight as u64, vk::BufferUsageFlags::UNIFORM_BUFFER, - )?; + ); let desc_layout_frame_data_bindings = [ // CamData @@ -288,13 +315,180 @@ impl VulkanManager { let pipe_layout_pp = unsafe { logical_device.create_pipeline_layout(&pipe_layout_pp_info, None)? }; - let uploader = Uploader::new( + let mut uploader = Uploader::new( logical_device.clone(), allocator.clone(), max_frames_in_flight as u64, queue_families.graphics_q_index, ); + let rtx_data = if raytracing_supported { + let rtx_set_bindings = [ + vk::DescriptorSetLayoutBinding::builder() + .binding(0) + .descriptor_type(vk::DescriptorType::ACCELERATION_STRUCTURE_KHR) + .descriptor_count(1) + .stage_flags(vk::ShaderStageFlags::RAYGEN_KHR) + .build(), + vk::DescriptorSetLayoutBinding::builder() + .binding(1) + .descriptor_type(vk::DescriptorType::STORAGE_IMAGE) + .descriptor_count(1) + .stage_flags(vk::ShaderStageFlags::RAYGEN_KHR) + .build(), + vk::DescriptorSetLayoutBinding::builder() + .binding(2) + .descriptor_type(vk::DescriptorType::UNIFORM_BUFFER_DYNAMIC) + .descriptor_count(1) + .stage_flags(vk::ShaderStageFlags::RAYGEN_KHR) + .build(), + ]; + let rtx_set_layout = unsafe { + logical_device.create_descriptor_set_layout( + &vk::DescriptorSetLayoutCreateInfo::builder() + .bindings(&rtx_set_bindings) + .build(), + None, + ) + } + .unwrap(); + + let rtx_pipe_layout_sets = [rtx_set_layout]; + let rtx_pipe_layout = unsafe { + logical_device.create_pipeline_layout( + &vk::PipelineLayoutCreateInfo::builder() + .set_layouts(&rtx_pipe_layout_sets) + .build(), + None, + ) + } + .unwrap(); + + let rtx_ext = Rc::new(khr::RayTracingPipeline::new(&instance, &logical_device)); + + let rtx_pipe = pipeline::create_rtx_pipeline( + rtx_pipe_layout, + "rtx_test.rgen.spv", + "rtx_test.rchit.spv", + &logical_device, + rtx_ext.clone(), + ); + + let rtx_pool_sizes = [ + vk::DescriptorPoolSize::builder() + .ty(vk::DescriptorType::ACCELERATION_STRUCTURE_KHR) + .descriptor_count(1) + .build(), + vk::DescriptorPoolSize::builder() + .ty(vk::DescriptorType::STORAGE_IMAGE) + .descriptor_count(1) + .build(), + vk::DescriptorPoolSize::builder() + .ty(vk::DescriptorType::UNIFORM_BUFFER_DYNAMIC) + .descriptor_count(1) + .build(), + ]; + let rtx_pool = unsafe { + logical_device.create_descriptor_pool( + &vk::DescriptorPoolCreateInfo::builder() + .max_sets(1) + .pool_sizes(&rtx_pool_sizes) + .build(), + None, + ) + } + .unwrap(); + + let rtx_set = unsafe { + logical_device.allocate_descriptor_sets( + &vk::DescriptorSetAllocateInfo::builder() + .descriptor_pool(rtx_pool) + .set_layouts(&[rtx_set_layout]) + .build(), + ) + } + .unwrap()[0]; + + let (rtx_sbt_gen, rtx_sbt_gen_alloc) = allocator.create_buffer( + 32, + vk::BufferUsageFlags::SHADER_BINDING_TABLE_KHR + | vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS + | vk::BufferUsageFlags::TRANSFER_DST, + gpu_allocator::MemoryLocation::GpuOnly, + ); + let (rtx_sbt_chit, rtx_sbt_chit_alloc) = allocator.create_buffer( + 32, + vk::BufferUsageFlags::SHADER_BINDING_TABLE_KHR + | vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS + | vk::BufferUsageFlags::TRANSFER_DST, + gpu_allocator::MemoryLocation::GpuOnly, + ); + let (rtx_sbt_miss, rtx_sbt_miss_alloc) = allocator.create_buffer( + 32, + vk::BufferUsageFlags::SHADER_BINDING_TABLE_KHR + | vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS + | vk::BufferUsageFlags::TRANSFER_DST, + gpu_allocator::MemoryLocation::GpuOnly, + ); + let rtx_sbt_gen_addr = unsafe { + logical_device.get_buffer_device_address( + &vk::BufferDeviceAddressInfo::builder() + .buffer(rtx_sbt_gen) + .build(), + ) + }; + let rtx_sbt_chit_addr = unsafe { + logical_device.get_buffer_device_address( + &vk::BufferDeviceAddressInfo::builder() + .buffer(rtx_sbt_chit) + .build(), + ) + }; + let rtx_sbt_miss_addr = unsafe { + logical_device.get_buffer_device_address( + &vk::BufferDeviceAddressInfo::builder() + .buffer(rtx_sbt_miss) + .build(), + ) + }; + + let handles = unsafe { + rtx_ext + .get_ray_tracing_shader_group_handles(rtx_pipe, 0, 2, 64) + .unwrap() + }; + let zero_handle = [0u8; 32]; + + uploader.enqueue_buffer_upload(rtx_sbt_gen, 0, &handles[0..32]); + uploader.enqueue_buffer_upload(rtx_sbt_chit, 0, &handles[32..64]); + uploader.enqueue_buffer_upload(rtx_sbt_miss, 0, &zero_handle); + + Some(RtxData { + acc_ext: Rc::new(khr::AccelerationStructure::new(&instance, &logical_device)), + rtx_ext, + scene_acc_buffer: vk::Buffer::null(), + scene_acc_buffer_alloc: SubAllocation::default(), + scene_acc: vk::AccelerationStructureKHR::null(), + rtx_set_layout, + rtx_pipe_layout, + rtx_pipe, + rtx_pool, + rtx_set, + + rtx_sbt_gen_alloc, + rtx_sbt_gen, + rtx_sbt_gen_addr, + rtx_sbt_chit_alloc, + rtx_sbt_chit, + rtx_sbt_chit_addr, + rtx_sbt_miss_alloc, + rtx_sbt_miss, + rtx_sbt_miss_addr, + }) + } else { + None + }; + Ok(Self { entry, instance, @@ -328,6 +522,8 @@ impl VulkanManager { pp_effects: Vec::new(), uploader: std::mem::ManuallyDrop::new(uploader), enable_wireframe: false, + + rtx_data, }) } @@ -352,10 +548,10 @@ impl VulkanManager { let app_info = vk::ApplicationInfo::builder() .application_name(&app_name) - .application_version(vk::make_version(0, 0, 1)) + .application_version(vk::make_api_version(0, 0, 1, 0)) .engine_name(&app_name) - .engine_version(vk::make_version(0, 0, 1)) - .api_version(vk::make_version(1, 2, 0)); + .engine_version(vk::make_api_version(0, 0, 1, 0)) + .api_version(vk::make_api_version(1, 2, 0, 0)); let surface_extensions = ash_window::enumerate_required_extensions(window).unwrap(); let mut extension_names_raw = surface_extensions @@ -375,7 +571,7 @@ impl VulkanManager { &mut debug::get_debug_create_info(startup_debug_severity, startup_debug_type); let layer_names = debug::get_layer_names(); - if debug::ENABLE_VALIDATION_LAYERS && debug::has_validation_layers_support(&entry) { + if debug::ENABLE_VALIDATION_LAYERS && debug::has_validation_layers_support(entry) { instance_create_info = instance_create_info .push_next(debug_create_info) .enabled_layer_names(&layer_names); @@ -475,7 +671,7 @@ impl VulkanManager { } fn transition_images( - &self, + device: &ash::Device, commandbuffer: vk::CommandBuffer, src_stages: vk::PipelineStageFlags, dst_stages: vk::PipelineStageFlags, @@ -500,7 +696,7 @@ impl VulkanManager { } unsafe { - self.device.cmd_pipeline_barrier( + device.cmd_pipeline_barrier( commandbuffer, src_stages, dst_stages, @@ -526,7 +722,7 @@ impl VulkanManager { offset: vk::Offset2D { x: 0, y: 0 }, extent: self.swapchain.extent, }) - .clear_values(&clear_values); + .clear_values(clear_values); unsafe { self.device .cmd_begin_render_pass(commandbuffer, &info, vk::SubpassContents::INLINE); @@ -794,7 +990,8 @@ impl VulkanManager { } // transition swapchain image to TRANSFER_DST_OPTIMAL and final pp image to TRANSFER_SRC_OPTIMAL - self.transition_images( + Self::transition_images( + &self.device, commandbuffer, vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT, vk::PipelineStageFlags::TRANSFER, @@ -834,7 +1031,8 @@ impl VulkanManager { ); // transition swapchain image to PRESENT_SRC_KHR - self.transition_images( + Self::transition_images( + &self.device, commandbuffer, vk::PipelineStageFlags::TRANSFER, vk::PipelineStageFlags::BOTTOM_OF_PIPE, // can be BOTTOM_OF_PIPE because vkQueuePresentKHR waits for a semaphore @@ -862,83 +1060,245 @@ impl VulkanManager { .begin_command_buffer(commandbuffer, &commandbuffer_begininfo)?; } - self.begin_renderpass( - commandbuffer, - self.renderpass, - self.swapchain.framebuffer_deferred, - &[ - vk::ClearValue { - color: vk::ClearColorValue { - float32: [0.2, 0.2, 0.2, 0.0], - }, - }, - vk::ClearValue { - depth_stencil: vk::ClearDepthStencilValue { - depth: 1.0, - stencil: 0, - }, - }, - ], - ); + if let Some(rtx_data) = &mut self.rtx_data { + if rtx_data.scene_acc == vk::AccelerationStructureKHR::null() { + let mut objects = Vec::new(); + for obj in &scene.models { + objects.push(( + obj.mesh.rtx_data.as_ref().unwrap().acc_struct, + obj.transform.get_transform_data().model_matrix, + )); + } - let desc_values_frame_data = [ - DescriptorData::DynamicUniformBuffer { - buffer: self.uniform_buffer.get_buffer(), - offset: 0, - size: self.uniform_buffer.get_size(), - }, - DescriptorData::InputAttachment { - image: self.swapchain.g0_imageview, - layout: vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL, - }, - DescriptorData::InputAttachment { - image: self.swapchain.g1_imageview, - layout: vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL, - }, - DescriptorData::InputAttachment { - image: self.swapchain.depth_imageview_depth_only, - layout: vk::ImageLayout::DEPTH_STENCIL_READ_ONLY_OPTIMAL, - }, - ]; - let desc_set_camera = self - .descriptor_manager - .get_descriptor_set(self.desc_layout_frame_data, &desc_values_frame_data)?; + let (acc, acc_buffer, acc_alloc) = self + .uploader + .enqueue_scene_acc_struct_build(rtx_data.acc_ext.clone(), &objects); + rtx_data.scene_acc = acc; + rtx_data.scene_acc_buffer = acc_buffer; + rtx_data.scene_acc_buffer_alloc = acc_alloc; + + unsafe { + let mut acc_write = vk::WriteDescriptorSet::builder() + .dst_set(rtx_data.rtx_set) + .dst_binding(0) + .descriptor_type(vk::DescriptorType::ACCELERATION_STRUCTURE_KHR) + .build(); + acc_write.descriptor_count = 1; + let accs = [rtx_data.scene_acc]; + let acc_write_next = vk::WriteDescriptorSetAccelerationStructureKHR::builder() + .acceleration_structures(&accs) + .build(); + acc_write.p_next = &acc_write_next as *const _ as *const _; + + let image_info = [vk::DescriptorImageInfo::builder() + .image_view(self.swapchain.g0_imageview) + .image_layout(vk::ImageLayout::GENERAL) + .build()]; + let buffer_info = [vk::DescriptorBufferInfo::builder() + .buffer(self.uniform_buffer.get_buffer()) + .range(self.uniform_buffer.get_size()) + .build()]; + + self.device.update_descriptor_sets( + &[ + acc_write, + vk::WriteDescriptorSet::builder() + .dst_set(rtx_data.rtx_set) + .dst_binding(1) + .descriptor_type(vk::DescriptorType::STORAGE_IMAGE) + .image_info(&image_info) + .build(), + vk::WriteDescriptorSet::builder() + .dst_set(rtx_data.rtx_set) + .dst_binding(2) + .descriptor_type(vk::DescriptorType::UNIFORM_BUFFER_DYNAMIC) + .buffer_info(&buffer_info) + .build(), + ], + &[], + ); + } + } - unsafe { - self.device.cmd_bind_descriptor_sets( + Self::transition_images( + &self.device, commandbuffer, - vk::PipelineBindPoint::GRAPHICS, - self.pipeline_layout_gpass, - 0, - &[desc_set_camera], - &[self.uniform_buffer.get_offset(self.current_frame_index) as u32], + vk::PipelineStageFlags::RAY_TRACING_SHADER_KHR, + vk::PipelineStageFlags::RAY_TRACING_SHADER_KHR, + &[ImageTransition { + image: self.swapchain.g0_image, + from: vk::ImageLayout::UNDEFINED, + to: vk::ImageLayout::GENERAL, + wait_access: vk::AccessFlags::empty(), + dst_access: vk::AccessFlags::SHADER_WRITE, + }], ); - } - let render_map = Self::build_render_order(&scene.models); - self.render_gpass(commandbuffer, &render_map)?; + unsafe { + self.device.cmd_bind_descriptor_sets( + commandbuffer, + vk::PipelineBindPoint::RAY_TRACING_KHR, + rtx_data.rtx_pipe_layout, + 0, + &[rtx_data.rtx_set], + &[self.uniform_buffer.get_offset(self.current_frame_index) as u32], + ); + self.device.cmd_bind_pipeline( + commandbuffer, + vk::PipelineBindPoint::RAY_TRACING_KHR, + rtx_data.rtx_pipe, + ); + rtx_data.rtx_ext.cmd_trace_rays( + commandbuffer, + &vk::StridedDeviceAddressRegionKHR::builder() + .device_address(rtx_data.rtx_sbt_gen_addr) + .stride(32) + .size(32) + .build(), + &vk::StridedDeviceAddressRegionKHR::builder() + .device_address(rtx_data.rtx_sbt_miss_addr) + .stride(32) + .size(32) + .build(), + &vk::StridedDeviceAddressRegionKHR::builder() + .device_address(rtx_data.rtx_sbt_chit_addr) + .stride(32) + .size(32) + .build(), + &vk::StridedDeviceAddressRegionKHR::builder() + .stride(0) + .size(0) + .build(), + self.swapchain.extent.width, + self.swapchain.extent.height, + 1, + ); + } - unsafe { - self.device - .cmd_next_subpass(commandbuffer, vk::SubpassContents::INLINE); + Self::transition_images( + &self.device, + commandbuffer, + vk::PipelineStageFlags::RAY_TRACING_SHADER_KHR, + vk::PipelineStageFlags::TRANSFER, + &[ + ImageTransition { + image: self.swapchain.g0_image, + from: vk::ImageLayout::GENERAL, + to: vk::ImageLayout::TRANSFER_SRC_OPTIMAL, + wait_access: vk::AccessFlags::SHADER_WRITE, + dst_access: vk::AccessFlags::TRANSFER_READ, + }, + ImageTransition { + image: self.swapchain.images[swapchain_image_index], + from: vk::ImageLayout::UNDEFINED, + to: vk::ImageLayout::TRANSFER_DST_OPTIMAL, + wait_access: vk::AccessFlags::empty(), + dst_access: vk::AccessFlags::TRANSFER_WRITE, + }, + ], + ); - self.device.cmd_bind_descriptor_sets( + self.blit_image( commandbuffer, - vk::PipelineBindPoint::GRAPHICS, - self.pipeline_layout_resolve_pass, - 0, - &[desc_set_camera], - &[self.uniform_buffer.get_offset(self.current_frame_index) as u32], + self.swapchain.g0_image, + self.swapchain.images[swapchain_image_index], + self.swapchain.extent.width as i32, + self.swapchain.extent.height as i32, ); - } - self.render_resolve_pass(commandbuffer, &scene.light_manager); + Self::transition_images( + &self.device, + commandbuffer, + vk::PipelineStageFlags::TRANSFER, + vk::PipelineStageFlags::BOTTOM_OF_PIPE, + &[ImageTransition { + image: self.swapchain.images[swapchain_image_index], + from: vk::ImageLayout::TRANSFER_DST_OPTIMAL, + to: vk::ImageLayout::PRESENT_SRC_KHR, + wait_access: vk::AccessFlags::TRANSFER_WRITE, + dst_access: vk::AccessFlags::empty(), + }], + ); + } else { + self.begin_renderpass( + commandbuffer, + self.renderpass, + self.swapchain.framebuffer_deferred, + &[ + vk::ClearValue { + color: vk::ClearColorValue { + float32: [0.2, 0.2, 0.2, 0.0], + }, + }, + vk::ClearValue { + depth_stencil: vk::ClearDepthStencilValue { + depth: 1.0, + stencil: 0, + }, + }, + ], + ); - unsafe { - self.device.cmd_end_render_pass(commandbuffer); + let desc_values_frame_data = [ + DescriptorData::DynamicUniformBuffer { + buffer: self.uniform_buffer.get_buffer(), + offset: 0, + size: self.uniform_buffer.get_size(), + }, + DescriptorData::InputAttachment { + image: self.swapchain.g0_imageview, + layout: vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL, + }, + DescriptorData::InputAttachment { + image: self.swapchain.g1_imageview, + layout: vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL, + }, + DescriptorData::InputAttachment { + image: self.swapchain.depth_imageview_depth_only, + layout: vk::ImageLayout::DEPTH_STENCIL_READ_ONLY_OPTIMAL, + }, + ]; + let desc_set_camera = self + .descriptor_manager + .get_descriptor_set(self.desc_layout_frame_data, &desc_values_frame_data)?; + + unsafe { + self.device.cmd_bind_descriptor_sets( + commandbuffer, + vk::PipelineBindPoint::GRAPHICS, + self.pipeline_layout_gpass, + 0, + &[desc_set_camera], + &[self.uniform_buffer.get_offset(self.current_frame_index) as u32], + ); + } + + let render_map = Self::build_render_order(&scene.models); + self.render_gpass(commandbuffer, &render_map)?; + + unsafe { + self.device + .cmd_next_subpass(commandbuffer, vk::SubpassContents::INLINE); + + self.device.cmd_bind_descriptor_sets( + commandbuffer, + vk::PipelineBindPoint::GRAPHICS, + self.pipeline_layout_resolve_pass, + 0, + &[desc_set_camera], + &[self.uniform_buffer.get_offset(self.current_frame_index) as u32], + ); + } - self.render_pp(commandbuffer, swapchain_image_index)?; + self.render_resolve_pass(commandbuffer, &scene.light_manager); + unsafe { + self.device.cmd_end_render_pass(commandbuffer); + self.render_pp(commandbuffer, swapchain_image_index)?; + } + } + + unsafe { self.device.end_command_buffer(commandbuffer)?; } diff --git a/src/vulkan/pipeline.rs b/src/vulkan/pipeline.rs index 4a28042..61ba7c9 100644 --- a/src/vulkan/pipeline.rs +++ b/src/vulkan/pipeline.rs @@ -1,4 +1,6 @@ -use ash::{version::DeviceV1_0, vk}; +use std::rc::Rc; + +use ash::{extensions::khr::RayTracingPipeline, vk}; use crate::assets::shader; @@ -21,6 +23,86 @@ pub fn create_shader_modules( Ok((vertexshader_module, fragmentshader_module)) } +pub fn create_rtx_pipeline( + layout: vk::PipelineLayout, + ray_gen_shader: &str, + ray_chit_shader: &str, + device: &ash::Device, + rtx_ext: Rc, +) -> vk::Pipeline { + let func_name = std::ffi::CString::new("main").unwrap(); + + let mut rgen_code = Vec::new(); + let rgen_shader_module = unsafe { + device + .create_shader_module( + &shader::load_single(ray_gen_shader.to_owned(), &mut rgen_code), + None, + ) + .unwrap() + }; + + let mut rchit_code = Vec::new(); + let rchit_shader_module = unsafe { + device + .create_shader_module( + &shader::load_single(ray_chit_shader.to_owned(), &mut rchit_code), + None, + ) + .unwrap() + }; + + let stages = [ + vk::PipelineShaderStageCreateInfo::builder() + .stage(vk::ShaderStageFlags::RAYGEN_KHR) + .module(rgen_shader_module) + .name(&func_name) + .build(), + vk::PipelineShaderStageCreateInfo::builder() + .stage(vk::ShaderStageFlags::CLOSEST_HIT_KHR) + .module(rchit_shader_module) + .name(&func_name) + .build(), + ]; + let groups = [ + vk::RayTracingShaderGroupCreateInfoKHR::builder() + .ty(vk::RayTracingShaderGroupTypeKHR::GENERAL) + .general_shader(0) + .closest_hit_shader(vk::SHADER_UNUSED_KHR) + .any_hit_shader(vk::SHADER_UNUSED_KHR) + .intersection_shader(vk::SHADER_UNUSED_KHR) + .build(), + vk::RayTracingShaderGroupCreateInfoKHR::builder() + .ty(vk::RayTracingShaderGroupTypeKHR::TRIANGLES_HIT_GROUP) + .general_shader(vk::SHADER_UNUSED_KHR) + .closest_hit_shader(1) + .any_hit_shader(vk::SHADER_UNUSED_KHR) + .intersection_shader(vk::SHADER_UNUSED_KHR) + .build(), + ]; + let pipe = unsafe { + rtx_ext.create_ray_tracing_pipelines( + vk::DeferredOperationKHR::null(), + vk::PipelineCache::null(), + &[vk::RayTracingPipelineCreateInfoKHR::builder() + .stages(&stages) + .groups(&groups) + .max_pipeline_ray_recursion_depth(1) + .layout(layout) + .build()], + None, + ) + } + .unwrap()[0]; + + unsafe { + device.destroy_shader_module(rgen_shader_module, None); + device.destroy_shader_module(rchit_shader_module, None); + } + + pipe +} + /// Creates a [`vk::Pipeline`] with the given options. /// /// Used to reduce code duplication. @@ -46,16 +128,17 @@ pub fn create_pipeline( fragmentshader_module: vk::ShaderModule, wireframe: bool, ) -> Result { - let mainfunctionname = std::ffi::CString::new("main").unwrap(); + let vert_func_name = std::ffi::CString::new("vert").unwrap(); + let frag_func_name = std::ffi::CString::new("frag").unwrap(); let vertexshader_stage = vk::PipelineShaderStageCreateInfo::builder() .stage(vk::ShaderStageFlags::VERTEX) .module(vertexshader_module) - .name(&mainfunctionname); + .name(&vert_func_name); let fragmentshader_stage = vk::PipelineShaderStageCreateInfo::builder() .stage(vk::ShaderStageFlags::FRAGMENT) .module(fragmentshader_module) - .name(&mainfunctionname); + .name(&frag_func_name); let shader_stages = [vertexshader_stage.build(), fragmentshader_stage.build()]; let vertex_attrib_descs = [ diff --git a/src/vulkan/pp_effect.rs b/src/vulkan/pp_effect.rs index d66a8ab..be2d708 100644 --- a/src/vulkan/pp_effect.rs +++ b/src/vulkan/pp_effect.rs @@ -1,6 +1,6 @@ use std::rc::Rc; -use ash::{version::DeviceV1_0, vk}; +use ash::vk; use super::pipeline; diff --git a/src/vulkan/queue.rs b/src/vulkan/queue.rs index 216bba4..7dd0347 100644 --- a/src/vulkan/queue.rs +++ b/src/vulkan/queue.rs @@ -1,8 +1,6 @@ -use ash::{ - extensions::khr, - version::{DeviceV1_0, InstanceV1_0}, - vk, -}; +use std::ffi::CStr; + +use ash::{extensions::khr, vk}; use super::{ error::{GraphicsError, GraphicsResult}, @@ -97,8 +95,26 @@ pub fn init_device_and_queues( instance: &ash::Instance, physical_device: vk::PhysicalDevice, queue_families: &QueueFamilies, -) -> GraphicsResult<(ash::Device, Queues)> { - let device_extension_names_raw = [khr::Swapchain::name().as_ptr()]; +) -> GraphicsResult<(ash::Device, Queues, bool)> { + let dev_extensions = + unsafe { instance.enumerate_device_extension_properties(physical_device)? }; + + let mut raytracing_supported = false; + for ext in &dev_extensions { + let ext_name = unsafe { CStr::from_ptr(ext.extension_name.as_ptr()) }; + if ext_name == khr::RayTracingPipeline::name() { + log::info!("Enabling raytracing support"); + raytracing_supported = true; + } + } + + let mut device_extension_names_raw = vec![khr::Swapchain::name().as_ptr()]; + if raytracing_supported { + device_extension_names_raw.push(khr::RayTracingPipeline::name().as_ptr()); + device_extension_names_raw.push(khr::AccelerationStructure::name().as_ptr()); + device_extension_names_raw.push(khr::DeferredHostOperations::name().as_ptr()); + } + // https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html // required for wireframe fill mode let features = vk::PhysicalDeviceFeatures::builder().fill_mode_non_solid(true); // TODO: check if feature is supported before force-enabling it @@ -109,16 +125,39 @@ pub fn init_device_and_queues( .queue_priorities(&priorities) .build()]; - let device_create_info = vk::DeviceCreateInfo::builder() + let mut device_create_info = vk::DeviceCreateInfo::builder() .queue_create_infos(&queue_info) .enabled_extension_names(&device_extension_names_raw) .enabled_features(&features); + let mut vk12features = vk::PhysicalDeviceVulkan12Features::builder() + .buffer_device_address(raytracing_supported) + .build(); + device_create_info = device_create_info.push_next(&mut vk12features); + + let mut acc_features = vk::PhysicalDeviceAccelerationStructureFeaturesKHR::builder() + .acceleration_structure(raytracing_supported) + .build(); + if raytracing_supported { + device_create_info = device_create_info.push_next(&mut acc_features); + } + + let mut ray_pipe_features = vk::PhysicalDeviceRayTracingPipelineFeaturesKHR::builder() + .ray_tracing_pipeline(raytracing_supported) + .build(); + if raytracing_supported { + device_create_info = device_create_info.push_next(&mut ray_pipe_features); + } + let logical_device: ash::Device = unsafe { instance.create_device(physical_device, &device_create_info, None) }?; let graphics_queue = unsafe { logical_device.get_device_queue(queue_families.graphics_q_index as u32, 0) }; - Ok((logical_device, Queues { graphics_queue })) + Ok(( + logical_device, + Queues { graphics_queue }, + raytracing_supported, + )) } diff --git a/src/vulkan/renderpass.rs b/src/vulkan/renderpass.rs index 4556ca7..192ec4c 100644 --- a/src/vulkan/renderpass.rs +++ b/src/vulkan/renderpass.rs @@ -1,4 +1,4 @@ -use ash::{version::DeviceV1_0, vk}; +use ash::vk; pub fn create_deferred_pass( color_format: vk::Format, diff --git a/src/vulkan/swapchain.rs b/src/vulkan/swapchain.rs index d3477ac..f437626 100644 --- a/src/vulkan/swapchain.rs +++ b/src/vulkan/swapchain.rs @@ -1,6 +1,7 @@ -use ash::{version::DeviceV1_0, vk}; +use ash::vk; +use gpu_allocator::SubAllocation; -use super::{queue, surface, GraphicsResult}; +use super::{allocator::Allocator, queue, surface, GraphicsResult}; const PREFERRED_IMAGE_COUNT: u32 = 3; @@ -11,7 +12,7 @@ pub struct SwapchainWrapper { pub images: Vec, pub imageviews: Vec, pub depth_image: vk::Image, // used in gpass and resolve pass - pub depth_image_alloc: vk_mem::Allocation, + pub depth_image_alloc: SubAllocation, pub depth_imageview: vk::ImageView, pub depth_imageview_depth_only: vk::ImageView, pub surface_format: vk::SurfaceFormatKHR, @@ -19,13 +20,13 @@ pub struct SwapchainWrapper { pub amount_of_images: u32, pub resolve_image: vk::Image, // will contain the finished deferred scene rendering pub resolve_imageview: vk::ImageView, - pub resolve_image_alloc: vk_mem::Allocation, + pub resolve_image_alloc: SubAllocation, pub g0_image: vk::Image, pub g0_imageview: vk::ImageView, - pub g0_image_alloc: vk_mem::Allocation, + pub g0_image_alloc: SubAllocation, pub g1_image: vk::Image, pub g1_imageview: vk::ImageView, - pub g1_image_alloc: vk_mem::Allocation, + pub g1_image_alloc: SubAllocation, pub framebuffer_deferred: vk::Framebuffer, // used for gpass and resolve pass, renders to resolve_image pub framebuffer_pp_a: vk::Framebuffer, // used for pp, renders to g0_image pub framebuffer_pp_b: vk::Framebuffer, // used for pp, renders to resolve_image @@ -38,7 +39,7 @@ impl SwapchainWrapper { logical_device: &ash::Device, surface: &surface::SurfaceWrapper, #[allow(unused_variables)] queue_families: &queue::QueueFamilies, - allocator: &vk_mem::Allocator, + allocator: &Allocator, ) -> GraphicsResult { let surface_capabilities = surface.get_capabilities(physical_device)?; let extent = surface_capabilities.current_extent; // TODO: handle 0xFFFF x 0xFFFF extent @@ -87,31 +88,13 @@ impl SwapchainWrapper { unsafe { logical_device.create_image_view(&imageview_create_info, None) }?; swapchain_imageviews.push(imageview); } - let extend_3d = vk::Extent3D { - width: extent.width, - height: extent.height, - depth: 1, - }; - let depth_image_info = vk::ImageCreateInfo::builder() - .image_type(vk::ImageType::TYPE_2D) - .format(vk::Format::D24_UNORM_S8_UINT) - .extent(extend_3d) - .mip_levels(1) - .array_layers(1) - .samples(vk::SampleCountFlags::TYPE_1) - .tiling(vk::ImageTiling::OPTIMAL) - .usage( - vk::ImageUsageFlags::DEPTH_STENCIL_ATTACHMENT - | vk::ImageUsageFlags::INPUT_ATTACHMENT, - ) - .sharing_mode(vk::SharingMode::EXCLUSIVE); - let allocation_info = vk_mem::AllocationCreateInfo { - usage: vk_mem::MemoryUsage::GpuOnly, - ..Default::default() - }; - let (depth_image, depth_image_alloc, _) = - allocator.create_image(&depth_image_info, &allocation_info)?; + let (depth_image, depth_image_alloc) = allocator.create_image( + extent.width, + extent.height, + vk::ImageUsageFlags::DEPTH_STENCIL_ATTACHMENT | vk::ImageUsageFlags::INPUT_ATTACHMENT, + vk::Format::D24_UNORM_S8_UINT, + ); let subresource_range = vk::ImageSubresourceRange::builder() .aspect_mask(vk::ImageAspectFlags::DEPTH | vk::ImageAspectFlags::STENCIL) .base_mip_level(0) @@ -140,26 +123,14 @@ impl SwapchainWrapper { let depth_imageview_depth_only = unsafe { logical_device.create_image_view(&imageview_create_info, None) }?; - let resolve_image_info = vk::ImageCreateInfo::builder() - .image_type(vk::ImageType::TYPE_2D) - .format(vk::Format::R16G16B16A16_SFLOAT) - .extent(extend_3d) - .mip_levels(1) - .array_layers(1) - .samples(vk::SampleCountFlags::TYPE_1) - .tiling(vk::ImageTiling::OPTIMAL) - .usage( - vk::ImageUsageFlags::COLOR_ATTACHMENT - | vk::ImageUsageFlags::TRANSFER_SRC - | vk::ImageUsageFlags::SAMPLED, - ) - .sharing_mode(vk::SharingMode::EXCLUSIVE); - let allocation_info = vk_mem::AllocationCreateInfo { - usage: vk_mem::MemoryUsage::GpuOnly, - ..Default::default() - }; - let (resolve_image, resolve_image_alloc, _) = - allocator.create_image(&resolve_image_info, &allocation_info)?; + let (resolve_image, resolve_image_alloc) = allocator.create_image( + extent.width, + extent.height, + vk::ImageUsageFlags::COLOR_ATTACHMENT + | vk::ImageUsageFlags::TRANSFER_SRC + | vk::ImageUsageFlags::SAMPLED, + vk::Format::R16G16B16A16_SFLOAT, + ); let subresource_range = vk::ImageSubresourceRange::builder() .aspect_mask(vk::ImageAspectFlags::COLOR) .base_mip_level(0) @@ -174,27 +145,16 @@ impl SwapchainWrapper { let resolve_imageview = unsafe { logical_device.create_image_view(&imageview_create_info, None) }?; - let g0_image_info = vk::ImageCreateInfo::builder() - .image_type(vk::ImageType::TYPE_2D) - .format(vk::Format::R16G16B16A16_SFLOAT) - .extent(extend_3d) - .mip_levels(1) - .array_layers(1) - .samples(vk::SampleCountFlags::TYPE_1) - .tiling(vk::ImageTiling::OPTIMAL) - .usage( - vk::ImageUsageFlags::COLOR_ATTACHMENT - | vk::ImageUsageFlags::INPUT_ATTACHMENT - | vk::ImageUsageFlags::TRANSFER_SRC - | vk::ImageUsageFlags::SAMPLED, - ) - .sharing_mode(vk::SharingMode::EXCLUSIVE); - let allocation_info = vk_mem::AllocationCreateInfo { - usage: vk_mem::MemoryUsage::GpuOnly, - ..Default::default() - }; - let (g0_image, g0_image_alloc, _) = - allocator.create_image(&g0_image_info, &allocation_info)?; + let (g0_image, g0_image_alloc) = allocator.create_image( + extent.width, + extent.height, + vk::ImageUsageFlags::COLOR_ATTACHMENT + | vk::ImageUsageFlags::INPUT_ATTACHMENT + | vk::ImageUsageFlags::TRANSFER_SRC + | vk::ImageUsageFlags::SAMPLED + | vk::ImageUsageFlags::STORAGE, + vk::Format::R16G16B16A16_SFLOAT, + ); let subresource_range = vk::ImageSubresourceRange::builder() .aspect_mask(vk::ImageAspectFlags::COLOR) .base_mip_level(0) @@ -209,22 +169,12 @@ impl SwapchainWrapper { let g0_imageview = unsafe { logical_device.create_image_view(&imageview_create_info, None) }?; - let g1_image_info = vk::ImageCreateInfo::builder() - .image_type(vk::ImageType::TYPE_2D) - .format(vk::Format::R16G16B16A16_SFLOAT) - .extent(extend_3d) - .mip_levels(1) - .array_layers(1) - .samples(vk::SampleCountFlags::TYPE_1) - .tiling(vk::ImageTiling::OPTIMAL) - .usage(vk::ImageUsageFlags::COLOR_ATTACHMENT | vk::ImageUsageFlags::INPUT_ATTACHMENT) - .sharing_mode(vk::SharingMode::EXCLUSIVE); - let allocation_info = vk_mem::AllocationCreateInfo { - usage: vk_mem::MemoryUsage::GpuOnly, - ..Default::default() - }; - let (g1_image, g1_image_alloc, _) = - allocator.create_image(&g1_image_info, &allocation_info)?; + let (g1_image, g1_image_alloc) = allocator.create_image( + extent.width, + extent.height, + vk::ImageUsageFlags::COLOR_ATTACHMENT | vk::ImageUsageFlags::INPUT_ATTACHMENT, + vk::Format::R16G16B16A16_SFLOAT, + ); let subresource_range = vk::ImageSubresourceRange::builder() .aspect_mask(vk::ImageAspectFlags::COLOR) .base_mip_level(0) @@ -328,7 +278,7 @@ impl SwapchainWrapper { Ok(()) } - pub unsafe fn cleanup(&mut self, logical_device: &ash::Device, allocator: &vk_mem::Allocator) { + pub unsafe fn cleanup(&mut self, logical_device: &ash::Device, allocator: &Allocator) { logical_device.destroy_framebuffer(self.framebuffer_deferred, None); logical_device.destroy_framebuffer(self.framebuffer_pp_a, None); logical_device.destroy_framebuffer(self.framebuffer_pp_b, None); diff --git a/src/vulkan/texture.rs b/src/vulkan/texture.rs index 4938743..af18dbf 100644 --- a/src/vulkan/texture.rs +++ b/src/vulkan/texture.rs @@ -1,8 +1,9 @@ use std::rc::Rc; -use ash::{version::DeviceV1_0, vk}; +use ash::vk; +use gpu_allocator::SubAllocation; -use super::uploader::Uploader; +use super::{allocator::Allocator, uploader::Uploader}; /// The filtering mode with which a [`Texture2D`] should be sampled. pub enum TextureFilterMode { @@ -16,10 +17,10 @@ pub enum TextureFilterMode { /// /// A Texture2D will always be in R8G8B8A8 format. pub struct Texture2D { - allocator: Rc, + allocator: Rc, device: Rc, image: vk::Image, - alloc: vk_mem::Allocation, + alloc: SubAllocation, /// The [`vk::ImageView`] that can be used to refer to this [`Texture2D`]. pub view: vk::ImageView, pub width: u32, @@ -40,32 +41,16 @@ impl Texture2D { height: u32, pixels: &[u8], filter: TextureFilterMode, - allocator: Rc, + allocator: Rc, uploader: &mut Uploader, device: Rc, - ) -> Result, vk_mem::Error> { - let image_info = vk::ImageCreateInfo::builder() - .image_type(vk::ImageType::TYPE_2D) - .format(vk::Format::R8G8B8A8_SRGB) - .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::TRANSFER_DST | vk::ImageUsageFlags::SAMPLED) - .sharing_mode(vk::SharingMode::EXCLUSIVE) - .initial_layout(vk::ImageLayout::UNDEFINED) - .build(); - let alloc_info = vk_mem::AllocationCreateInfo { - usage: vk_mem::MemoryUsage::GpuOnly, - ..Default::default() - }; - - let (image, alloc, _) = allocator.create_image(&image_info, &alloc_info)?; + ) -> Rc { + let (image, alloc) = allocator.create_image( + width, + height, + vk::ImageUsageFlags::TRANSFER_DST | vk::ImageUsageFlags::SAMPLED, + vk::Format::R8G8B8A8_SRGB, + ); uploader.enqueue_image_upload( image, @@ -116,7 +101,7 @@ impl Texture2D { .build(); let sampler = unsafe { device.create_sampler(&sampler_info, None) }.unwrap(); - Ok(Rc::new(Texture2D { + Rc::new(Texture2D { allocator, device, image, @@ -125,7 +110,7 @@ impl Texture2D { width, height, sampler, - })) + }) } } diff --git a/src/vulkan/uploader.rs b/src/vulkan/uploader.rs index 9be39f6..9ad18e2 100644 --- a/src/vulkan/uploader.rs +++ b/src/vulkan/uploader.rs @@ -1,38 +1,50 @@ use std::{mem::size_of, rc::Rc}; -use ash::{version::DeviceV1_0, vk}; +use ash::{extensions::khr, vk}; +use crystal::prelude::Mat4; +use gpu_allocator::{MemoryLocation, SubAllocation}; +use ve_format::mesh::Vertex; + +use super::allocator::Allocator; const DEFAULT_STAGING_BUFFER_SIZE: u64 = 16 * 1024 * 1024; struct StagingBuffer { buffer: vk::Buffer, - alloc: vk_mem::Allocation, + alloc: SubAllocation, mapping: *mut u8, pos: u64, size: u64, last_used_frame: u64, } +#[derive(Clone)] +struct ScratchBuffer { + buffer: vk::Buffer, + alloc: SubAllocation, +} + /// This struct automatically manages a pool of staging buffers that can be used to upload data to GPU-only buffers and images. /// /// # Notes /// This struct has to be cleaned up manually by calling [`destroy()`](Uploader::destroy()). pub struct Uploader { device: Rc, - allocator: Rc, + allocator: Rc, staging_buffers: Vec, frame_counter: u64, max_frames_ahead: u64, command_pool: vk::CommandPool, command_buffers: Vec, fences: Vec, + scratch_buffers: Vec>, } impl Uploader { /// Creates a new [`Uploader`]. pub fn new( device: Rc, - allocator: Rc, + allocator: Rc, max_frames_ahead: u64, queue_family: u32, ) -> Uploader { @@ -67,6 +79,7 @@ impl Uploader { command_pool, command_buffers, fences, + scratch_buffers: vec![vec![]; max_frames_ahead as usize], }; let command_buffer = res.command_buffers[0]; @@ -95,7 +108,6 @@ impl Uploader { } for buf in &self.staging_buffers { - self.allocator.unmap_memory(&buf.alloc); self.allocator.destroy_buffer(buf.buffer, &buf.alloc); } @@ -118,21 +130,12 @@ impl Uploader { // no staging buffer with enough capacity found, create a new one let new_size = size.max(DEFAULT_STAGING_BUFFER_SIZE); - let buffer_info = vk::BufferCreateInfo::builder() - .size(new_size) - .usage(vk::BufferUsageFlags::TRANSFER_SRC) - .sharing_mode(vk::SharingMode::EXCLUSIVE) - .build(); - let alloc_info = vk_mem::AllocationCreateInfo { - usage: vk_mem::MemoryUsage::CpuOnly, - ..Default::default() - }; - - let (buffer, alloc, _) = self - .allocator - .create_buffer(&buffer_info, &alloc_info) - .unwrap(); - let mapping = self.allocator.map_memory(&alloc).unwrap(); + let (buffer, alloc) = self.allocator.create_buffer( + new_size, + vk::BufferUsageFlags::TRANSFER_SRC, + MemoryLocation::CpuToGpu, + ); + let mapping = Allocator::get_ptr(&alloc) as *mut u8; self.staging_buffers.push(StagingBuffer { buffer, @@ -146,6 +149,289 @@ impl Uploader { self.staging_buffers.len() - 1 } + pub fn enqueue_scene_acc_struct_build( + &mut self, + rtx_ext: Rc, + objects: &[(vk::AccelerationStructureKHR, Mat4)], + ) -> (vk::AccelerationStructureKHR, vk::Buffer, SubAllocation) { + log::info!( + "Building Scene AccelerationStructure for {} objects", + objects.len() + ); + + let (staging_buffer, staging_buffer_alloc) = self.allocator.create_buffer( + (size_of::() * objects.len()) as u64, + vk::BufferUsageFlags::ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_KHR + | vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS, + MemoryLocation::CpuToGpu, + ); + let ptr = + Allocator::get_ptr(&staging_buffer_alloc) as *mut vk::AccelerationStructureInstanceKHR; + for (i, (acc, transform)) in objects.iter().enumerate() { + let acc_addr = unsafe { + rtx_ext.get_acceleration_structure_device_address( + &vk::AccelerationStructureDeviceAddressInfoKHR::builder() + .acceleration_structure(*acc) + .build(), + ) + }; + + unsafe { + ptr.add(i).write(vk::AccelerationStructureInstanceKHR { + transform: vk::TransformMatrixKHR { + matrix: [ + *transform.get_unchecked((0, 0)), + *transform.get_unchecked((0, 1)), + *transform.get_unchecked((0, 2)), + *transform.get_unchecked((0, 3)), + *transform.get_unchecked((1, 0)), + *transform.get_unchecked((1, 1)), + *transform.get_unchecked((1, 2)), + *transform.get_unchecked((1, 3)), + *transform.get_unchecked((2, 0)), + *transform.get_unchecked((2, 1)), + *transform.get_unchecked((2, 2)), + *transform.get_unchecked((2, 3)), + ], + }, + instance_custom_index_and_mask: 0xFF000000, + instance_shader_binding_table_record_offset_and_flags: 0, + acceleration_structure_reference: vk::AccelerationStructureReferenceKHR { + device_handle: acc_addr, + }, + }) + }; + } + let staging_buffer_addr = unsafe { + self.device.get_buffer_device_address( + &vk::BufferDeviceAddressInfo::builder() + .buffer(staging_buffer) + .build(), + ) + }; + + let geometries = [vk::AccelerationStructureGeometryKHR::builder() + .geometry_type(vk::GeometryTypeKHR::INSTANCES) + .geometry(vk::AccelerationStructureGeometryDataKHR { + instances: vk::AccelerationStructureGeometryInstancesDataKHR::builder() + .array_of_pointers(false) + .data(vk::DeviceOrHostAddressConstKHR { + device_address: staging_buffer_addr, + }) + .build(), + }) + .build()]; + let mut geometry_info = vk::AccelerationStructureBuildGeometryInfoKHR::builder() + .ty(vk::AccelerationStructureTypeKHR::TOP_LEVEL) + .mode(vk::BuildAccelerationStructureModeKHR::BUILD) + .geometries(&geometries) + .build(); + + let build_size = unsafe { + rtx_ext.get_acceleration_structure_build_sizes( + vk::AccelerationStructureBuildTypeKHR::DEVICE, + &geometry_info, + &[objects.len() as u32], + ) + }; + log::info!( + "AccelerationStructure needs {} bytes and {} bytes of scratch space", + build_size.acceleration_structure_size, + build_size.build_scratch_size + ); + + let (acc_buffer, acc_buffer_alloc) = self.allocator.create_buffer( + build_size.acceleration_structure_size, + vk::BufferUsageFlags::ACCELERATION_STRUCTURE_STORAGE_KHR, + MemoryLocation::GpuOnly, + ); + let (scratch_buffer, scratch_buffer_alloc) = self.allocator.create_buffer( + build_size.build_scratch_size, + vk::BufferUsageFlags::STORAGE_BUFFER | vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS, + MemoryLocation::GpuOnly, + ); + + let acc = unsafe { + rtx_ext + .create_acceleration_structure( + &vk::AccelerationStructureCreateInfoKHR::builder() + .buffer(acc_buffer) + .offset(0) + .size(build_size.acceleration_structure_size) + .ty(vk::AccelerationStructureTypeKHR::TOP_LEVEL) + .build(), + None, + ) + .unwrap() + }; + + let cmd = self.command_buffers[(self.frame_counter % self.max_frames_ahead) as usize]; + + unsafe { + geometry_info.scratch_data = vk::DeviceOrHostAddressKHR { + device_address: self.device.get_buffer_device_address( + &vk::BufferDeviceAddressInfo::builder() + .buffer(scratch_buffer) + .build(), + ), + }; + geometry_info.dst_acceleration_structure = acc; + + rtx_ext.cmd_build_acceleration_structures( + cmd, + &[geometry_info], + &[&[vk::AccelerationStructureBuildRangeInfoKHR::builder() + .primitive_count(objects.len() as u32) + .build()]], + ); + } + + self.scratch_buffers[(self.frame_counter % self.max_frames_ahead) as usize].push( + ScratchBuffer { + buffer: scratch_buffer, + alloc: scratch_buffer_alloc, + }, + ); + self.scratch_buffers[(self.frame_counter % self.max_frames_ahead) as usize].push( + ScratchBuffer { + buffer: staging_buffer, + alloc: staging_buffer_alloc, + }, + ); + + (acc, acc_buffer, acc_buffer_alloc) + } + + pub fn enqueue_acc_struct_build( + &mut self, + rtx_ext: Rc, + vertex_buffer: vk::Buffer, + index_buffer: vk::Buffer, + submeshes: &[(u32, u32)], + vertex_count: u32, + ) -> (vk::AccelerationStructureKHR, vk::Buffer, SubAllocation) { + log::info!( + "Building AccelerationStructure for mesh with {} submeshes", + submeshes.len() + ); + + let vertex_buffer_addr = unsafe { + self.device.get_buffer_device_address( + &vk::BufferDeviceAddressInfo::builder().buffer(vertex_buffer), + ) + }; + let index_buffer_addr = unsafe { + self.device.get_buffer_device_address( + &vk::BufferDeviceAddressInfo::builder().buffer(index_buffer), + ) + }; + + let geometries = [vk::AccelerationStructureGeometryKHR::builder() + .geometry_type(vk::GeometryTypeKHR::TRIANGLES) + .geometry(vk::AccelerationStructureGeometryDataKHR { + triangles: vk::AccelerationStructureGeometryTrianglesDataKHR::builder() + .vertex_format(vk::Format::R32G32B32_SFLOAT) + .vertex_data(vk::DeviceOrHostAddressConstKHR { + device_address: vertex_buffer_addr, + }) + .vertex_stride(size_of::() as u64) + .max_vertex(vertex_count - 1) + .index_type(vk::IndexType::UINT32) + .index_data(vk::DeviceOrHostAddressConstKHR { + device_address: index_buffer_addr, + }) + .build(), + }) + .build()]; + let mut geometry_info = vk::AccelerationStructureBuildGeometryInfoKHR::builder() + .ty(vk::AccelerationStructureTypeKHR::BOTTOM_LEVEL) + .mode(vk::BuildAccelerationStructureModeKHR::BUILD) + .geometries(&geometries) + .build(); + + let build_size = unsafe { + rtx_ext.get_acceleration_structure_build_sizes( + vk::AccelerationStructureBuildTypeKHR::DEVICE, + &geometry_info, + &[submeshes[0].1], + ) + }; + log::info!( + "AccelerationStructure needs {} bytes and {} bytes of scratch space", + build_size.acceleration_structure_size, + build_size.build_scratch_size + ); + + let (acc_buffer, acc_buffer_alloc) = self.allocator.create_buffer( + build_size.acceleration_structure_size, + vk::BufferUsageFlags::ACCELERATION_STRUCTURE_STORAGE_KHR, + MemoryLocation::GpuOnly, + ); + let (scratch_buffer, scratch_buffer_alloc) = self.allocator.create_buffer( + build_size.build_scratch_size, + vk::BufferUsageFlags::STORAGE_BUFFER | vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS, + MemoryLocation::GpuOnly, + ); + + let acc = unsafe { + rtx_ext + .create_acceleration_structure( + &vk::AccelerationStructureCreateInfoKHR::builder() + .buffer(acc_buffer) + .offset(0) + .size(build_size.acceleration_structure_size) + .ty(vk::AccelerationStructureTypeKHR::BOTTOM_LEVEL) + .build(), + None, + ) + .unwrap() + }; + + let cmd = self.command_buffers[(self.frame_counter % self.max_frames_ahead) as usize]; + + unsafe { + // wait for vertex/index buffer transfers + self.device.cmd_pipeline_barrier( + cmd, + vk::PipelineStageFlags::TRANSFER, + vk::PipelineStageFlags::ACCELERATION_STRUCTURE_BUILD_KHR, + vk::DependencyFlags::BY_REGION, + &[vk::MemoryBarrier::builder() + .src_access_mask(vk::AccessFlags::TRANSFER_WRITE) + .dst_access_mask(vk::AccessFlags::TRANSFER_READ) + .build()], + &[], + &[], + ); + + geometry_info.scratch_data = vk::DeviceOrHostAddressKHR { + device_address: self.device.get_buffer_device_address( + &vk::BufferDeviceAddressInfo::builder() + .buffer(scratch_buffer) + .build(), + ), + }; + geometry_info.dst_acceleration_structure = acc; + + rtx_ext.cmd_build_acceleration_structures( + cmd, + &[geometry_info], + &[&[vk::AccelerationStructureBuildRangeInfoKHR::builder() + .primitive_count(submeshes[0].1 / 3) + .build()]], + ); + } + + self.scratch_buffers[(self.frame_counter % self.max_frames_ahead) as usize].push( + ScratchBuffer { + buffer: scratch_buffer, + alloc: scratch_buffer_alloc, + }, + ); + + (acc, acc_buffer, acc_buffer_alloc) + } + /// Enqueues a buffer upload command. /// /// The data upload will happend before any other vulkan commands are executed this frame. @@ -303,12 +589,16 @@ impl Uploader { unsafe { let mem_barrier = vk::MemoryBarrier::builder() - .src_access_mask(vk::AccessFlags::TRANSFER_WRITE) + .src_access_mask( + vk::AccessFlags::TRANSFER_WRITE + | vk::AccessFlags::ACCELERATION_STRUCTURE_WRITE_KHR, + ) .dst_access_mask(vk::AccessFlags::empty()) .build(); self.device.cmd_pipeline_barrier( command_buffer, - vk::PipelineStageFlags::TRANSFER, + vk::PipelineStageFlags::TRANSFER + | vk::PipelineStageFlags::ACCELERATION_STRUCTURE_BUILD_KHR, vk::PipelineStageFlags::TOP_OF_PIPE, vk::DependencyFlags::BY_REGION, &[mem_barrier], @@ -353,5 +643,11 @@ impl Uploader { .begin_command_buffer(command_buffer, &begin_info) .unwrap(); } + + for sb in &self.scratch_buffers[(self.frame_counter % self.max_frames_ahead) as usize] { + log::info!("Destroying scratch buffer"); + self.allocator.destroy_buffer(sb.buffer, &sb.alloc); + } + self.scratch_buffers[(self.frame_counter % self.max_frames_ahead) as usize].clear(); } }