Compare commits
No commits in common. "migrate-to-vulkano" and "main" have entirely different histories.
migrate-to
...
main
43 changed files with 1920 additions and 1133 deletions
7
.vscode/extensions.json
vendored
7
.vscode/extensions.json
vendored
|
@ -1,7 +0,0 @@
|
||||||
{
|
|
||||||
"recommendations": [
|
|
||||||
"pinage404.rust-extension-pack",
|
|
||||||
"vadimcn.vscode-lldb",
|
|
||||||
"jnoortheen.nix-ide"
|
|
||||||
]
|
|
||||||
}
|
|
45
.vscode/launch.json
vendored
45
.vscode/launch.json
vendored
|
@ -1,45 +0,0 @@
|
||||||
{
|
|
||||||
// Use IntelliSense to learn about possible attributes.
|
|
||||||
// Hover to view descriptions of existing attributes.
|
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
||||||
"version": "0.2.0",
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"type": "lldb",
|
|
||||||
"request": "launch",
|
|
||||||
"name": "Debug executable 'rust_vulkan_test'",
|
|
||||||
"cargo": {
|
|
||||||
"args": [
|
|
||||||
"build",
|
|
||||||
"--bin=rust_vulkan_test",
|
|
||||||
"--package=rust_vulkan_test"
|
|
||||||
],
|
|
||||||
"filter": {
|
|
||||||
"name": "rust_vulkan_test",
|
|
||||||
"kind": "bin"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"args": [],
|
|
||||||
"cwd": "${workspaceFolder}"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "lldb",
|
|
||||||
"request": "launch",
|
|
||||||
"name": "Debug unit tests in executable 'rust_vulkan_test'",
|
|
||||||
"cargo": {
|
|
||||||
"args": [
|
|
||||||
"test",
|
|
||||||
"--no-run",
|
|
||||||
"--bin=rust_vulkan_test",
|
|
||||||
"--package=rust_vulkan_test"
|
|
||||||
],
|
|
||||||
"filter": {
|
|
||||||
"name": "rust_vulkan_test",
|
|
||||||
"kind": "bin"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"args": [],
|
|
||||||
"cwd": "${workspaceFolder}"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
11
.vscode/settings.json
vendored
11
.vscode/settings.json
vendored
|
@ -1,11 +0,0 @@
|
||||||
{
|
|
||||||
"editor.formatOnSave": true,
|
|
||||||
"editor.codeActionsOnSave": {
|
|
||||||
"source.organizeImports": "always",
|
|
||||||
},
|
|
||||||
"[rust]": {
|
|
||||||
"editor.defaultFormatter": "rust-lang.rust-analyzer",
|
|
||||||
},
|
|
||||||
"files.insertFinalNewline": true,
|
|
||||||
"files.trimTrailingWhitespace": true
|
|
||||||
}
|
|
461
Cargo.lock
generated
461
Cargo.lock
generated
|
@ -118,9 +118,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.94"
|
version = "1.0.93"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7"
|
checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrayref"
|
name = "arrayref"
|
||||||
|
@ -145,8 +145,16 @@ name = "ash"
|
||||||
version = "0.38.0+1.3.281"
|
version = "0.38.0+1.3.281"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f"
|
checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ash-window"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "52bca67b61cb81e5553babde81b8211f713cb6db79766f80168f3e5f40ea6c82"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libloading",
|
"ash",
|
||||||
|
"raw-window-handle",
|
||||||
|
"raw-window-metal",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -173,6 +181,12 @@ version = "2.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "block2"
|
name = "block2"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
|
@ -190,29 +204,15 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytemuck"
|
name = "bytemuck"
|
||||||
version = "1.20.0"
|
version = "1.19.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a"
|
checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d"
|
||||||
dependencies = [
|
|
||||||
"bytemuck_derive",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bytemuck_derive"
|
|
||||||
version = "1.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
version = "1.9.0"
|
version = "1.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
|
checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "calloop"
|
name = "calloop"
|
||||||
|
@ -242,9 +242,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.4"
|
version = "1.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf"
|
checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jobserver",
|
"jobserver",
|
||||||
"libc",
|
"libc",
|
||||||
|
@ -270,12 +270,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cmake"
|
name = "cocoa"
|
||||||
version = "0.1.52"
|
version = "0.25.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c682c223677e0e5b6b7f63a64b9351844c3f1b1678a68b7ee617e30fb082620e"
|
checksum = "f6140449f97a6e97f9511815c5632d84c8aacf8ac271ad77c559218161a1373c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"bitflags 1.3.2",
|
||||||
|
"block",
|
||||||
|
"cocoa-foundation",
|
||||||
|
"core-foundation",
|
||||||
|
"core-graphics",
|
||||||
|
"foreign-types",
|
||||||
|
"libc",
|
||||||
|
"objc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cocoa-foundation"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"block",
|
||||||
|
"core-foundation",
|
||||||
|
"core-graphics-types",
|
||||||
|
"libc",
|
||||||
|
"objc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -343,26 +364,11 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-queue"
|
|
||||||
version = "0.3.12"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-utils",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-utils"
|
name = "crossbeam-utils"
|
||||||
version = "0.8.21"
|
version = "0.8.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crunchy"
|
|
||||||
version = "0.2.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cursor-icon"
|
name = "cursor-icon"
|
||||||
|
@ -428,20 +434,14 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "errno"
|
name = "errno"
|
||||||
version = "0.3.10"
|
version = "0.3.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
|
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "foldhash"
|
|
||||||
version = "0.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "foreign-types"
|
name = "foreign-types"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
|
@ -491,33 +491,16 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glam"
|
name = "glob"
|
||||||
version = "0.29.2"
|
version = "0.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dc46dd3ec48fdd8e693a98d2b8bafae273a2d54c1de02a2a7e3d57d501f39677"
|
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "half"
|
|
||||||
version = "2.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888"
|
|
||||||
dependencies = [
|
|
||||||
"bytemuck",
|
|
||||||
"cfg-if",
|
|
||||||
"crunchy",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.15.2"
|
version = "0.15.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "heck"
|
|
||||||
version = "0.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
|
@ -533,9 +516,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.7.0"
|
version = "2.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
|
checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
|
@ -547,12 +530,6 @@ version = "1.70.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "itoa"
|
|
||||||
version = "1.0.14"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jni"
|
name = "jni"
|
||||||
version = "0.21.1"
|
version = "0.21.1"
|
||||||
|
@ -586,25 +563,24 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.76"
|
version = "0.3.72"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7"
|
checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.168"
|
version = "0.2.164"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d"
|
checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libloading"
|
name = "libloading"
|
||||||
version = "0.8.6"
|
version = "0.8.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
|
checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
|
@ -618,7 +594,7 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"libc",
|
"libc",
|
||||||
"redox_syscall 0.5.8",
|
"redox_syscall 0.5.7",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -627,22 +603,21 @@ version = "0.4.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
|
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lock_api"
|
|
||||||
version = "0.4.12"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"scopeguard",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.22"
|
version = "0.4.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "malloc_buf"
|
||||||
|
version = "0.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.7.4"
|
version = "2.7.4"
|
||||||
|
@ -658,12 +633,6 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "minimal-lexical"
|
|
||||||
version = "0.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ndk"
|
name = "ndk"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
|
@ -694,16 +663,6 @@ dependencies = [
|
||||||
"jni-sys",
|
"jni-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nom"
|
|
||||||
version = "7.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
"minimal-lexical",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_enum"
|
name = "num_enum"
|
||||||
version = "0.7.3"
|
version = "0.7.3"
|
||||||
|
@ -725,6 +684,15 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "objc"
|
||||||
|
version = "0.2.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
|
||||||
|
dependencies = [
|
||||||
|
"malloc_buf",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objc-sys"
|
name = "objc-sys"
|
||||||
version = "0.3.5"
|
version = "0.3.5"
|
||||||
|
@ -952,29 +920,6 @@ dependencies = [
|
||||||
"ttf-parser",
|
"ttf-parser",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "parking_lot"
|
|
||||||
version = "0.12.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
|
|
||||||
dependencies = [
|
|
||||||
"lock_api",
|
|
||||||
"parking_lot_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "parking_lot_core"
|
|
||||||
version = "0.9.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"libc",
|
|
||||||
"redox_syscall 0.5.8",
|
|
||||||
"smallvec",
|
|
||||||
"windows-targets 0.52.6",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "percent-encoding"
|
name = "percent-encoding"
|
||||||
version = "2.3.1"
|
version = "2.3.1"
|
||||||
|
@ -1039,9 +984,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.92"
|
version = "1.0.89"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
|
checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
@ -1072,13 +1017,14 @@ checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "raw-window-metal"
|
name = "raw-window-metal"
|
||||||
version = "1.0.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b2000e45d7daa9b6d946e88dfa1d7ae330424a81918a6545741821c989eb80a9"
|
checksum = "76e8caa82e31bb98fee12fa8f051c94a6aa36b07cddb03f0d4fc558988360ff1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"objc2",
|
"cocoa",
|
||||||
"objc2-foundation",
|
"core-graphics",
|
||||||
"objc2-quartz-core",
|
"objc",
|
||||||
|
"raw-window-handle",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1092,9 +1038,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.5.8"
|
version = "0.5.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
|
checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
]
|
]
|
||||||
|
@ -1128,47 +1074,32 @@ version = "0.8.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "roxmltree"
|
|
||||||
version = "0.14.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "921904a62e410e37e215c40381b7117f830d9d89ba60ab5236170541dd25646b"
|
|
||||||
dependencies = [
|
|
||||||
"xmlparser",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rust_vulkan_test"
|
name = "rust_vulkan_test"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"ash",
|
||||||
|
"ash-window",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"glam",
|
"glob",
|
||||||
"log",
|
"log",
|
||||||
"vulkano",
|
|
||||||
"vulkano-shaders",
|
|
||||||
"winit",
|
"winit",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.38.42"
|
version = "0.38.40"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85"
|
checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"errno",
|
"errno",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys",
|
"linux-raw-sys",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ryu"
|
|
||||||
version = "1.0.18"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "same-file"
|
name = "same-file"
|
||||||
version = "1.0.6"
|
version = "1.0.6"
|
||||||
|
@ -1184,12 +1115,6 @@ version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
|
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "scopeguard"
|
|
||||||
version = "1.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sctk-adwaita"
|
name = "sctk-adwaita"
|
||||||
version = "0.10.1"
|
version = "0.10.1"
|
||||||
|
@ -1205,57 +1130,24 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.216"
|
version = "1.0.215"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e"
|
checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.216"
|
version = "1.0.215"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e"
|
checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde_json"
|
|
||||||
version = "1.0.133"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377"
|
|
||||||
dependencies = [
|
|
||||||
"itoa",
|
|
||||||
"memchr",
|
|
||||||
"ryu",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "shaderc"
|
|
||||||
version = "0.8.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "27e07913ada18607bb60d12431cbe3358d3bbebbe95948e1618851dc01e63b7b"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"shaderc-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "shaderc-sys"
|
|
||||||
version = "0.8.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "73120d240fe22196300f39ca8547ca2d014960f27b19b47b21288b396272f7f7"
|
|
||||||
dependencies = [
|
|
||||||
"cmake",
|
|
||||||
"libc",
|
|
||||||
"roxmltree",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shlex"
|
name = "shlex"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
|
@ -1271,12 +1163,6 @@ dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "slabbin"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1fd33b7a607dbd960b5e78bb4740d1f86e84250eb03a12960ee1482c2a256063"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smallvec"
|
name = "smallvec"
|
||||||
version = "1.13.2"
|
version = "1.13.2"
|
||||||
|
@ -1325,9 +1211,9 @@ checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.90"
|
version = "2.0.87"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
|
checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -1354,16 +1240,6 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "thread_local"
|
|
||||||
version = "1.1.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"once_cell",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tiny-skia"
|
name = "tiny-skia"
|
||||||
version = "0.11.4"
|
version = "0.11.4"
|
||||||
|
@ -1408,9 +1284,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing"
|
name = "tracing"
|
||||||
version = "0.1.41"
|
version = "0.1.40"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
|
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"tracing-core",
|
"tracing-core",
|
||||||
|
@ -1418,21 +1294,21 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing-core"
|
name = "tracing-core"
|
||||||
version = "0.1.33"
|
version = "0.1.32"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
|
checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ttf-parser"
|
name = "ttf-parser"
|
||||||
version = "0.25.1"
|
version = "0.25.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31"
|
checksum = "5902c5d130972a0000f60860bfbf46f7ca3db5391eddfedd1b8728bd9dc96c0e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.14"
|
version = "1.0.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
|
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-segmentation"
|
name = "unicode-segmentation"
|
||||||
|
@ -1452,71 +1328,6 @@ version = "0.9.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "vk-parse"
|
|
||||||
version = "0.15.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3859da4d7b98bec73e68fb65815d47a263819c415c90eed42b80440a02cbce8c"
|
|
||||||
dependencies = [
|
|
||||||
"xml-rs",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "vulkano"
|
|
||||||
version = "0.34.0"
|
|
||||||
source = "git+https://github.com/vulkano-rs/vulkano.git?branch=master#ea30f65280360b1e1bc907cd42d4eb355fed3c9d"
|
|
||||||
dependencies = [
|
|
||||||
"ash",
|
|
||||||
"bytemuck",
|
|
||||||
"crossbeam-queue",
|
|
||||||
"foldhash",
|
|
||||||
"half",
|
|
||||||
"heck",
|
|
||||||
"indexmap",
|
|
||||||
"libloading",
|
|
||||||
"nom",
|
|
||||||
"once_cell",
|
|
||||||
"parking_lot",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"raw-window-handle",
|
|
||||||
"raw-window-metal",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"slabbin",
|
|
||||||
"smallvec",
|
|
||||||
"thread_local",
|
|
||||||
"vk-parse",
|
|
||||||
"vulkano-macros",
|
|
||||||
"x11-dl",
|
|
||||||
"x11rb",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "vulkano-macros"
|
|
||||||
version = "0.34.0"
|
|
||||||
source = "git+https://github.com/vulkano-rs/vulkano.git?branch=master#ea30f65280360b1e1bc907cd42d4eb355fed3c9d"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro-crate",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "vulkano-shaders"
|
|
||||||
version = "0.34.0"
|
|
||||||
source = "git+https://github.com/vulkano-rs/vulkano.git?branch=master#ea30f65280360b1e1bc907cd42d4eb355fed3c9d"
|
|
||||||
dependencies = [
|
|
||||||
"foldhash",
|
|
||||||
"heck",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"shaderc",
|
|
||||||
"syn",
|
|
||||||
"vulkano",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "walkdir"
|
name = "walkdir"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
|
@ -1535,9 +1346,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.99"
|
version = "0.2.95"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396"
|
checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
@ -1546,12 +1357,13 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-backend"
|
name = "wasm-bindgen-backend"
|
||||||
version = "0.2.99"
|
version = "0.2.95"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79"
|
checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"log",
|
"log",
|
||||||
|
"once_cell",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn",
|
||||||
|
@ -1560,22 +1372,21 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-futures"
|
name = "wasm-bindgen-futures"
|
||||||
version = "0.4.49"
|
version = "0.4.45"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2"
|
checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"once_cell",
|
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro"
|
name = "wasm-bindgen-macro"
|
||||||
version = "0.2.99"
|
version = "0.2.95"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe"
|
checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"wasm-bindgen-macro-support",
|
"wasm-bindgen-macro-support",
|
||||||
|
@ -1583,9 +1394,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro-support"
|
name = "wasm-bindgen-macro-support"
|
||||||
version = "0.2.99"
|
version = "0.2.95"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2"
|
checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -1596,9 +1407,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-shared"
|
name = "wasm-bindgen-shared"
|
||||||
version = "0.2.99"
|
version = "0.2.95"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6"
|
checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wayland-backend"
|
name = "wayland-backend"
|
||||||
|
@ -1711,9 +1522,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "web-sys"
|
name = "web-sys"
|
||||||
version = "0.3.76"
|
version = "0.3.72"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc"
|
checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
|
@ -2061,18 +1872,6 @@ version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56"
|
checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "xml-rs"
|
|
||||||
version = "0.8.24"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ea8b391c9a790b496184c29f7f93b9ed5b16abb306c05415b68bcc16e4d06432"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "xmlparser"
|
|
||||||
version = "0.13.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
version = "0.7.35"
|
version = "0.7.35"
|
||||||
|
|
11
Cargo.toml
11
Cargo.toml
|
@ -8,13 +8,12 @@ publish = false
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
winit = { version = "0.30", features = ["rwh_06"] }
|
winit = { version = "0.30", features = ["rwh_06"] }
|
||||||
|
ash = { version = "0.38", default-features = false, features = ["linked", "debug", "std"] }
|
||||||
vulkano = { git = "https://github.com/vulkano-rs/vulkano.git", branch = "master" }
|
ash-window = "0.13"
|
||||||
vulkano-shaders = { git = "https://github.com/vulkano-rs/vulkano.git", branch = "master" }
|
|
||||||
|
|
||||||
# Math
|
|
||||||
glam = { version = "0.29" }
|
|
||||||
|
|
||||||
# Log and tracing
|
# Log and tracing
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
env_logger = "0.11.5"
|
env_logger = "0.11.5"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
glob = "0.3"
|
24
build.rs
Normal file
24
build.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
for shader in glob::glob("res/shaders/*").unwrap().filter_map(Result::ok) {
|
||||||
|
if !shader.is_file() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let shader_file_name = shader.to_str().unwrap();
|
||||||
|
|
||||||
|
let mut command = Command::new("glslc");
|
||||||
|
command.arg(&shader);
|
||||||
|
|
||||||
|
let out_file = match shader.extension().unwrap().to_str().unwrap() {
|
||||||
|
"vert" => shader_file_name.replace(".vert", ".vert.spv"),
|
||||||
|
"frag" => shader_file_name.replace(".frag", ".frag.spv"),
|
||||||
|
_ => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
command.arg("-o");
|
||||||
|
command.arg(out_file);
|
||||||
|
command.output().unwrap();
|
||||||
|
}
|
||||||
|
}
|
37
flake.nix
37
flake.nix
|
@ -30,34 +30,24 @@
|
||||||
cargo = rust;
|
cargo = rust;
|
||||||
});
|
});
|
||||||
|
|
||||||
buildInputs = with pkgs; [ vulkan-headers vulkan-loader vulkan-validation-layers ]
|
libs = with pkgs; [ vulkan-headers vulkan-loader vulkan-validation-layers ]
|
||||||
++ pkgs.lib.optionals pkgs.stdenv.hostPlatform.isLinux (with pkgs; [ libxkbcommon wayland libGL ])
|
++ pkgs.lib.optionals pkgs.stdenv.hostPlatform.isLinux (with pkgs; [ libxkbcommon wayland libGL ])
|
||||||
++ pkgs.lib.optionals pkgs.stdenv.hostPlatform.isDarwin (with pkgs; [ darwin.apple_sdk.frameworks.SystemConfiguration ]);
|
++ pkgs.lib.optionals pkgs.stdenv.hostPlatform.isDarwin (with pkgs; [ darwin.apple_sdk.frameworks.SystemConfiguration ]);
|
||||||
|
|
||||||
nativeBuildInputs = with pkgs; [
|
|
||||||
pkg-config
|
|
||||||
cmake
|
|
||||||
python312
|
|
||||||
];
|
|
||||||
|
|
||||||
mkRustVulkanShell = { nixGLSupport ? true }: pkgs.mkShell {
|
|
||||||
nativeBuildInputs = with pkgs; [
|
|
||||||
(rust.override { extensions = ["rust-src" "rust-analyzer"]; })
|
|
||||||
] ++ nativeBuildInputs;
|
|
||||||
|
|
||||||
buildInputs = buildInputs
|
|
||||||
++ pkgs.lib.optionals nixGLSupport [ pkgs.nixgl.auto.nixVulkanNvidia pkgs.nixgl.nixVulkanIntel ];
|
|
||||||
|
|
||||||
LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath buildInputs;
|
|
||||||
VK_LAYER_PATH = "${pkgs.vulkan-validation-layers}/share/vulkan/explicit_layer.d";
|
|
||||||
};
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
devShells = {
|
devShells = {
|
||||||
default = mkRustVulkanShell {};
|
default = pkgs.mkShell {
|
||||||
|
nativeBuildInputs = with pkgs; [
|
||||||
|
(rust.override { extensions = ["rust-src" "rust-analyzer"]; })
|
||||||
|
pkg-config
|
||||||
|
];
|
||||||
|
|
||||||
# Crash with error: cannot coerce null to a string: null
|
buildInputs = libs ++ [
|
||||||
nixos = mkRustVulkanShell { nixGLSupport = false; };
|
pkgs.nixgl.auto.nixVulkanNvidia pkgs.nixgl.nixVulkanIntel
|
||||||
|
];
|
||||||
|
|
||||||
|
LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath (with pkgs; [ libxkbcommon wayland libGL ]);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
packages = {
|
packages = {
|
||||||
|
@ -67,7 +57,8 @@
|
||||||
|
|
||||||
src = self;
|
src = self;
|
||||||
|
|
||||||
inherit nativeBuildInputs buildInputs;
|
nativeBuildInputs = with pkgs; [ pkg-config shaderc ];
|
||||||
|
buildInputs = libs;
|
||||||
|
|
||||||
cargoLock = {
|
cargoLock = {
|
||||||
lockFile = ./Cargo.lock;
|
lockFile = ./Cargo.lock;
|
||||||
|
|
8
res/shaders/main.frag
Normal file
8
res/shaders/main.frag
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
layout (location = 0) in vec3 fragColor;
|
||||||
|
layout (location = 0) out vec4 outColor;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
outColor = vec4(fragColor, 1.0);
|
||||||
|
}
|
1
res/shaders/main.vert
Normal file
1
res/shaders/main.vert
Normal file
|
@ -0,0 +1 @@
|
||||||
|
#version 450
out gl_PerVertex {
vec4 gl_Position;
};
layout (location = 0) out vec3 fragColor;
vec2 positions[3] = vec2[](
vec2(0.0, -0.5),
vec2(0.5, 0.5),
vec2(-0.5, 0.5)
);
vec3 colors[3] = vec3[](
vec3(1.0, 0.0, 0.0),
vec3(0.0, 1.0, 0.0),
vec3(0.0, 0.0, 1.0)
);
void main() {
gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
fragColor = colors[gl_VertexIndex];
}
|
|
@ -1,9 +1,10 @@
|
||||||
#version 450
|
#version 450
|
||||||
|
#extension GL_ARB_separate_shader_objects: enable
|
||||||
|
|
||||||
layout (location = 0) in vec3 color;
|
layout (location = 0) in vec3 fragColor;
|
||||||
|
|
||||||
layout (location = 0) out vec4 f_color;
|
layout (location = 0) out vec4 outColor;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
f_color = vec4(color, 1.0);
|
outColor = vec4(fragColor, 1.0);
|
||||||
}
|
}
|
|
@ -1 +1 @@
|
||||||
#version 450
layout (location = 0) in vec2 position;
layout (location = 1) in vec3 color;
layout (location = 0) out vec3 fragColor;
layout (set = 0, binding = 0) uniform MVPData {
mat4 world;
mat4 view;
mat4 projection;
} uniforms;
void main() {
gl_Position = uniforms.projection * worldview * vec4(position, 0.0, 1.0);
fragColor = color;
}
|
#version 450
layout (location = 1) in vec3 color;
// NOTE: names must match the `Vertex` struct in Rust
layout (location = 0) in vec2 pos;
layout (location = 1) in vec3 color;
layout (location = 0) out vec3 fragColor;
mat4 world;
mat4 view;
mat4 projection;
void main() {
} uniforms;
, 0.0, 1.0);
fragColor = color;
}
|
93
src/display/app.rs
Normal file
93
src/display/app.rs
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
use crate::display::window::Window;
|
||||||
|
use crate::renderer::{vulkan::VkRenderContext, Renderable};
|
||||||
|
use winit::application::ApplicationHandler;
|
||||||
|
use winit::event::WindowEvent;
|
||||||
|
use winit::event_loop::ActiveEventLoop;
|
||||||
|
use winit::window::WindowId;
|
||||||
|
use crate::scene::TriangleScene;
|
||||||
|
|
||||||
|
pub struct App {
|
||||||
|
window: Window,
|
||||||
|
render_context: Option<VkRenderContext>,
|
||||||
|
scene: Option<Box<dyn Renderable>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl App {
|
||||||
|
pub fn new(window: Window) -> Self {
|
||||||
|
Self {
|
||||||
|
window,
|
||||||
|
render_context: None,
|
||||||
|
scene: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_scene(&mut self, mut scene: Box<dyn Renderable>) {
|
||||||
|
let result = self.render_context.as_mut()
|
||||||
|
.ok_or_else(|| anyhow::anyhow!("No render context"))
|
||||||
|
.and_then(|render_context| render_context.init_scene(&mut scene));
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(_) => self.scene = Some(scene),
|
||||||
|
Err(err) => log::warn!("{err}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ApplicationHandler for App {
|
||||||
|
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
|
||||||
|
self.window
|
||||||
|
.create_window(event_loop)
|
||||||
|
.map_err(|err| format!("Failed to create window: {}", err))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
self.render_context = VkRenderContext::init(&self.window).ok();
|
||||||
|
|
||||||
|
let scene = TriangleScene::new();
|
||||||
|
self.set_scene(Box::new(scene));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn window_event(&mut self, event_loop: &ActiveEventLoop, _id: WindowId, event: WindowEvent) {
|
||||||
|
match event {
|
||||||
|
WindowEvent::CloseRequested => {
|
||||||
|
match self.render_context.as_ref() {
|
||||||
|
Some(render_context) => render_context.exit(),
|
||||||
|
None => log::warn!("Window closed but no render context found"),
|
||||||
|
};
|
||||||
|
|
||||||
|
log::debug!("The close button was pressed; stopping");
|
||||||
|
event_loop.exit();
|
||||||
|
}
|
||||||
|
WindowEvent::Resized(size) => {
|
||||||
|
match self.render_context.as_mut() {
|
||||||
|
Some(render_context) => {
|
||||||
|
if let Err(error) =
|
||||||
|
render_context.update_resolution(size.width, size.height)
|
||||||
|
{
|
||||||
|
log::error!(
|
||||||
|
"Failed to update resolution of render context : {}",
|
||||||
|
error
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => log::warn!("Window resized but no render context found"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
WindowEvent::RedrawRequested => {
|
||||||
|
if !event_loop.exiting() {
|
||||||
|
match self.render_context.as_mut() {
|
||||||
|
Some(render_context) => {
|
||||||
|
if let Err(error) = render_context.render(self.scene.as_ref()) {
|
||||||
|
log::error!("Failed to render with render context : {}", error);
|
||||||
|
event_loop.exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => log::warn!("Window resized but no render context found"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
self.window.request_redraw();
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
5
src/display/mod.rs
Normal file
5
src/display/mod.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
mod app;
|
||||||
|
mod window;
|
||||||
|
|
||||||
|
pub use app::App;
|
||||||
|
pub use window::Window;
|
65
src/display/window.rs
Normal file
65
src/display/window.rs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
use std::ffi::c_char;
|
||||||
|
use winit::dpi::Pixel;
|
||||||
|
use winit::event_loop::ActiveEventLoop;
|
||||||
|
use winit::raw_window_handle::HasDisplayHandle;
|
||||||
|
|
||||||
|
pub struct Window {
|
||||||
|
handle: Option<winit::window::Window>,
|
||||||
|
window_attributes: winit::window::WindowAttributes,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Window {
|
||||||
|
pub fn new(window_attributes: winit::window::WindowAttributes) -> Self {
|
||||||
|
Self {
|
||||||
|
handle: None,
|
||||||
|
window_attributes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_window(&mut self, event_loop: &ActiveEventLoop) -> anyhow::Result<()> {
|
||||||
|
let window = event_loop.create_window(self.window_attributes.clone())?;
|
||||||
|
|
||||||
|
self.handle = Some(window);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn required_extensions(&self) -> anyhow::Result<Vec<*const c_char>> {
|
||||||
|
let display_handle = self
|
||||||
|
.handle
|
||||||
|
.as_ref()
|
||||||
|
.ok_or_else(|| anyhow::anyhow!("Window not found"))?
|
||||||
|
.display_handle()?;
|
||||||
|
|
||||||
|
#[allow(unused_mut)]
|
||||||
|
let mut extension_names =
|
||||||
|
ash_window::enumerate_required_extensions(display_handle.as_raw())?.to_vec();
|
||||||
|
|
||||||
|
// TODO: Move this because is not related to Window extensions
|
||||||
|
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||||
|
{
|
||||||
|
extension_names.push(ash::khr::portability_enumeration::NAME.as_ptr());
|
||||||
|
// Enabling this extension is a requirement when using `VK_KHR_portability_subset`
|
||||||
|
extension_names.push(ash::khr::get_physical_device_properties2::NAME.as_ptr());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(extension_names)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle(&self) -> Option<&winit::window::Window> {
|
||||||
|
self.handle.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn physical_size<P: Pixel>(&self) -> Option<winit::dpi::PhysicalSize<P>> {
|
||||||
|
self.window_attributes
|
||||||
|
.inner_size
|
||||||
|
.and_then(|size| Some(size.to_physical::<P>(1.0)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn request_redraw(&self) {
|
||||||
|
match self.handle.as_ref() {
|
||||||
|
Some(window) => window.request_redraw(),
|
||||||
|
None => log::warn!("Redraw requested but no window found"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
src/main.rs
17
src/main.rs
|
@ -1,15 +1,24 @@
|
||||||
use std::error::Error;
|
|
||||||
use winit::event_loop::{ControlFlow, EventLoop};
|
use winit::event_loop::{ControlFlow, EventLoop};
|
||||||
|
|
||||||
|
mod display;
|
||||||
mod renderer;
|
mod renderer;
|
||||||
|
mod scene;
|
||||||
|
|
||||||
fn main() -> Result<(), impl Error> {
|
fn main() {
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
|
|
||||||
let event_loop = EventLoop::new().unwrap();
|
let event_loop = EventLoop::new().unwrap();
|
||||||
event_loop.set_control_flow(ControlFlow::Poll);
|
event_loop.set_control_flow(ControlFlow::Poll);
|
||||||
|
|
||||||
let mut app = renderer::App::new(&event_loop);
|
let window_attributes = winit::window::Window::default_attributes()
|
||||||
|
.with_title("Rust ASH Test")
|
||||||
|
.with_inner_size(winit::dpi::PhysicalSize::new(
|
||||||
|
f64::from(800),
|
||||||
|
f64::from(600),
|
||||||
|
));
|
||||||
|
|
||||||
event_loop.run_app(&mut app)
|
let window = display::Window::new(window_attributes);
|
||||||
|
let mut app = display::App::new(window);
|
||||||
|
|
||||||
|
event_loop.run_app(&mut app).unwrap();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,291 +0,0 @@
|
||||||
use crate::renderer::render_context::RenderContext;
|
|
||||||
use crate::renderer::Scene;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use vulkano::buffer::allocator::{SubbufferAllocator, SubbufferAllocatorCreateInfo};
|
|
||||||
use vulkano::buffer::BufferUsage;
|
|
||||||
use vulkano::command_buffer::allocator::StandardCommandBufferAllocator;
|
|
||||||
use vulkano::command_buffer::{
|
|
||||||
AutoCommandBufferBuilder, CommandBufferUsage, RenderingAttachmentInfo, RenderingInfo,
|
|
||||||
};
|
|
||||||
use vulkano::descriptor_set::allocator::StandardDescriptorSetAllocator;
|
|
||||||
use vulkano::device::physical::PhysicalDeviceType;
|
|
||||||
use vulkano::device::{
|
|
||||||
Device, DeviceCreateInfo, DeviceExtensions, DeviceFeatures, Queue, QueueCreateInfo, QueueFlags,
|
|
||||||
};
|
|
||||||
use vulkano::instance::{Instance, InstanceCreateFlags, InstanceCreateInfo};
|
|
||||||
use vulkano::memory::allocator::{MemoryTypeFilter, StandardMemoryAllocator};
|
|
||||||
use vulkano::render_pass::{AttachmentLoadOp, AttachmentStoreOp};
|
|
||||||
use vulkano::swapchain::{acquire_next_image, Surface, SwapchainPresentInfo};
|
|
||||||
use vulkano::sync::GpuFuture;
|
|
||||||
use vulkano::{sync, Validated, Version, VulkanError, VulkanLibrary};
|
|
||||||
use winit::application::ApplicationHandler;
|
|
||||||
use winit::event::WindowEvent;
|
|
||||||
use winit::event_loop::{ActiveEventLoop, EventLoop};
|
|
||||||
use winit::window::WindowId;
|
|
||||||
|
|
||||||
pub struct App {
|
|
||||||
pub instance: Arc<Instance>,
|
|
||||||
pub device: Arc<Device>,
|
|
||||||
pub queue: Arc<Queue>,
|
|
||||||
|
|
||||||
pub memory_allocator: Arc<StandardMemoryAllocator>,
|
|
||||||
pub command_buffer_allocator: Arc<StandardCommandBufferAllocator>,
|
|
||||||
pub uniform_buffer_allocator: SubbufferAllocator,
|
|
||||||
pub descriptor_set_allocator: Arc<StandardDescriptorSetAllocator>,
|
|
||||||
|
|
||||||
pub rcx: Option<RenderContext>,
|
|
||||||
scene: Option<Scene>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl App {
|
|
||||||
pub fn new(event_loop: &EventLoop<()>) -> Self {
|
|
||||||
let library = VulkanLibrary::new().unwrap();
|
|
||||||
|
|
||||||
let required_extensions = Surface::required_extensions(event_loop).unwrap();
|
|
||||||
|
|
||||||
let instance = Instance::new(
|
|
||||||
library,
|
|
||||||
InstanceCreateInfo {
|
|
||||||
// Enable enumerating devices that use non-conformant Vulkan implementations.
|
|
||||||
// (e.g. MoltenVK)
|
|
||||||
flags: InstanceCreateFlags::ENUMERATE_PORTABILITY,
|
|
||||||
enabled_extensions: required_extensions,
|
|
||||||
enabled_layers: vec![
|
|
||||||
String::from("VK_LAYER_KHRONOS_validation"),
|
|
||||||
],
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let mut device_extensions = DeviceExtensions {
|
|
||||||
khr_swapchain: true,
|
|
||||||
..DeviceExtensions::empty()
|
|
||||||
};
|
|
||||||
|
|
||||||
let (physical_device, queue_family_index) = instance
|
|
||||||
.enumerate_physical_devices()
|
|
||||||
.unwrap()
|
|
||||||
.filter(|p| {
|
|
||||||
p.api_version() >= Version::V1_3 || p.supported_extensions().khr_dynamic_rendering
|
|
||||||
})
|
|
||||||
.filter(|p| p.supported_extensions().contains(&device_extensions))
|
|
||||||
.filter_map(|p| {
|
|
||||||
p.queue_family_properties()
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.position(|(i, q)| {
|
|
||||||
q.queue_flags.intersects(QueueFlags::GRAPHICS)
|
|
||||||
&& p.presentation_support(i as u32, event_loop).unwrap()
|
|
||||||
})
|
|
||||||
.map(|i| (p, i as u32))
|
|
||||||
})
|
|
||||||
.min_by_key(|(p, _)| match p.properties().device_type {
|
|
||||||
PhysicalDeviceType::DiscreteGpu => 0,
|
|
||||||
PhysicalDeviceType::IntegratedGpu => 1,
|
|
||||||
PhysicalDeviceType::VirtualGpu => 2,
|
|
||||||
PhysicalDeviceType::Cpu => 3,
|
|
||||||
PhysicalDeviceType::Other => 4,
|
|
||||||
_ => 5,
|
|
||||||
})
|
|
||||||
.expect("no suitable physical device found");
|
|
||||||
|
|
||||||
println!(
|
|
||||||
"Using device: {} (type: {:?})",
|
|
||||||
physical_device.properties().device_name,
|
|
||||||
physical_device.properties().device_type,
|
|
||||||
);
|
|
||||||
|
|
||||||
if physical_device.api_version() < Version::V1_3 {
|
|
||||||
device_extensions.khr_dynamic_rendering = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
let (device, mut queues) = Device::new(
|
|
||||||
physical_device,
|
|
||||||
DeviceCreateInfo {
|
|
||||||
queue_create_infos: vec![QueueCreateInfo {
|
|
||||||
queue_family_index,
|
|
||||||
..Default::default()
|
|
||||||
}],
|
|
||||||
enabled_extensions: device_extensions,
|
|
||||||
enabled_features: DeviceFeatures {
|
|
||||||
dynamic_rendering: true,
|
|
||||||
..DeviceFeatures::empty()
|
|
||||||
},
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let queue = queues.next().unwrap();
|
|
||||||
let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device.clone()));
|
|
||||||
|
|
||||||
let command_buffer_allocator = Arc::new(StandardCommandBufferAllocator::new(
|
|
||||||
device.clone(),
|
|
||||||
Default::default(),
|
|
||||||
));
|
|
||||||
|
|
||||||
let uniform_buffer_allocator = SubbufferAllocator::new(
|
|
||||||
memory_allocator.clone(),
|
|
||||||
SubbufferAllocatorCreateInfo {
|
|
||||||
buffer_usage: BufferUsage::UNIFORM_BUFFER,
|
|
||||||
memory_type_filter: MemoryTypeFilter::PREFER_DEVICE
|
|
||||||
| MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
let descriptor_set_allocator = Arc::new(StandardDescriptorSetAllocator::new(
|
|
||||||
device.clone(),
|
|
||||||
Default::default(),
|
|
||||||
));
|
|
||||||
|
|
||||||
Self {
|
|
||||||
instance,
|
|
||||||
device,
|
|
||||||
queue,
|
|
||||||
memory_allocator,
|
|
||||||
command_buffer_allocator,
|
|
||||||
uniform_buffer_allocator,
|
|
||||||
descriptor_set_allocator,
|
|
||||||
rcx: None,
|
|
||||||
scene: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ApplicationHandler for App {
|
|
||||||
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
|
|
||||||
let window_attributes = winit::window::Window::default_attributes()
|
|
||||||
.with_title("Rust ASH Test")
|
|
||||||
.with_inner_size(winit::dpi::PhysicalSize::new(
|
|
||||||
f64::from(800),
|
|
||||||
f64::from(600),
|
|
||||||
));
|
|
||||||
|
|
||||||
let window = Arc::new(event_loop.create_window(window_attributes).unwrap());
|
|
||||||
|
|
||||||
let surface = Surface::from_window(self.instance.clone(), window.clone()).unwrap();
|
|
||||||
|
|
||||||
self.rcx = Some(RenderContext::new(window, surface, &self.device));
|
|
||||||
self.scene = Some(Scene::load(&self).unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn window_event(&mut self, event_loop: &ActiveEventLoop, _id: WindowId, event: WindowEvent) {
|
|
||||||
match event {
|
|
||||||
WindowEvent::CloseRequested => {
|
|
||||||
log::debug!("The close button was pressed; stopping");
|
|
||||||
event_loop.exit();
|
|
||||||
}
|
|
||||||
WindowEvent::Resized(_) => {
|
|
||||||
let rcx = self.rcx.as_mut().unwrap();
|
|
||||||
rcx.recreate_swapchain = true;
|
|
||||||
}
|
|
||||||
WindowEvent::RedrawRequested => {
|
|
||||||
let (image_index, acquire_future) = {
|
|
||||||
let rcx = self.rcx.as_mut().unwrap();
|
|
||||||
let window_size = rcx.window.inner_size();
|
|
||||||
|
|
||||||
if window_size.width == 0 || window_size.height == 0 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
rcx.previous_frame_end.as_mut().unwrap().cleanup_finished();
|
|
||||||
rcx.update_swapchain().unwrap();
|
|
||||||
|
|
||||||
let (image_index, suboptimal, acquire_future) =
|
|
||||||
match acquire_next_image(rcx.swapchain.clone(), None)
|
|
||||||
.map_err(Validated::unwrap)
|
|
||||||
{
|
|
||||||
Ok(r) => r,
|
|
||||||
Err(VulkanError::OutOfDate) => {
|
|
||||||
rcx.recreate_swapchain = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Err(e) => panic!("failed to acquire next image: {e}"),
|
|
||||||
};
|
|
||||||
|
|
||||||
if suboptimal {
|
|
||||||
rcx.recreate_swapchain = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
(image_index, acquire_future)
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut builder = AutoCommandBufferBuilder::primary(
|
|
||||||
self.command_buffer_allocator.clone(),
|
|
||||||
self.queue.queue_family_index(),
|
|
||||||
CommandBufferUsage::OneTimeSubmit,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
{
|
|
||||||
let rcx = self.rcx.as_ref().unwrap();
|
|
||||||
builder
|
|
||||||
.begin_rendering(RenderingInfo {
|
|
||||||
color_attachments: vec![Some(RenderingAttachmentInfo {
|
|
||||||
load_op: AttachmentLoadOp::Clear,
|
|
||||||
store_op: AttachmentStoreOp::Store,
|
|
||||||
clear_value: Some([0.0, 0.0, 0.0, 1.0].into()),
|
|
||||||
..RenderingAttachmentInfo::image_view(
|
|
||||||
rcx.attachment_image_views[image_index as usize].clone(),
|
|
||||||
)
|
|
||||||
})],
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.unwrap()
|
|
||||||
.set_viewport(0, [rcx.viewport.clone()].into_iter().collect())
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(scene) = self.scene.as_ref() {
|
|
||||||
scene.render(&self, &mut builder).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.end_rendering().unwrap();
|
|
||||||
|
|
||||||
let command_buffer = builder.build().unwrap();
|
|
||||||
|
|
||||||
{
|
|
||||||
let rcx = self.rcx.as_mut().unwrap();
|
|
||||||
|
|
||||||
let future = rcx
|
|
||||||
.previous_frame_end
|
|
||||||
.take()
|
|
||||||
.unwrap()
|
|
||||||
.join(acquire_future)
|
|
||||||
.then_execute(self.queue.clone(), command_buffer)
|
|
||||||
.unwrap()
|
|
||||||
.then_swapchain_present(
|
|
||||||
self.queue.clone(),
|
|
||||||
SwapchainPresentInfo::swapchain_image_index(
|
|
||||||
rcx.swapchain.clone(),
|
|
||||||
image_index,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.then_signal_fence_and_flush();
|
|
||||||
|
|
||||||
match future.map_err(Validated::unwrap) {
|
|
||||||
Ok(future) => {
|
|
||||||
rcx.previous_frame_end = Some(future.boxed());
|
|
||||||
}
|
|
||||||
Err(VulkanError::OutOfDate) => {
|
|
||||||
rcx.recreate_swapchain = true;
|
|
||||||
rcx.previous_frame_end = Some(sync::now(self.device.clone()).boxed());
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
println!("failed to flush future: {e}");
|
|
||||||
rcx.previous_frame_end = Some(sync::now(self.device.clone()).boxed());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) {
|
|
||||||
let rcx = self.rcx.as_mut().unwrap();
|
|
||||||
rcx.window.request_redraw();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +1,9 @@
|
||||||
mod app;
|
use std::sync::Arc;
|
||||||
mod pipelines;
|
use ash::vk;
|
||||||
mod render_context;
|
|
||||||
mod vertex;
|
|
||||||
pub use app::App;
|
|
||||||
|
|
||||||
mod scene;
|
pub mod vulkan;
|
||||||
pub use scene::Scene;
|
|
||||||
pub use vertex::Vertex2D;
|
pub trait Renderable {
|
||||||
|
fn init(&mut self, device: &Arc<vulkan::VkDevice>, render_pass: &Arc<vulkan::VkRenderPass>) -> anyhow::Result<()>;
|
||||||
|
fn render(&self, device: &vulkan::VkDevice, swapchain: &vulkan::VkSwapchain, command_buffer: &vk::CommandBuffer) -> anyhow::Result<()>;
|
||||||
|
}
|
|
@ -1 +0,0 @@
|
||||||
pub mod triangle_pipeline;
|
|
|
@ -1,111 +0,0 @@
|
||||||
use std::collections::BTreeMap;
|
|
||||||
use std::error::Error;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use vulkano::descriptor_set::layout::{
|
|
||||||
DescriptorSetLayoutBinding, DescriptorSetLayoutCreateInfo, DescriptorType,
|
|
||||||
};
|
|
||||||
use vulkano::device::Device;
|
|
||||||
use vulkano::pipeline::graphics::color_blend::{ColorBlendAttachmentState, ColorBlendState};
|
|
||||||
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
|
|
||||||
use vulkano::pipeline::graphics::multisample::MultisampleState;
|
|
||||||
use vulkano::pipeline::graphics::rasterization::RasterizationState;
|
|
||||||
use vulkano::pipeline::graphics::subpass::PipelineRenderingCreateInfo;
|
|
||||||
use vulkano::pipeline::graphics::vertex_input::{Vertex, VertexDefinition};
|
|
||||||
use vulkano::pipeline::graphics::viewport::ViewportState;
|
|
||||||
use vulkano::pipeline::graphics::GraphicsPipelineCreateInfo;
|
|
||||||
use vulkano::pipeline::layout::{PipelineDescriptorSetLayoutCreateInfo, PipelineLayoutCreateFlags};
|
|
||||||
use vulkano::pipeline::{
|
|
||||||
DynamicState, GraphicsPipeline, PipelineLayout, PipelineShaderStageCreateInfo,
|
|
||||||
};
|
|
||||||
use vulkano::shader::{EntryPoint, ShaderStages};
|
|
||||||
use vulkano::swapchain::Swapchain;
|
|
||||||
|
|
||||||
use crate::renderer::Vertex2D;
|
|
||||||
|
|
||||||
pub mod shaders {
|
|
||||||
pub mod vs {
|
|
||||||
vulkano_shaders::shader! {
|
|
||||||
ty: "vertex",
|
|
||||||
path: r"res/shaders/vertex.vert",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod fs {
|
|
||||||
vulkano_shaders::shader! {
|
|
||||||
ty: "fragment",
|
|
||||||
path: r"res/shaders/vertex.frag",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_triangle_pipeline(
|
|
||||||
device: &Arc<Device>,
|
|
||||||
swapchain: &Arc<Swapchain>,
|
|
||||||
) -> Result<Arc<GraphicsPipeline>, Box<dyn Error>> {
|
|
||||||
let (vs, fs) = load_shaders(device)?;
|
|
||||||
let vertex_input_state = Vertex2D::per_vertex().definition(&vs)?;
|
|
||||||
|
|
||||||
let stages = [
|
|
||||||
PipelineShaderStageCreateInfo::new(vs),
|
|
||||||
PipelineShaderStageCreateInfo::new(fs),
|
|
||||||
];
|
|
||||||
|
|
||||||
let mut bindings = BTreeMap::<u32, DescriptorSetLayoutBinding>::new();
|
|
||||||
let mut descriptor_set_layout_binding =
|
|
||||||
DescriptorSetLayoutBinding::descriptor_type(DescriptorType::UniformBuffer);
|
|
||||||
descriptor_set_layout_binding.stages = ShaderStages::VERTEX;
|
|
||||||
bindings.insert(0, descriptor_set_layout_binding);
|
|
||||||
|
|
||||||
let descriptor_set_layout = DescriptorSetLayoutCreateInfo {
|
|
||||||
bindings,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
let create_info = PipelineDescriptorSetLayoutCreateInfo {
|
|
||||||
set_layouts: vec![descriptor_set_layout],
|
|
||||||
flags: PipelineLayoutCreateFlags::default(),
|
|
||||||
push_constant_ranges: vec![],
|
|
||||||
}
|
|
||||||
.into_pipeline_layout_create_info(device.clone())?;
|
|
||||||
|
|
||||||
let layout = PipelineLayout::new(device.clone(), create_info)?;
|
|
||||||
|
|
||||||
let subpass = PipelineRenderingCreateInfo {
|
|
||||||
color_attachment_formats: vec![Some(swapchain.image_format())],
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
let pipeline = GraphicsPipeline::new(
|
|
||||||
device.clone(),
|
|
||||||
None,
|
|
||||||
GraphicsPipelineCreateInfo {
|
|
||||||
stages: stages.into_iter().collect(),
|
|
||||||
vertex_input_state: Some(vertex_input_state),
|
|
||||||
input_assembly_state: Some(InputAssemblyState::default()),
|
|
||||||
viewport_state: Some(ViewportState::default()),
|
|
||||||
rasterization_state: Some(RasterizationState::default()),
|
|
||||||
multisample_state: Some(MultisampleState::default()),
|
|
||||||
color_blend_state: Some(ColorBlendState::with_attachment_states(
|
|
||||||
subpass.color_attachment_formats.len() as u32,
|
|
||||||
ColorBlendAttachmentState::default(),
|
|
||||||
)),
|
|
||||||
dynamic_state: [DynamicState::Viewport].into_iter().collect(),
|
|
||||||
subpass: Some(subpass.into()),
|
|
||||||
..GraphicsPipelineCreateInfo::layout(layout)
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(pipeline)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_shaders(device: &Arc<Device>) -> Result<(EntryPoint, EntryPoint), Box<dyn Error>> {
|
|
||||||
let vs = shaders::vs::load(device.clone())?
|
|
||||||
.entry_point("main")
|
|
||||||
.ok_or("Failed find main entry point of vertex shader".to_string())?;
|
|
||||||
|
|
||||||
let fs = shaders::fs::load(device.clone())?
|
|
||||||
.entry_point("main")
|
|
||||||
.ok_or("Failed find main entry point of fragment shader".to_string())?;
|
|
||||||
|
|
||||||
Ok((vs, fs))
|
|
||||||
}
|
|
|
@ -1,102 +0,0 @@
|
||||||
use std::sync::Arc;
|
|
||||||
use vulkano::device::Device;
|
|
||||||
use vulkano::image::view::ImageView;
|
|
||||||
use vulkano::image::{Image, ImageUsage};
|
|
||||||
use vulkano::pipeline::graphics::viewport::Viewport;
|
|
||||||
use vulkano::swapchain::{Surface, Swapchain, SwapchainCreateInfo};
|
|
||||||
use vulkano::sync::GpuFuture;
|
|
||||||
use vulkano::{sync, Validated, VulkanError};
|
|
||||||
use winit::window::Window;
|
|
||||||
|
|
||||||
pub struct RenderContext {
|
|
||||||
pub(super) window: Arc<Window>,
|
|
||||||
pub(super) swapchain: Arc<Swapchain>,
|
|
||||||
pub(super) attachment_image_views: Vec<Arc<ImageView>>,
|
|
||||||
pub(super) viewport: Viewport,
|
|
||||||
pub(super) recreate_swapchain: bool,
|
|
||||||
pub(super) previous_frame_end: Option<Box<dyn GpuFuture>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RenderContext {
|
|
||||||
pub fn new(window: Arc<Window>, surface: Arc<Surface>, device: &Arc<Device>) -> Self {
|
|
||||||
let window_size = window.inner_size();
|
|
||||||
|
|
||||||
let (swapchain, images) = {
|
|
||||||
let surface_capabilities = device
|
|
||||||
.physical_device()
|
|
||||||
.surface_capabilities(&surface, Default::default())
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let (image_format, _) = device
|
|
||||||
.physical_device()
|
|
||||||
.surface_formats(&surface, Default::default())
|
|
||||||
.unwrap()[0];
|
|
||||||
|
|
||||||
Swapchain::new(
|
|
||||||
device.clone(),
|
|
||||||
surface,
|
|
||||||
SwapchainCreateInfo {
|
|
||||||
// 2 because with some graphics driver, it crash on fullscreen because fullscreen need to min image to works.
|
|
||||||
min_image_count: surface_capabilities.min_image_count.max(2),
|
|
||||||
image_format,
|
|
||||||
image_extent: window_size.into(),
|
|
||||||
image_usage: ImageUsage::COLOR_ATTACHMENT,
|
|
||||||
composite_alpha: surface_capabilities
|
|
||||||
.supported_composite_alpha
|
|
||||||
.into_iter()
|
|
||||||
.next()
|
|
||||||
.unwrap(),
|
|
||||||
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
};
|
|
||||||
|
|
||||||
let attachment_image_views = window_size_dependent_setup(&images);
|
|
||||||
|
|
||||||
let viewport = Viewport {
|
|
||||||
offset: [0.0, 0.0],
|
|
||||||
extent: window_size.into(),
|
|
||||||
depth_range: 0.0..=1.0,
|
|
||||||
};
|
|
||||||
|
|
||||||
let recreate_swapchain = false;
|
|
||||||
let previous_frame_end = Some(sync::now(device.clone()).boxed());
|
|
||||||
|
|
||||||
Self {
|
|
||||||
window,
|
|
||||||
swapchain,
|
|
||||||
attachment_image_views,
|
|
||||||
viewport,
|
|
||||||
recreate_swapchain,
|
|
||||||
previous_frame_end,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_swapchain(&mut self) -> Result<(), Validated<VulkanError>> {
|
|
||||||
if !self.recreate_swapchain {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
let window_size = self.window.inner_size();
|
|
||||||
let (new_swapchain, new_images) = self.swapchain.recreate(SwapchainCreateInfo {
|
|
||||||
image_extent: window_size.into(),
|
|
||||||
..self.swapchain.create_info()
|
|
||||||
})?;
|
|
||||||
|
|
||||||
self.swapchain = new_swapchain;
|
|
||||||
self.attachment_image_views = window_size_dependent_setup(&new_images);
|
|
||||||
self.viewport.extent = window_size.into();
|
|
||||||
self.recreate_swapchain = false;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn window_size_dependent_setup(images: &[Arc<Image>]) -> Vec<Arc<ImageView>> {
|
|
||||||
images
|
|
||||||
.iter()
|
|
||||||
.map(|image| ImageView::new_default(image.clone()).unwrap())
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
}
|
|
|
@ -1,151 +0,0 @@
|
||||||
use crate::renderer::pipelines::triangle_pipeline::shaders::vs;
|
|
||||||
use glam::{Mat3, Mat4, Vec3};
|
|
||||||
use std::error::Error;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use std::time::Instant;
|
|
||||||
use vulkano::buffer::Subbuffer;
|
|
||||||
use vulkano::command_buffer::{AutoCommandBufferBuilder, PrimaryAutoCommandBuffer};
|
|
||||||
use vulkano::descriptor_set::{DescriptorSet, WriteDescriptorSet};
|
|
||||||
use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint};
|
|
||||||
|
|
||||||
use crate::renderer::{pipelines::triangle_pipeline::create_triangle_pipeline, App, Vertex2D};
|
|
||||||
|
|
||||||
const VERTICES: [Vertex2D; 12] = [
|
|
||||||
// Triangle en haut à gauche
|
|
||||||
Vertex2D {
|
|
||||||
position: [-0.5, -0.75],
|
|
||||||
color: [1.0, 0.0, 0.0],
|
|
||||||
},
|
|
||||||
Vertex2D {
|
|
||||||
position: [-0.75, -0.25],
|
|
||||||
color: [0.0, 1.0, 0.0],
|
|
||||||
},
|
|
||||||
Vertex2D {
|
|
||||||
position: [-0.25, -0.25],
|
|
||||||
color: [0.0, 0.0, 1.0],
|
|
||||||
},
|
|
||||||
// Triangle en bas à gauche
|
|
||||||
Vertex2D {
|
|
||||||
position: [-0.5, 0.25],
|
|
||||||
color: [0.5, 0.5, 0.5],
|
|
||||||
},
|
|
||||||
Vertex2D {
|
|
||||||
position: [-0.75, 0.75],
|
|
||||||
color: [0.2, 0.8, 0.2],
|
|
||||||
},
|
|
||||||
Vertex2D {
|
|
||||||
position: [-0.25, 0.75],
|
|
||||||
color: [0.8, 0.2, 0.2],
|
|
||||||
},
|
|
||||||
// Triangle en haut à droite
|
|
||||||
Vertex2D {
|
|
||||||
position: [0.5, -0.75],
|
|
||||||
color: [1.0, 1.0, 0.0],
|
|
||||||
},
|
|
||||||
Vertex2D {
|
|
||||||
position: [0.25, -0.25],
|
|
||||||
color: [0.0, 1.0, 1.0],
|
|
||||||
},
|
|
||||||
Vertex2D {
|
|
||||||
position: [0.75, -0.25],
|
|
||||||
color: [1.0, 0.0, 1.0],
|
|
||||||
},
|
|
||||||
// Triangle en bas à droite
|
|
||||||
Vertex2D {
|
|
||||||
position: [0.5, 0.25],
|
|
||||||
color: [0.1, 0.5, 0.8],
|
|
||||||
},
|
|
||||||
Vertex2D {
|
|
||||||
position: [0.25, 0.75],
|
|
||||||
color: [0.8, 0.6, 0.1],
|
|
||||||
},
|
|
||||||
Vertex2D {
|
|
||||||
position: [0.75, 0.75],
|
|
||||||
color: [0.3, 0.4, 0.6],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
pub struct Scene {
|
|
||||||
pipeline: Arc<GraphicsPipeline>,
|
|
||||||
vertex_buffer: Subbuffer<[Vertex2D]>,
|
|
||||||
|
|
||||||
rotation_start: Instant,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Scene {
|
|
||||||
pub fn load(app: &App) -> Result<Self, Box<dyn Error>> {
|
|
||||||
let pipeline = create_triangle_pipeline(&app.device, &app.rcx.as_ref().unwrap().swapchain)?;
|
|
||||||
let vertex_buffer =
|
|
||||||
Vertex2D::create_buffer(Vec::from_iter(VERTICES), &app.memory_allocator)?;
|
|
||||||
|
|
||||||
Ok(Scene {
|
|
||||||
pipeline,
|
|
||||||
vertex_buffer,
|
|
||||||
rotation_start: Instant::now(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn render(
|
|
||||||
&self,
|
|
||||||
app: &App,
|
|
||||||
builder: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer>,
|
|
||||||
) -> Result<(), Box<dyn Error>> {
|
|
||||||
let vertex_count = self.vertex_buffer.len() as u32;
|
|
||||||
let instance_count = vertex_count / 3;
|
|
||||||
|
|
||||||
let uniform_buffer = self.get_uniform_buffer(app);
|
|
||||||
let layout = &self.pipeline.layout().set_layouts()[0];
|
|
||||||
let descriptor_set = DescriptorSet::new(
|
|
||||||
app.descriptor_set_allocator.clone(),
|
|
||||||
layout.clone(),
|
|
||||||
[WriteDescriptorSet::buffer(0, uniform_buffer)],
|
|
||||||
[],
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
builder
|
|
||||||
.bind_pipeline_graphics(self.pipeline.clone())?
|
|
||||||
.bind_descriptor_sets(
|
|
||||||
PipelineBindPoint::Graphics,
|
|
||||||
self.pipeline.layout().clone(),
|
|
||||||
0,
|
|
||||||
descriptor_set,
|
|
||||||
)?
|
|
||||||
.bind_vertex_buffers(0, self.vertex_buffer.clone())?
|
|
||||||
.draw(vertex_count, instance_count, 0, 0)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_uniform_buffer(&self, app: &App) -> Subbuffer<vs::MVPData> {
|
|
||||||
let swapchain = &app.rcx.as_ref().unwrap().swapchain;
|
|
||||||
let elapsed = self.rotation_start.elapsed();
|
|
||||||
let rotation = elapsed.as_secs() as f64 + elapsed.subsec_nanos() as f64 / 1_000_000_000.0;
|
|
||||||
let rotation = Mat3::from_rotation_y(rotation as f32);
|
|
||||||
|
|
||||||
// NOTE: This teapot was meant for OpenGL where the origin is at the lower left
|
|
||||||
// instead the origin is at the upper left in Vulkan, so we reverse the Y axis.
|
|
||||||
let aspect_ratio = swapchain.image_extent()[0] as f32 / swapchain.image_extent()[1] as f32;
|
|
||||||
|
|
||||||
let proj = Mat4::perspective_rh_gl(std::f32::consts::FRAC_PI_2, aspect_ratio, 0.01, 100.0);
|
|
||||||
let view = Mat4::look_at_rh(
|
|
||||||
Vec3::new(0.3, 0.3, 1.0),
|
|
||||||
Vec3::new(0.0, 0.0, 0.0),
|
|
||||||
Vec3::new(0.0, -1.0, 0.0),
|
|
||||||
);
|
|
||||||
let scale = Mat4::from_scale(Vec3::splat(1.0));
|
|
||||||
|
|
||||||
let uniform_data = vs::MVPData {
|
|
||||||
world: Mat4::from_mat3(rotation).to_cols_array_2d(),
|
|
||||||
view: (view * scale).to_cols_array_2d(),
|
|
||||||
projection: proj.to_cols_array_2d(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let buffer = app.uniform_buffer_allocator.allocate_sized().unwrap();
|
|
||||||
*buffer.write().unwrap() = uniform_data;
|
|
||||||
|
|
||||||
buffer
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
use std::sync::Arc;
|
|
||||||
use vulkano::buffer::{
|
|
||||||
AllocateBufferError, Buffer, BufferContents, BufferCreateInfo, BufferUsage, Subbuffer,
|
|
||||||
};
|
|
||||||
use vulkano::memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator};
|
|
||||||
use vulkano::pipeline::graphics::vertex_input::Vertex;
|
|
||||||
use vulkano::Validated;
|
|
||||||
|
|
||||||
#[derive(BufferContents, Vertex)]
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct Vertex2D {
|
|
||||||
#[format(R32G32_SFLOAT)]
|
|
||||||
pub position: [f32; 2],
|
|
||||||
|
|
||||||
#[format(R32G32B32_SFLOAT)]
|
|
||||||
pub color: [f32; 3],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Vertex2D {
|
|
||||||
pub fn create_buffer(
|
|
||||||
vertices: Vec<Vertex2D>,
|
|
||||||
memory_allocator: &Arc<StandardMemoryAllocator>,
|
|
||||||
) -> Result<Subbuffer<[Vertex2D]>, Validated<AllocateBufferError>> {
|
|
||||||
Buffer::from_iter(
|
|
||||||
memory_allocator.clone(),
|
|
||||||
BufferCreateInfo {
|
|
||||||
usage: BufferUsage::VERTEX_BUFFER,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
AllocationCreateInfo {
|
|
||||||
memory_type_filter: MemoryTypeFilter::PREFER_DEVICE
|
|
||||||
| MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
vertices,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
45
src/renderer/vulkan/mod.rs
Normal file
45
src/renderer/vulkan/mod.rs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
mod vk_render_context;
|
||||||
|
pub use vk_render_context::VkRenderContext;
|
||||||
|
|
||||||
|
mod vk_instance;
|
||||||
|
pub use vk_instance::VkInstance;
|
||||||
|
|
||||||
|
mod vk_surface;
|
||||||
|
pub use vk_surface::{SwapchainSupportDetails, VkSurface};
|
||||||
|
|
||||||
|
mod vk_physical_device;
|
||||||
|
pub use vk_physical_device::VkPhysicalDevice;
|
||||||
|
|
||||||
|
mod vk_device;
|
||||||
|
pub use vk_device::VkDevice;
|
||||||
|
|
||||||
|
mod vk_swapchain;
|
||||||
|
pub use vk_swapchain::VkSwapchain;
|
||||||
|
|
||||||
|
mod vk_shader_module;
|
||||||
|
pub use vk_shader_module::VkShaderModule;
|
||||||
|
|
||||||
|
mod vk_graphics_pipeline;
|
||||||
|
pub use vk_graphics_pipeline::VkGraphicsPipeline;
|
||||||
|
|
||||||
|
mod vk_render_pass;
|
||||||
|
pub use vk_render_pass::VkRenderPass;
|
||||||
|
|
||||||
|
mod vk_semaphore;
|
||||||
|
pub use vk_semaphore::VkSemaphore;
|
||||||
|
|
||||||
|
mod vk_command_pool;
|
||||||
|
pub use vk_command_pool::VkCommandPool;
|
||||||
|
|
||||||
|
mod vk_framebuffer;
|
||||||
|
pub use vk_framebuffer::VkFramebuffer;
|
||||||
|
|
||||||
|
mod vk_fence;
|
||||||
|
pub use vk_fence::VkFence;
|
||||||
|
|
||||||
|
mod utils;
|
||||||
|
mod vertex;
|
||||||
|
mod vk_buffer;
|
||||||
|
pub use vk_buffer::VkBuffer;
|
||||||
|
|
||||||
|
pub use vertex::Vertex;
|
51
src/renderer/vulkan/utils/layers.rs
Normal file
51
src/renderer/vulkan/utils/layers.rs
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
use std::ffi::CString;
|
||||||
|
|
||||||
|
pub enum LayersSelector<'a> {
|
||||||
|
Nothing,
|
||||||
|
SpecificLayers(Vec<&'a str>),
|
||||||
|
All,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn use_layers(entry: &ash::Entry, selector: LayersSelector) -> Vec<CString> {
|
||||||
|
let layers_available = get_layers_available(entry)
|
||||||
|
.iter()
|
||||||
|
.filter_map(|layer| {
|
||||||
|
layer
|
||||||
|
.layer_name_as_c_str()
|
||||||
|
.and_then(|layer_name| Ok(CString::from(layer_name)))
|
||||||
|
.ok()
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
match selector {
|
||||||
|
LayersSelector::Nothing => Vec::new(),
|
||||||
|
LayersSelector::SpecificLayers(layers) => select_layers(&layers_available, &layers),
|
||||||
|
LayersSelector::All => layers_available,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_layers_available(entry: &ash::Entry) -> Vec<ash::vk::LayerProperties> {
|
||||||
|
unsafe {
|
||||||
|
entry
|
||||||
|
.enumerate_instance_layer_properties()
|
||||||
|
.unwrap_or_default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn select_layers(layers_available: &Vec<CString>, layers_to_select: &[&str]) -> Vec<CString> {
|
||||||
|
layers_to_select
|
||||||
|
.iter()
|
||||||
|
.filter_map(|layer_name| {
|
||||||
|
if layers_available.iter().any(|layer_available| {
|
||||||
|
layer_available
|
||||||
|
.to_str()
|
||||||
|
.and_then(|layer_available| Ok(layer_available.eq(*layer_name)))
|
||||||
|
.unwrap_or(false)
|
||||||
|
}) {
|
||||||
|
CString::new(*layer_name).ok()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
}
|
1
src/renderer/vulkan/utils/mod.rs
Normal file
1
src/renderer/vulkan/utils/mod.rs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
pub mod layers;
|
37
src/renderer/vulkan/vertex.rs
Normal file
37
src/renderer/vulkan/vertex.rs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
use ash::vk;
|
||||||
|
use std::mem::offset_of;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Vertex {
|
||||||
|
pub position: [f32; 2],
|
||||||
|
pub color: [f32; 3],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Vertex {
|
||||||
|
pub fn new(position: [f32; 2], color: [f32; 3]) -> Self {
|
||||||
|
Self { position, color }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_binding_description() -> vk::VertexInputBindingDescription {
|
||||||
|
vk::VertexInputBindingDescription::default()
|
||||||
|
.binding(0)
|
||||||
|
.stride(size_of::<Self>() as u32)
|
||||||
|
.input_rate(vk::VertexInputRate::VERTEX)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_attribute_descriptions() -> [vk::VertexInputAttributeDescription; 2] {
|
||||||
|
let position_attribute = vk::VertexInputAttributeDescription::default()
|
||||||
|
.binding(0)
|
||||||
|
.location(0)
|
||||||
|
.format(vk::Format::R32G32_SFLOAT)
|
||||||
|
.offset(offset_of!(Vertex, position) as u32);
|
||||||
|
|
||||||
|
let color_attribute = vk::VertexInputAttributeDescription::default()
|
||||||
|
.binding(0)
|
||||||
|
.location(1)
|
||||||
|
.format(vk::Format::R32G32B32_SFLOAT)
|
||||||
|
.offset(offset_of!(Vertex, color) as u32);
|
||||||
|
|
||||||
|
[position_attribute, color_attribute]
|
||||||
|
}
|
||||||
|
}
|
31
src/renderer/vulkan/vk_buffer.rs
Normal file
31
src/renderer/vulkan/vk_buffer.rs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
use ash::prelude::VkResult;
|
||||||
|
use ash::vk;
|
||||||
|
use crate::renderer::vulkan::VkDevice;
|
||||||
|
|
||||||
|
pub struct VkBuffer {
|
||||||
|
device: Arc<VkDevice>,
|
||||||
|
|
||||||
|
handle: vk::Buffer,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VkBuffer {
|
||||||
|
pub fn new(device: &Arc<VkDevice>, info: &vk::BufferCreateInfo) -> VkResult<Self> {
|
||||||
|
let buffer = unsafe { device.handle.create_buffer(info, None)? };
|
||||||
|
|
||||||
|
Ok(VkBuffer { device: Arc::clone(device), handle: buffer })
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn mem_requirements(&self) -> vk::MemoryRequirements {
|
||||||
|
unsafe { self.device.handle.get_buffer_memory_requirements(self.handle) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for VkBuffer {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
self.device.handle.destroy_buffer(self.handle, None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
52
src/renderer/vulkan/vk_command_pool.rs
Normal file
52
src/renderer/vulkan/vk_command_pool.rs
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
use super::VkDevice;
|
||||||
|
use ash::prelude::VkResult;
|
||||||
|
use ash::vk;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub struct VkCommandPool {
|
||||||
|
device: Arc<VkDevice>,
|
||||||
|
|
||||||
|
pub handle: vk::CommandPool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VkCommandPool {
|
||||||
|
pub fn new(device: &Arc<VkDevice>) -> VkResult<Self> {
|
||||||
|
let command_pool_info =
|
||||||
|
vk::CommandPoolCreateInfo::default()
|
||||||
|
.flags(vk::CommandPoolCreateFlags::RESET_COMMAND_BUFFER)
|
||||||
|
.queue_family_index(device.queue_family_index);
|
||||||
|
let command_pool = unsafe {
|
||||||
|
device
|
||||||
|
.handle
|
||||||
|
.create_command_pool(&command_pool_info, None)?
|
||||||
|
};
|
||||||
|
log::debug!("Command pool created ({command_pool:?})");
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
device: device.clone(),
|
||||||
|
handle: command_pool,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn allocate_command_buffers_for_framebuffers(&self, framebuffers_count: u32) -> VkResult<Vec<vk::CommandBuffer>> {
|
||||||
|
let command_buffer_info = vk::CommandBufferAllocateInfo::default()
|
||||||
|
.command_pool(self.handle)
|
||||||
|
.level(vk::CommandBufferLevel::PRIMARY)
|
||||||
|
.command_buffer_count(framebuffers_count);
|
||||||
|
|
||||||
|
let command_buffers = unsafe {
|
||||||
|
self.device
|
||||||
|
.handle
|
||||||
|
.allocate_command_buffers(&command_buffer_info)?
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(command_buffers)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for VkCommandPool {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe { self.device.handle.destroy_command_pool(self.handle, None) };
|
||||||
|
log::debug!("Command pool destroyed ({:?})", self.handle);
|
||||||
|
}
|
||||||
|
}
|
109
src/renderer/vulkan/vk_device.rs
Normal file
109
src/renderer/vulkan/vk_device.rs
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
use super::{VkInstance, VkPhysicalDevice};
|
||||||
|
use ash::prelude::VkResult;
|
||||||
|
use ash::vk;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub struct VkDevice {
|
||||||
|
instance: Arc<VkInstance>,
|
||||||
|
physical_device: Arc<VkPhysicalDevice>,
|
||||||
|
|
||||||
|
pub handle: ash::Device,
|
||||||
|
pub swapchain_loader: ash::khr::swapchain::Device,
|
||||||
|
pub queue_family_index: u32,
|
||||||
|
|
||||||
|
// Arc not used because vk::Queue is destroyed with Device automatically
|
||||||
|
// so any references of vk::Queue must be destroyed with VkDevice
|
||||||
|
queues: Vec<vk::Queue>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VkDevice {
|
||||||
|
pub fn new_graphics_device(
|
||||||
|
instance: &Arc<VkInstance>,
|
||||||
|
physical_device: &Arc<VkPhysicalDevice>,
|
||||||
|
queue_family_index: u32,
|
||||||
|
) -> anyhow::Result<Self> {
|
||||||
|
let device_extension_names_raw = [
|
||||||
|
ash::khr::swapchain::NAME.as_ptr(),
|
||||||
|
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||||
|
ash::khr::portability_subset::NAME.as_ptr(),
|
||||||
|
];
|
||||||
|
let features = vk::PhysicalDeviceFeatures {
|
||||||
|
shader_clip_distance: 1,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let queues_priorities = [1.0];
|
||||||
|
let queue_info = vk::DeviceQueueCreateInfo::default()
|
||||||
|
.queue_family_index(queue_family_index)
|
||||||
|
.queue_priorities(&queues_priorities);
|
||||||
|
|
||||||
|
let device_create_info = vk::DeviceCreateInfo::default()
|
||||||
|
.queue_create_infos(std::slice::from_ref(&queue_info))
|
||||||
|
.enabled_extension_names(&device_extension_names_raw)
|
||||||
|
.enabled_features(&features);
|
||||||
|
|
||||||
|
let device = unsafe {
|
||||||
|
instance
|
||||||
|
.handle
|
||||||
|
.create_device(physical_device.handle, &device_create_info, None)?
|
||||||
|
};
|
||||||
|
log::debug!("Device created ({:?})", device.handle());
|
||||||
|
|
||||||
|
let queues = queues_priorities
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(index, _)| unsafe { device.get_device_queue(queue_family_index, index as u32) })
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let swapchain_loader = ash::khr::swapchain::Device::new(&instance.handle, &device);
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
instance: Arc::clone(instance),
|
||||||
|
physical_device: Arc::clone(&physical_device),
|
||||||
|
handle: device,
|
||||||
|
swapchain_loader,
|
||||||
|
queue_family_index,
|
||||||
|
queues,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_device_queue(&self, queue_index: u32) -> Option<&vk::Queue> {
|
||||||
|
self.queues.get(queue_index as usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_command_pool(
|
||||||
|
&self,
|
||||||
|
info: &vk::CommandPoolCreateInfo,
|
||||||
|
) -> VkResult<vk::CommandPool> {
|
||||||
|
let info = info.queue_family_index(self.queue_family_index);
|
||||||
|
|
||||||
|
unsafe { self.handle.create_command_pool(&info, None) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn allocate_command_buffers(
|
||||||
|
&self,
|
||||||
|
info: &vk::CommandBufferAllocateInfo,
|
||||||
|
) -> VkResult<Vec<vk::CommandBuffer>> {
|
||||||
|
unsafe { self.handle.allocate_command_buffers(&info) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_fence(&self, info: &vk::FenceCreateInfo) -> VkResult<vk::Fence> {
|
||||||
|
unsafe { self.handle.create_fence(&info, None) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_semaphore(
|
||||||
|
&self,
|
||||||
|
info: &vk::SemaphoreCreateInfo,
|
||||||
|
) -> VkResult<vk::Semaphore> {
|
||||||
|
unsafe { self.handle.create_semaphore(&info, None) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for VkDevice {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
self.handle.destroy_device(None);
|
||||||
|
log::debug!("Device destroyed ({:?})", self.handle.handle());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
src/renderer/vulkan/vk_fence.rs
Normal file
30
src/renderer/vulkan/vk_fence.rs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
use super::VkDevice;
|
||||||
|
use ash::vk;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub struct VkFence {
|
||||||
|
device: Arc<VkDevice>,
|
||||||
|
|
||||||
|
pub handle: vk::Fence,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VkFence {
|
||||||
|
pub fn new(device: &Arc<VkDevice>) -> anyhow::Result<Self> {
|
||||||
|
let fence_info = vk::FenceCreateInfo::default()
|
||||||
|
.flags(vk::FenceCreateFlags::SIGNALED);
|
||||||
|
let fence = unsafe { device.handle.create_fence(&fence_info, None)? };
|
||||||
|
log::debug!("Fence created ({fence:?})");
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
device: device.clone(),
|
||||||
|
handle: fence,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for VkFence {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe { self.device.handle.destroy_fence(self.handle, None) };
|
||||||
|
log::debug!("Fence destroyed ({:?})", self.handle);
|
||||||
|
}
|
||||||
|
}
|
44
src/renderer/vulkan/vk_framebuffer.rs
Normal file
44
src/renderer/vulkan/vk_framebuffer.rs
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
use super::{VkDevice, VkRenderPass, VkSwapchain};
|
||||||
|
use ash::vk;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub struct VkFramebuffer {
|
||||||
|
device: Arc<VkDevice>,
|
||||||
|
image_view: Arc<vk::ImageView>,
|
||||||
|
render_pass: Arc<VkRenderPass>,
|
||||||
|
|
||||||
|
pub handle: vk::Framebuffer,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VkFramebuffer {
|
||||||
|
pub fn from_swapchain_image_view(
|
||||||
|
device: &Arc<VkDevice>,
|
||||||
|
render_pass: &Arc<VkRenderPass>,
|
||||||
|
image_view: &Arc<vk::ImageView>,
|
||||||
|
swapchain: &VkSwapchain,
|
||||||
|
) -> anyhow::Result<Self> {
|
||||||
|
let attachments = [*image_view.as_ref()];
|
||||||
|
let framebuffer_info = vk::FramebufferCreateInfo::default()
|
||||||
|
.render_pass(render_pass.handle)
|
||||||
|
.width(swapchain.surface_resolution.width)
|
||||||
|
.height(swapchain.surface_resolution.height)
|
||||||
|
.attachments(&attachments)
|
||||||
|
.layers(1);
|
||||||
|
|
||||||
|
let framebuffer = unsafe { device.handle.create_framebuffer(&framebuffer_info, None)? };
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
device: device.clone(),
|
||||||
|
render_pass: render_pass.clone(),
|
||||||
|
image_view: image_view.clone(),
|
||||||
|
|
||||||
|
handle: framebuffer,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for VkFramebuffer {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe { self.device.handle.destroy_framebuffer(self.handle, None) };
|
||||||
|
}
|
||||||
|
}
|
120
src/renderer/vulkan/vk_graphics_pipeline.rs
Normal file
120
src/renderer/vulkan/vk_graphics_pipeline.rs
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
use super::{VkDevice, VkRenderPass, VkShaderModule, VkSwapchain};
|
||||||
|
use ash::vk;
|
||||||
|
use std::ffi::CStr;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub struct VkGraphicsPipeline {
|
||||||
|
device: Arc<VkDevice>,
|
||||||
|
render_pass: Arc<VkRenderPass>,
|
||||||
|
|
||||||
|
pub pipeline_layout: vk::PipelineLayout,
|
||||||
|
pub pipeline: vk::Pipeline,
|
||||||
|
vertex_shader: VkShaderModule,
|
||||||
|
fragment_shader: VkShaderModule,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VkGraphicsPipeline {
|
||||||
|
pub fn new(
|
||||||
|
device: &Arc<VkDevice>,
|
||||||
|
render_pass: &Arc<VkRenderPass>,
|
||||||
|
) -> anyhow::Result<Self> {
|
||||||
|
let shader_entry_name = CStr::from_bytes_with_nul(b"main\0")?;
|
||||||
|
|
||||||
|
let vert_shader_module =
|
||||||
|
VkShaderModule::from_spv_file(device, "res/shaders/main.vert.spv")?;
|
||||||
|
|
||||||
|
let vert_shader_info = vk::PipelineShaderStageCreateInfo::default()
|
||||||
|
.module(vert_shader_module.handle)
|
||||||
|
.name(shader_entry_name)
|
||||||
|
.stage(vk::ShaderStageFlags::VERTEX);
|
||||||
|
|
||||||
|
let frag_shader_module =
|
||||||
|
VkShaderModule::from_spv_file(device, "res/shaders/main.frag.spv")?;
|
||||||
|
|
||||||
|
let frag_shader_info = vk::PipelineShaderStageCreateInfo::default()
|
||||||
|
.module(frag_shader_module.handle)
|
||||||
|
.name(shader_entry_name)
|
||||||
|
.stage(vk::ShaderStageFlags::FRAGMENT);
|
||||||
|
|
||||||
|
let shader_stage_create_infos = [vert_shader_info, frag_shader_info];
|
||||||
|
|
||||||
|
let vertex_input_info = vk::PipelineVertexInputStateCreateInfo::default();
|
||||||
|
|
||||||
|
let input_assembly = vk::PipelineInputAssemblyStateCreateInfo::default()
|
||||||
|
.topology(vk::PrimitiveTopology::TRIANGLE_LIST);
|
||||||
|
|
||||||
|
let viewport_state = vk::PipelineViewportStateCreateInfo::default()
|
||||||
|
.viewport_count(1)
|
||||||
|
.scissor_count(1);
|
||||||
|
|
||||||
|
let rasterizer = vk::PipelineRasterizationStateCreateInfo::default()
|
||||||
|
.polygon_mode(vk::PolygonMode::FILL)
|
||||||
|
.cull_mode(vk::CullModeFlags::BACK)
|
||||||
|
.front_face(vk::FrontFace::CLOCKWISE)
|
||||||
|
.line_width(1.0);
|
||||||
|
|
||||||
|
let multisampling = vk::PipelineMultisampleStateCreateInfo::default()
|
||||||
|
.rasterization_samples(vk::SampleCountFlags::TYPE_1)
|
||||||
|
.min_sample_shading(1.0);
|
||||||
|
|
||||||
|
let color_blend_attachment = vk::PipelineColorBlendAttachmentState::default()
|
||||||
|
.color_write_mask(vk::ColorComponentFlags::RGBA);
|
||||||
|
|
||||||
|
let attachments = [color_blend_attachment];
|
||||||
|
let color_blending =
|
||||||
|
vk::PipelineColorBlendStateCreateInfo::default().attachments(&attachments);
|
||||||
|
|
||||||
|
let dynamic_state = vk::PipelineDynamicStateCreateInfo::default()
|
||||||
|
.dynamic_states(&[vk::DynamicState::VIEWPORT, vk::DynamicState::SCISSOR]);
|
||||||
|
|
||||||
|
let pipeline_layout_info = vk::PipelineLayoutCreateInfo::default();
|
||||||
|
let pipeline_layout = unsafe {
|
||||||
|
device
|
||||||
|
.handle
|
||||||
|
.create_pipeline_layout(&pipeline_layout_info, None)?
|
||||||
|
};
|
||||||
|
log::debug!("Pipeline layout created ({pipeline_layout:?})");
|
||||||
|
|
||||||
|
let pipeline_info = vk::GraphicsPipelineCreateInfo::default()
|
||||||
|
.stages(&shader_stage_create_infos)
|
||||||
|
.vertex_input_state(&vertex_input_info)
|
||||||
|
.input_assembly_state(&input_assembly)
|
||||||
|
.viewport_state(&viewport_state)
|
||||||
|
.rasterization_state(&rasterizer)
|
||||||
|
.multisample_state(&multisampling)
|
||||||
|
.color_blend_state(&color_blending)
|
||||||
|
.dynamic_state(&dynamic_state)
|
||||||
|
.layout(pipeline_layout)
|
||||||
|
.render_pass(render_pass.handle);
|
||||||
|
let pipeline = unsafe {
|
||||||
|
device
|
||||||
|
.handle
|
||||||
|
.create_graphics_pipelines(vk::PipelineCache::null(), &[pipeline_info], None)
|
||||||
|
.map_err(|(_, error)| error)?[0]
|
||||||
|
};
|
||||||
|
log::debug!("Pipeline created ({pipeline_layout:?})");
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
device: device.clone(),
|
||||||
|
render_pass: render_pass.clone(),
|
||||||
|
pipeline_layout,
|
||||||
|
pipeline,
|
||||||
|
vertex_shader: vert_shader_module,
|
||||||
|
fragment_shader: frag_shader_module,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for VkGraphicsPipeline {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
self.device.handle.destroy_pipeline(self.pipeline, None);
|
||||||
|
log::debug!("Pipeline destroyed ({:?})", self.pipeline);
|
||||||
|
|
||||||
|
self.device
|
||||||
|
.handle
|
||||||
|
.destroy_pipeline_layout(self.pipeline_layout, None);
|
||||||
|
log::debug!("Pipeline layout destroyed ({:?})", self.pipeline_layout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
128
src/renderer/vulkan/vk_instance.rs
Normal file
128
src/renderer/vulkan/vk_instance.rs
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
use crate::renderer::vulkan::{
|
||||||
|
utils::layers::{use_layers, LayersSelector},
|
||||||
|
VkPhysicalDevice,
|
||||||
|
};
|
||||||
|
use ash::khr::surface;
|
||||||
|
use ash::{vk, Entry, Instance};
|
||||||
|
use std::ffi::{c_char, CStr, CString};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub struct VkInstance {
|
||||||
|
pub entry: Entry,
|
||||||
|
pub handle: Instance,
|
||||||
|
pub surface_loader: surface::Instance,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VkInstance {
|
||||||
|
pub fn new(required_extensions: &Vec<*const c_char>) -> Self {
|
||||||
|
let entry = Entry::linked();
|
||||||
|
|
||||||
|
log::debug!("Initializing Vulkan instance");
|
||||||
|
|
||||||
|
if log::log_enabled!(log::Level::Debug) {
|
||||||
|
let layer_properties =
|
||||||
|
unsafe { entry.enumerate_instance_layer_properties() }.unwrap_or_default();
|
||||||
|
|
||||||
|
for layer_property in layer_properties {
|
||||||
|
let layer_extensions = unsafe {
|
||||||
|
entry.enumerate_instance_extension_properties(
|
||||||
|
layer_property.layer_name_as_c_str().ok(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.unwrap_or_default();
|
||||||
|
log::debug!("{layer_property:#?} {layer_extensions:#?}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let required_extensions = required_extensions
|
||||||
|
.iter()
|
||||||
|
.map(|str| unsafe { CStr::from_ptr(*str) })
|
||||||
|
.map(|cstr| cstr.to_string_lossy())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
log::debug!(
|
||||||
|
"Required instance extensions: {}",
|
||||||
|
required_extensions.join(", ")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Layers
|
||||||
|
#[allow(unused)]
|
||||||
|
let mut layer_selector = LayersSelector::Nothing;
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
{
|
||||||
|
layer_selector = LayersSelector::SpecificLayers(vec![
|
||||||
|
"VK_LAYER_KHRONOS_validation",
|
||||||
|
"VK_LAYER_MANGOHUD_overlay_x86_64",
|
||||||
|
"VK_LAYER_NV_optimus",
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
let layers = use_layers(&entry, layer_selector);
|
||||||
|
|
||||||
|
{
|
||||||
|
let layers = layers
|
||||||
|
.iter()
|
||||||
|
.map(|layer| layer.to_string_lossy())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
log::debug!("Selected debug layers : {}", layers.join(", "))
|
||||||
|
}
|
||||||
|
|
||||||
|
let layers_raw = layers.iter().map(|s| s.as_ptr()).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// App Info
|
||||||
|
let app_name = CString::new("VulkanTriangle").unwrap();
|
||||||
|
let appinfo = vk::ApplicationInfo::default()
|
||||||
|
.application_name(app_name.as_c_str())
|
||||||
|
.application_version(0)
|
||||||
|
.engine_name(app_name.as_c_str())
|
||||||
|
.engine_version(0)
|
||||||
|
.api_version(vk::make_api_version(0, 1, 0, 0));
|
||||||
|
|
||||||
|
let create_flags = if cfg!(any(target_os = "macos", target_os = "ios")) {
|
||||||
|
vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR
|
||||||
|
} else {
|
||||||
|
vk::InstanceCreateFlags::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Instance Info
|
||||||
|
let create_info = vk::InstanceCreateInfo::default()
|
||||||
|
.application_info(&appinfo)
|
||||||
|
.enabled_layer_names(&layers_raw)
|
||||||
|
.enabled_extension_names(&required_extensions)
|
||||||
|
.flags(create_flags);
|
||||||
|
|
||||||
|
let instance: Instance = unsafe {
|
||||||
|
entry
|
||||||
|
.create_instance(&create_info, None)
|
||||||
|
.expect("Instance creation error")
|
||||||
|
};
|
||||||
|
|
||||||
|
let surface_loader = surface::Instance::new(&entry, &instance);
|
||||||
|
|
||||||
|
log::debug!("Vulkan instance created ({:?})", instance.handle());
|
||||||
|
|
||||||
|
Self {
|
||||||
|
entry,
|
||||||
|
handle: instance,
|
||||||
|
surface_loader,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_physical_devices(instance: &Arc<Self>) -> Vec<VkPhysicalDevice> {
|
||||||
|
let physical_devices = unsafe { instance.handle.enumerate_physical_devices() };
|
||||||
|
physical_devices
|
||||||
|
.unwrap_or_default()
|
||||||
|
.iter()
|
||||||
|
.map(|physical_device| VkPhysicalDevice::new(&instance, *physical_device))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for VkInstance {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
self.handle.destroy_instance(None);
|
||||||
|
}
|
||||||
|
log::debug!("Vulkan instance destroyed ({:?})", self.handle.handle());
|
||||||
|
}
|
||||||
|
}
|
85
src/renderer/vulkan/vk_physical_device.rs
Normal file
85
src/renderer/vulkan/vk_physical_device.rs
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
use super::{VkInstance, VkSurface};
|
||||||
|
use ash::vk;
|
||||||
|
|
||||||
|
pub struct VkPhysicalDevice {
|
||||||
|
instance: Arc<VkInstance>,
|
||||||
|
pub handle: vk::PhysicalDevice,
|
||||||
|
|
||||||
|
pub properties: vk::PhysicalDeviceProperties,
|
||||||
|
pub features: vk::PhysicalDeviceFeatures,
|
||||||
|
pub queue_family_properties: Vec<vk::QueueFamilyProperties>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VkPhysicalDevice {
|
||||||
|
pub fn new(instance: &Arc<VkInstance>, physical_device: vk::PhysicalDevice) -> Self {
|
||||||
|
log::debug!("New physical device");
|
||||||
|
let device_properties = unsafe { instance.handle.get_physical_device_properties(physical_device) };
|
||||||
|
log::debug!("{device_properties:#?}");
|
||||||
|
let device_features = unsafe { instance.handle.get_physical_device_features(physical_device) };
|
||||||
|
log::debug!("{device_features:#?}");
|
||||||
|
let device_queue_families =
|
||||||
|
unsafe { instance.handle.get_physical_device_queue_family_properties(physical_device) };
|
||||||
|
log::debug!("{device_queue_families:#?}");
|
||||||
|
|
||||||
|
Self {
|
||||||
|
instance: Arc::clone(instance),
|
||||||
|
handle: physical_device,
|
||||||
|
properties: device_properties,
|
||||||
|
features: device_features,
|
||||||
|
queue_family_properties: device_queue_families,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_queue_family_by(
|
||||||
|
&self,
|
||||||
|
queue_flags: Option<vk::QueueFlags>,
|
||||||
|
surface: Option<&VkSurface>,
|
||||||
|
) -> Option<(u32, &vk::QueueFamilyProperties)> {
|
||||||
|
self.queue_family_properties.iter().enumerate().find_map(
|
||||||
|
|(index, queue_family_property)| {
|
||||||
|
let surface_check_passed = match surface {
|
||||||
|
Some(surface) => surface
|
||||||
|
.physical_device_queue_supported(self, index as u32)
|
||||||
|
.unwrap_or(false),
|
||||||
|
None => true,
|
||||||
|
};
|
||||||
|
|
||||||
|
let queue_flags_check_passed = match queue_flags {
|
||||||
|
Some(queue_flags) => queue_family_property.queue_flags.contains(queue_flags),
|
||||||
|
None => true,
|
||||||
|
};
|
||||||
|
|
||||||
|
if surface_check_passed && queue_flags_check_passed {
|
||||||
|
Some((index as u32, queue_family_property))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pick_physical_device_and_queue_by<'a>(
|
||||||
|
physical_devices: &'a Vec<VkPhysicalDevice>,
|
||||||
|
queue_flags: Option<vk::QueueFlags>,
|
||||||
|
surface: Option<&VkSurface>,
|
||||||
|
) -> Option<(&'a VkPhysicalDevice, u32, &'a vk::QueueFamilyProperties)> {
|
||||||
|
physical_devices.iter().find_map(|physical_device| {
|
||||||
|
physical_device
|
||||||
|
.find_queue_family_by(queue_flags, surface)
|
||||||
|
.and_then(|(queue_index, queue_family_properties)| {
|
||||||
|
Some((physical_device, queue_index, queue_family_properties))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn priority(&self) -> usize {
|
||||||
|
match self.properties.device_type {
|
||||||
|
vk::PhysicalDeviceType::CPU => 1,
|
||||||
|
vk::PhysicalDeviceType::VIRTUAL_GPU => 2,
|
||||||
|
vk::PhysicalDeviceType::INTEGRATED_GPU => 3,
|
||||||
|
vk::PhysicalDeviceType::DISCRETE_GPU => 4,
|
||||||
|
_ => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
206
src/renderer/vulkan/vk_render_context.rs
Normal file
206
src/renderer/vulkan/vk_render_context.rs
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
use super::{
|
||||||
|
VkCommandPool, VkDevice, VkFence, VkFramebuffer, VkGraphicsPipeline, VkInstance, VkPhysicalDevice,
|
||||||
|
VkRenderPass, VkSemaphore, VkSurface, VkSwapchain,
|
||||||
|
};
|
||||||
|
use ash::vk;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use crate::renderer::Renderable;
|
||||||
|
|
||||||
|
pub struct VkRenderContext {
|
||||||
|
instance: Arc<VkInstance>,
|
||||||
|
surface: Arc<VkSurface>,
|
||||||
|
device: Arc<VkDevice>,
|
||||||
|
|
||||||
|
swapchain: Arc<VkSwapchain>,
|
||||||
|
render_pass: Arc<VkRenderPass>,
|
||||||
|
framebuffers: Vec<Arc<VkFramebuffer>>,
|
||||||
|
|
||||||
|
command_pool: VkCommandPool,
|
||||||
|
command_buffers: Vec<vk::CommandBuffer>,
|
||||||
|
image_available_semaphore: VkSemaphore,
|
||||||
|
render_finished_semaphore: VkSemaphore,
|
||||||
|
in_flight_fence: VkFence,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VkRenderContext {
|
||||||
|
pub fn init(window: &crate::display::Window) -> anyhow::Result<Self> {
|
||||||
|
let required_extensions = window.required_extensions()?;
|
||||||
|
|
||||||
|
let instance = Arc::new(VkInstance::new(&required_extensions));
|
||||||
|
let surface = Arc::new(VkSurface::new(&window, instance.clone())?);
|
||||||
|
|
||||||
|
let mut physical_devices = VkInstance::get_physical_devices(&instance);
|
||||||
|
physical_devices.sort_by(|a, b| b.priority().cmp(&a.priority()));
|
||||||
|
|
||||||
|
let (physical_device, queue_family_index, properties) =
|
||||||
|
VkPhysicalDevice::pick_physical_device_and_queue_by(
|
||||||
|
&physical_devices,
|
||||||
|
Some(vk::QueueFlags::GRAPHICS),
|
||||||
|
Some(&surface),
|
||||||
|
)
|
||||||
|
.ok_or_else(|| anyhow::anyhow!("Unable to find physical device"))?;
|
||||||
|
log::debug!(
|
||||||
|
"Selected queue {properties:#?} for physical device {:?}",
|
||||||
|
physical_device.properties.device_name_as_c_str()
|
||||||
|
);
|
||||||
|
|
||||||
|
let device = Arc::new(VkDevice::new_graphics_device(
|
||||||
|
&instance,
|
||||||
|
&physical_device,
|
||||||
|
queue_family_index,
|
||||||
|
)?);
|
||||||
|
|
||||||
|
let swapchain = Arc::new(VkSwapchain::new(
|
||||||
|
&window,
|
||||||
|
&surface,
|
||||||
|
&device,
|
||||||
|
&physical_device,
|
||||||
|
)?);
|
||||||
|
|
||||||
|
let render_pass = Arc::new(VkRenderPass::new(&device, &swapchain)?);
|
||||||
|
|
||||||
|
let framebuffers = swapchain
|
||||||
|
.create_framebuffers(&render_pass)
|
||||||
|
.ok_or_else(|| anyhow::anyhow!("Failed to get framebuffers"))?;
|
||||||
|
|
||||||
|
let command_pool = VkCommandPool::new(&device)?;
|
||||||
|
|
||||||
|
// Destroyed with command pool
|
||||||
|
let command_buffers = command_pool
|
||||||
|
.allocate_command_buffers_for_framebuffers(framebuffers.len() as u32)?;
|
||||||
|
|
||||||
|
let image_available_semaphore = VkSemaphore::new(&device)?;
|
||||||
|
let render_finished_semaphore = VkSemaphore::new(&device)?;
|
||||||
|
let in_flight_fence = VkFence::new(&device)?;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
instance,
|
||||||
|
surface,
|
||||||
|
device,
|
||||||
|
|
||||||
|
swapchain,
|
||||||
|
render_pass,
|
||||||
|
framebuffers,
|
||||||
|
|
||||||
|
command_pool,
|
||||||
|
command_buffers,
|
||||||
|
|
||||||
|
image_available_semaphore,
|
||||||
|
render_finished_semaphore,
|
||||||
|
in_flight_fence,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(&mut self, scene: Option<&Box<dyn Renderable>>) -> anyhow::Result<()> {
|
||||||
|
unsafe { self.device.handle.wait_for_fences(&[self.in_flight_fence.handle], true, u64::MAX)? };
|
||||||
|
unsafe { self.device.handle.reset_fences(&[self.in_flight_fence.handle])? };
|
||||||
|
|
||||||
|
let (index, _) = self
|
||||||
|
.swapchain
|
||||||
|
.acquire_next_image(&self.image_available_semaphore)?;
|
||||||
|
|
||||||
|
// if self.swapchain.is_dirty() {
|
||||||
|
// self.update_swapchain()?
|
||||||
|
// }
|
||||||
|
|
||||||
|
let command_buffer = self.command_buffers[index as usize];
|
||||||
|
unsafe { self.device.handle.reset_command_buffer(command_buffer, vk::CommandBufferResetFlags::default())? };
|
||||||
|
|
||||||
|
let render_area = vk::Rect2D::default().extent(self.swapchain.surface_resolution);
|
||||||
|
let clear_value = vk::ClearValue::default();
|
||||||
|
let command_buffer_begin_info = vk::CommandBufferBeginInfo::default();
|
||||||
|
unsafe {
|
||||||
|
self.device
|
||||||
|
.handle
|
||||||
|
.begin_command_buffer(command_buffer, &command_buffer_begin_info)?
|
||||||
|
};
|
||||||
|
|
||||||
|
let clear_values = [clear_value];
|
||||||
|
let framebuffer = self.framebuffers[index as usize].as_ref();
|
||||||
|
let render_pass_begin_info = vk::RenderPassBeginInfo::default()
|
||||||
|
.render_pass(self.render_pass.handle)
|
||||||
|
.framebuffer(framebuffer.handle)
|
||||||
|
.render_area(render_area)
|
||||||
|
.clear_values(&clear_values);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
self.device.handle.cmd_begin_render_pass(
|
||||||
|
command_buffer,
|
||||||
|
&render_pass_begin_info,
|
||||||
|
vk::SubpassContents::INLINE,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(scene) = scene {
|
||||||
|
scene.render(&self.device, &self.swapchain, &command_buffer)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe { self.device.handle.cmd_end_render_pass(command_buffer) };
|
||||||
|
|
||||||
|
unsafe { self.device.handle.end_command_buffer(command_buffer)? };
|
||||||
|
|
||||||
|
let wait_semaphores = [self.image_available_semaphore.handle];
|
||||||
|
let signal_semaphores = [self.render_finished_semaphore.handle];
|
||||||
|
let wait_stages = [vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT];
|
||||||
|
let command_buffers_to_submit = [command_buffer];
|
||||||
|
let submit_info = vk::SubmitInfo::default()
|
||||||
|
.wait_semaphores(&wait_semaphores)
|
||||||
|
.wait_dst_stage_mask(&wait_stages)
|
||||||
|
.command_buffers(&command_buffers_to_submit)
|
||||||
|
.signal_semaphores(&signal_semaphores);
|
||||||
|
|
||||||
|
let queue = self
|
||||||
|
.device
|
||||||
|
.get_device_queue(0)
|
||||||
|
.ok_or_else(|| anyhow::anyhow!("Failed to get a queue"))?;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
self.device
|
||||||
|
.handle
|
||||||
|
.queue_submit(*queue, &[submit_info], self.in_flight_fence.handle)?
|
||||||
|
};
|
||||||
|
|
||||||
|
let swapchains = [self.swapchain.handle.unwrap()];
|
||||||
|
let indices = [index];
|
||||||
|
let present_info = vk::PresentInfoKHR::default()
|
||||||
|
.wait_semaphores(&signal_semaphores)
|
||||||
|
.swapchains(&swapchains)
|
||||||
|
.image_indices(&indices);
|
||||||
|
|
||||||
|
unsafe { self.device.swapchain_loader.queue_present(*queue, &present_info)? };
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_resolution(&mut self, width: u32, height: u32) -> anyhow::Result<()> {
|
||||||
|
match Arc::get_mut(&mut self.swapchain) {
|
||||||
|
Some(swapchain) => swapchain.update_resolution(width, height)?,
|
||||||
|
None => log::warn!("Impossible to get mutable swapchain"),
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn exit(&self) {
|
||||||
|
unsafe { self.device.handle.device_wait_idle().unwrap() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_scene(&self, scene: &mut Box<dyn Renderable>) -> anyhow::Result<()> {
|
||||||
|
scene.init(&self.device, &self.render_pass)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_swapchain(&mut self) -> anyhow::Result<()> {
|
||||||
|
match Arc::get_mut(&mut self.swapchain) {
|
||||||
|
Some(swapchain) => {
|
||||||
|
swapchain.create_swapchain()?;
|
||||||
|
|
||||||
|
self.framebuffers = self.swapchain
|
||||||
|
.create_framebuffers(&self.render_pass)
|
||||||
|
.ok_or_else(|| anyhow::anyhow!("Failed to get framebuffers"))?;
|
||||||
|
}
|
||||||
|
None => log::warn!("Impossible to get mutable swapchain"),
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
56
src/renderer/vulkan/vk_render_pass.rs
Normal file
56
src/renderer/vulkan/vk_render_pass.rs
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
use super::{VkDevice, VkSwapchain};
|
||||||
|
use ash::prelude::VkResult;
|
||||||
|
use ash::vk;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub struct VkRenderPass {
|
||||||
|
device: Arc<VkDevice>,
|
||||||
|
|
||||||
|
pub handle: vk::RenderPass,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VkRenderPass {
|
||||||
|
pub fn new(device: &Arc<VkDevice>, swapchain: &Arc<VkSwapchain>) -> VkResult<Self> {
|
||||||
|
let color_attachment = vk::AttachmentDescription::default()
|
||||||
|
.format(swapchain.surface_format.format)
|
||||||
|
.samples(vk::SampleCountFlags::TYPE_1)
|
||||||
|
.load_op(vk::AttachmentLoadOp::CLEAR)
|
||||||
|
.store_op(vk::AttachmentStoreOp::STORE)
|
||||||
|
.stencil_load_op(vk::AttachmentLoadOp::DONT_CARE)
|
||||||
|
.stencil_store_op(vk::AttachmentStoreOp::DONT_CARE)
|
||||||
|
.initial_layout(vk::ImageLayout::UNDEFINED)
|
||||||
|
.final_layout(vk::ImageLayout::PRESENT_SRC_KHR);
|
||||||
|
|
||||||
|
let color_attachment_ref = vk::AttachmentReference::default()
|
||||||
|
.attachment(0)
|
||||||
|
.layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL);
|
||||||
|
|
||||||
|
let color_attachments = [color_attachment_ref];
|
||||||
|
let subpass = vk::SubpassDescription::default()
|
||||||
|
.pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS)
|
||||||
|
.color_attachments(&color_attachments);
|
||||||
|
|
||||||
|
let attachments = [color_attachment];
|
||||||
|
let subpasses = [subpass];
|
||||||
|
let render_pass_info = vk::RenderPassCreateInfo::default()
|
||||||
|
.attachments(&attachments)
|
||||||
|
.subpasses(&subpasses);
|
||||||
|
|
||||||
|
let render_pass = unsafe { device.handle.create_render_pass(&render_pass_info, None)? };
|
||||||
|
log::debug!("Render pass created ({render_pass:?})");
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
device: device.clone(),
|
||||||
|
handle: render_pass,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for VkRenderPass {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
self.device.handle.destroy_render_pass(self.handle, None);
|
||||||
|
log::debug!("Render pass destroyed ({:?})", self.handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
src/renderer/vulkan/vk_semaphore.rs
Normal file
29
src/renderer/vulkan/vk_semaphore.rs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
use super::VkDevice;
|
||||||
|
use ash::vk;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub struct VkSemaphore {
|
||||||
|
device: Arc<VkDevice>,
|
||||||
|
|
||||||
|
pub handle: vk::Semaphore,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VkSemaphore {
|
||||||
|
pub fn new(device: &Arc<VkDevice>) -> anyhow::Result<Self> {
|
||||||
|
let semaphore_info = vk::SemaphoreCreateInfo::default();
|
||||||
|
let semaphore = unsafe { device.handle.create_semaphore(&semaphore_info, None)? };
|
||||||
|
log::debug!("Semaphore created ({semaphore:?})");
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
device: device.clone(),
|
||||||
|
handle: semaphore,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for VkSemaphore {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe { self.device.handle.destroy_semaphore(self.handle, None) };
|
||||||
|
log::debug!("Semaphore destroyed ({:?})", self.handle);
|
||||||
|
}
|
||||||
|
}
|
42
src/renderer/vulkan/vk_shader_module.rs
Normal file
42
src/renderer/vulkan/vk_shader_module.rs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
use super::VkDevice;
|
||||||
|
use ash::vk;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub struct VkShaderModule {
|
||||||
|
device: Arc<VkDevice>,
|
||||||
|
|
||||||
|
pub handle: vk::ShaderModule,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VkShaderModule {
|
||||||
|
pub fn from_spv_file<P: AsRef<Path>>(device: &Arc<VkDevice>, path: P) -> anyhow::Result<Self> {
|
||||||
|
let mut file = std::fs::File::open(&path)?;
|
||||||
|
let frag_shader_str = ash::util::read_spv(&mut file)?;
|
||||||
|
|
||||||
|
let shader_create_info = vk::ShaderModuleCreateInfo::default().code(&frag_shader_str);
|
||||||
|
let shader_module = unsafe {
|
||||||
|
device
|
||||||
|
.handle
|
||||||
|
.create_shader_module(&shader_create_info, None)?
|
||||||
|
};
|
||||||
|
log::debug!(
|
||||||
|
"Shader module created ({shader_module:?}) from {:?}",
|
||||||
|
path.as_ref()
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
device: device.clone(),
|
||||||
|
handle: shader_module,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for VkShaderModule {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
self.device.handle.destroy_shader_module(self.handle, None);
|
||||||
|
log::debug!("Shader module destroyed ({:?})", self.handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
94
src/renderer/vulkan/vk_surface.rs
Normal file
94
src/renderer/vulkan/vk_surface.rs
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
use super::{VkInstance, VkPhysicalDevice};
|
||||||
|
use ash::prelude::VkResult;
|
||||||
|
use ash::vk;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use winit::raw_window_handle::{HasDisplayHandle, HasWindowHandle};
|
||||||
|
|
||||||
|
pub struct SwapchainSupportDetails(
|
||||||
|
pub Vec<vk::SurfaceFormatKHR>,
|
||||||
|
pub vk::SurfaceCapabilitiesKHR,
|
||||||
|
pub Vec<vk::PresentModeKHR>,
|
||||||
|
);
|
||||||
|
|
||||||
|
pub struct VkSurface {
|
||||||
|
instance: Arc<VkInstance>,
|
||||||
|
|
||||||
|
pub handle: vk::SurfaceKHR,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VkSurface {
|
||||||
|
pub fn new(window: &crate::display::Window, instance: Arc<VkInstance>) -> anyhow::Result<Self> {
|
||||||
|
let window_handle = window
|
||||||
|
.handle()
|
||||||
|
.ok_or_else(|| anyhow::anyhow!("Window handle is not available."))?;
|
||||||
|
|
||||||
|
let surface = unsafe {
|
||||||
|
ash_window::create_surface(
|
||||||
|
&instance.entry,
|
||||||
|
&instance.handle,
|
||||||
|
window_handle.display_handle()?.as_raw(),
|
||||||
|
window_handle.window_handle()?.as_raw(),
|
||||||
|
None,
|
||||||
|
)?
|
||||||
|
};
|
||||||
|
|
||||||
|
log::debug!("Surface created ({:?})", surface);
|
||||||
|
|
||||||
|
Ok(Self { instance, handle: surface })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn physical_device_queue_supported(
|
||||||
|
&self,
|
||||||
|
physical_device: &VkPhysicalDevice,
|
||||||
|
queue_index: u32,
|
||||||
|
) -> VkResult<bool> {
|
||||||
|
unsafe {
|
||||||
|
self.instance
|
||||||
|
.surface_loader
|
||||||
|
.get_physical_device_surface_support(
|
||||||
|
physical_device.handle,
|
||||||
|
queue_index,
|
||||||
|
self.handle,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_physical_device_swapchain_support_details(
|
||||||
|
&self,
|
||||||
|
physical_device: &VkPhysicalDevice,
|
||||||
|
) -> VkResult<SwapchainSupportDetails> {
|
||||||
|
unsafe {
|
||||||
|
let formats = self
|
||||||
|
.instance
|
||||||
|
.surface_loader
|
||||||
|
.get_physical_device_surface_formats(physical_device.handle, self.handle)?;
|
||||||
|
|
||||||
|
let capabilities = self
|
||||||
|
.instance
|
||||||
|
.surface_loader
|
||||||
|
.get_physical_device_surface_capabilities(physical_device.handle, self.handle)?;
|
||||||
|
|
||||||
|
let present_modes = self
|
||||||
|
.instance
|
||||||
|
.surface_loader
|
||||||
|
.get_physical_device_surface_present_modes(physical_device.handle, self.handle)?;
|
||||||
|
|
||||||
|
Ok(SwapchainSupportDetails(
|
||||||
|
formats,
|
||||||
|
capabilities,
|
||||||
|
present_modes,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for VkSurface {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
self.instance
|
||||||
|
.surface_loader
|
||||||
|
.destroy_surface(self.handle, None);
|
||||||
|
}
|
||||||
|
log::debug!("Surface destroyed ({:?})", self.handle);
|
||||||
|
}
|
||||||
|
}
|
297
src/renderer/vulkan/vk_swapchain.rs
Normal file
297
src/renderer/vulkan/vk_swapchain.rs
Normal file
|
@ -0,0 +1,297 @@
|
||||||
|
use super::{SwapchainSupportDetails, VkDevice, VkFramebuffer, VkPhysicalDevice, VkRenderPass, VkSemaphore, VkSurface};
|
||||||
|
use crate::display::Window;
|
||||||
|
use ash::prelude::VkResult;
|
||||||
|
use ash::vk;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub struct VkSwapchain {
|
||||||
|
surface: Arc<VkSurface>,
|
||||||
|
device: Arc<VkDevice>,
|
||||||
|
|
||||||
|
pub handle: Option<vk::SwapchainKHR>,
|
||||||
|
swapchain_support_details: SwapchainSupportDetails,
|
||||||
|
|
||||||
|
pub desired_image_count: u32,
|
||||||
|
pub surface_format: vk::SurfaceFormatKHR,
|
||||||
|
pub surface_resolution: vk::Extent2D,
|
||||||
|
pub new_requested_surface_resolution: Option<vk::Extent2D>,
|
||||||
|
pub present_mode: vk::PresentModeKHR,
|
||||||
|
pub pre_transform: vk::SurfaceTransformFlagsKHR,
|
||||||
|
|
||||||
|
pub present_images: Option<Vec<vk::Image>>,
|
||||||
|
pub present_image_views: Option<Vec<Arc<vk::ImageView>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VkSwapchain {
|
||||||
|
pub fn new(
|
||||||
|
window: &Window,
|
||||||
|
surface: &Arc<VkSurface>,
|
||||||
|
device: &Arc<VkDevice>,
|
||||||
|
physical_device: &VkPhysicalDevice,
|
||||||
|
) -> anyhow::Result<Self> {
|
||||||
|
log::debug!("Creating swapchain");
|
||||||
|
|
||||||
|
let window_size = window
|
||||||
|
.physical_size::<u32>()
|
||||||
|
.and_then(|size| {
|
||||||
|
Some(vk::Extent2D {
|
||||||
|
width: size.width,
|
||||||
|
height: size.height,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.ok_or_else(|| anyhow::anyhow!("Failed to get swapchain extent"))?;
|
||||||
|
log::debug!("Window size ({}x{})", window_size.width, window_size.height);
|
||||||
|
|
||||||
|
let swapchain_support_details =
|
||||||
|
surface.get_physical_device_swapchain_support_details(physical_device)?;
|
||||||
|
let SwapchainSupportDetails(surface_formats, surface_capabilities, present_modes) =
|
||||||
|
&swapchain_support_details;
|
||||||
|
log::debug!("Supported surface formats by physical device: {surface_formats:#?}");
|
||||||
|
log::debug!("Surface capabilities: {surface_capabilities:#?}");
|
||||||
|
log::debug!("Present modes: {present_modes:#?}");
|
||||||
|
|
||||||
|
let surface_format = Self::choose_surface_format(surface_formats)
|
||||||
|
.ok_or_else(|| anyhow::anyhow!("No available surface formats"))?;
|
||||||
|
let desired_image_count = Self::choose_desired_image_count(surface_capabilities);
|
||||||
|
let swapchain_extent = Self::choose_swapchain_extent(window_size, surface_capabilities);
|
||||||
|
let pre_transform = Self::choose_pre_transform(surface_capabilities);
|
||||||
|
let present_mode = Self::choose_present_mode(present_modes);
|
||||||
|
|
||||||
|
let mut swapchain = Self {
|
||||||
|
surface: surface.clone(),
|
||||||
|
device: device.clone(),
|
||||||
|
|
||||||
|
handle: None,
|
||||||
|
new_requested_surface_resolution: None,
|
||||||
|
swapchain_support_details,
|
||||||
|
desired_image_count,
|
||||||
|
surface_format,
|
||||||
|
surface_resolution: swapchain_extent,
|
||||||
|
present_mode,
|
||||||
|
pre_transform,
|
||||||
|
present_images: None,
|
||||||
|
present_image_views: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
swapchain.create_swapchain()?;
|
||||||
|
|
||||||
|
Ok(swapchain)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_swapchain(&mut self) -> VkResult<()> {
|
||||||
|
if let Some(new_requested_surface_resolution) = self.new_requested_surface_resolution {
|
||||||
|
self.surface_resolution = new_requested_surface_resolution;
|
||||||
|
self.new_requested_surface_resolution = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut swapchain_create_info = self.create_swapchain_info(&self.surface);
|
||||||
|
|
||||||
|
if let Some(old_swapchain) = self.handle {
|
||||||
|
swapchain_create_info.old_swapchain = old_swapchain;
|
||||||
|
}
|
||||||
|
|
||||||
|
let swapchain = unsafe {
|
||||||
|
self.device
|
||||||
|
.swapchain_loader
|
||||||
|
.create_swapchain(&swapchain_create_info, None)?
|
||||||
|
};
|
||||||
|
|
||||||
|
let present_images = unsafe {
|
||||||
|
self.device
|
||||||
|
.swapchain_loader
|
||||||
|
.get_swapchain_images(swapchain)?
|
||||||
|
};
|
||||||
|
let present_images_view = present_images
|
||||||
|
.iter()
|
||||||
|
.map(|i| {
|
||||||
|
self.create_present_image_view(*i)
|
||||||
|
.expect("Failed to create image view")
|
||||||
|
})
|
||||||
|
.map(|i| Arc::new(i))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
if log::log_enabled!(log::Level::Debug) {
|
||||||
|
let label = match self.handle {
|
||||||
|
None => "Swapchain created",
|
||||||
|
Some(_) => "Swapchain updated",
|
||||||
|
};
|
||||||
|
log::debug!("{label} ({swapchain:?}) : {swapchain_create_info:#?}");
|
||||||
|
}
|
||||||
|
|
||||||
|
self.handle = Some(swapchain);
|
||||||
|
self.present_image_views = Some(present_images_view);
|
||||||
|
self.present_images = Some(present_images);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_framebuffers(
|
||||||
|
&self,
|
||||||
|
render_pass: &Arc<VkRenderPass>,
|
||||||
|
) -> Option<Vec<Arc<VkFramebuffer>>> {
|
||||||
|
let present_image_views = self.present_image_views.as_ref()?;
|
||||||
|
|
||||||
|
Some(
|
||||||
|
present_image_views
|
||||||
|
.iter()
|
||||||
|
.map(|image_view| {
|
||||||
|
VkFramebuffer::from_swapchain_image_view(
|
||||||
|
&self.device,
|
||||||
|
&render_pass,
|
||||||
|
&image_view,
|
||||||
|
&self,
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
})
|
||||||
|
.map(|framebuffer| Arc::new(framebuffer))
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_resolution(&mut self, width: u32, height: u32) -> VkResult<()> {
|
||||||
|
log::debug!("New resolution requested ({width}x{height})");
|
||||||
|
|
||||||
|
let chosen_extent = Self::choose_swapchain_extent(
|
||||||
|
vk::Extent2D { width, height },
|
||||||
|
&self.swapchain_support_details.1,
|
||||||
|
);
|
||||||
|
if chosen_extent.width != self.surface_resolution.width
|
||||||
|
|| chosen_extent.height != self.surface_resolution.height
|
||||||
|
{
|
||||||
|
self.new_requested_surface_resolution = Some(chosen_extent);
|
||||||
|
log::debug!(
|
||||||
|
"New resolution submitted ({}x{})",
|
||||||
|
chosen_extent.width,
|
||||||
|
chosen_extent.height
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
log::debug!("New resolution skipped ({width}x{height}) : Same resolution");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn acquire_next_image(&self, semaphore: &VkSemaphore) -> VkResult<(u32, bool)> {
|
||||||
|
unsafe {
|
||||||
|
self.device.swapchain_loader.acquire_next_image(
|
||||||
|
self.handle.unwrap(),
|
||||||
|
u64::MAX,
|
||||||
|
semaphore.handle,
|
||||||
|
vk::Fence::null(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_dirty(&self) -> bool {
|
||||||
|
self.new_requested_surface_resolution.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_swapchain_info(&self, surface: &VkSurface) -> vk::SwapchainCreateInfoKHR {
|
||||||
|
vk::SwapchainCreateInfoKHR::default()
|
||||||
|
.surface(surface.handle)
|
||||||
|
.min_image_count(self.desired_image_count)
|
||||||
|
.image_color_space(self.surface_format.color_space)
|
||||||
|
.image_format(self.surface_format.format)
|
||||||
|
.image_extent(self.surface_resolution)
|
||||||
|
.image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT)
|
||||||
|
.image_sharing_mode(vk::SharingMode::EXCLUSIVE)
|
||||||
|
.pre_transform(self.pre_transform)
|
||||||
|
.composite_alpha(vk::CompositeAlphaFlagsKHR::OPAQUE)
|
||||||
|
.present_mode(self.present_mode)
|
||||||
|
.clipped(true)
|
||||||
|
.image_array_layers(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn choose_swapchain_extent(
|
||||||
|
window_size: vk::Extent2D,
|
||||||
|
surface_capabilities: &vk::SurfaceCapabilitiesKHR,
|
||||||
|
) -> vk::Extent2D {
|
||||||
|
vk::Extent2D {
|
||||||
|
width: window_size
|
||||||
|
.width
|
||||||
|
.max(surface_capabilities.min_image_extent.width)
|
||||||
|
.min(surface_capabilities.max_image_extent.width),
|
||||||
|
height: window_size
|
||||||
|
.height
|
||||||
|
.max(surface_capabilities.min_image_extent.height)
|
||||||
|
.min(surface_capabilities.max_image_extent.height),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn choose_surface_format(
|
||||||
|
surface_formats: &Vec<vk::SurfaceFormatKHR>,
|
||||||
|
) -> Option<vk::SurfaceFormatKHR> {
|
||||||
|
surface_formats.first().and_then(|f| Some(*f))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn choose_desired_image_count(surface_capabilities: &vk::SurfaceCapabilitiesKHR) -> u32 {
|
||||||
|
let mut desired_image_count = surface_capabilities.min_image_count + 1;
|
||||||
|
if surface_capabilities.max_image_count > 0
|
||||||
|
&& desired_image_count > surface_capabilities.max_image_count
|
||||||
|
{
|
||||||
|
desired_image_count = surface_capabilities.max_image_count;
|
||||||
|
}
|
||||||
|
desired_image_count
|
||||||
|
}
|
||||||
|
|
||||||
|
fn choose_pre_transform(
|
||||||
|
surface_capabilities: &vk::SurfaceCapabilitiesKHR,
|
||||||
|
) -> vk::SurfaceTransformFlagsKHR {
|
||||||
|
if surface_capabilities
|
||||||
|
.supported_transforms
|
||||||
|
.contains(vk::SurfaceTransformFlagsKHR::IDENTITY)
|
||||||
|
{
|
||||||
|
vk::SurfaceTransformFlagsKHR::IDENTITY
|
||||||
|
} else {
|
||||||
|
surface_capabilities.current_transform
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn choose_present_mode(present_modes: &Vec<vk::PresentModeKHR>) -> vk::PresentModeKHR {
|
||||||
|
present_modes
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.find(|&mode| mode == vk::PresentModeKHR::MAILBOX)
|
||||||
|
.unwrap_or(vk::PresentModeKHR::FIFO)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_present_image_view(&self, image: vk::Image) -> VkResult<vk::ImageView> {
|
||||||
|
let create_view_info = vk::ImageViewCreateInfo::default()
|
||||||
|
.view_type(vk::ImageViewType::TYPE_2D)
|
||||||
|
.format(self.surface_format.format)
|
||||||
|
.components(vk::ComponentMapping {
|
||||||
|
r: vk::ComponentSwizzle::IDENTITY,
|
||||||
|
g: vk::ComponentSwizzle::IDENTITY,
|
||||||
|
b: vk::ComponentSwizzle::IDENTITY,
|
||||||
|
a: vk::ComponentSwizzle::IDENTITY,
|
||||||
|
})
|
||||||
|
.subresource_range(vk::ImageSubresourceRange {
|
||||||
|
aspect_mask: vk::ImageAspectFlags::COLOR,
|
||||||
|
base_mip_level: 0,
|
||||||
|
level_count: 1,
|
||||||
|
base_array_layer: 0,
|
||||||
|
layer_count: 1,
|
||||||
|
})
|
||||||
|
.image(image);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
self.device
|
||||||
|
.handle
|
||||||
|
.create_image_view(&create_view_info, None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for VkSwapchain {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if let Some(swapchain) = self.handle {
|
||||||
|
unsafe {
|
||||||
|
self.device
|
||||||
|
.swapchain_loader
|
||||||
|
.destroy_swapchain(swapchain, None);
|
||||||
|
}
|
||||||
|
self.handle = None;
|
||||||
|
log::debug!("Swapchain destroyed ({swapchain:?})");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
4
src/scene/mod.rs
Normal file
4
src/scene/mod.rs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
mod triangle;
|
||||||
|
mod vertex;
|
||||||
|
|
||||||
|
pub use triangle::TriangleScene;
|
49
src/scene/triangle.rs
Normal file
49
src/scene/triangle.rs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
use crate::renderer::vulkan::{VkDevice, VkGraphicsPipeline, VkRenderPass, VkSwapchain};
|
||||||
|
use crate::renderer::Renderable;
|
||||||
|
use ash::vk;
|
||||||
|
use ash::vk::CommandBuffer;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub struct TriangleScene {
|
||||||
|
pipeline: Option<VkGraphicsPipeline>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TriangleScene {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self { pipeline: None }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Renderable for TriangleScene {
|
||||||
|
fn init(&mut self, device: &Arc<VkDevice>, render_pass: &Arc<VkRenderPass>) -> anyhow::Result<()> {
|
||||||
|
let pipeline = VkGraphicsPipeline::new(&device, &render_pass)?;
|
||||||
|
self.pipeline = Some(pipeline);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render(&self, device: &VkDevice, swapchain: &VkSwapchain, command_buffer: &CommandBuffer) -> anyhow::Result<()> {
|
||||||
|
unsafe {
|
||||||
|
device.handle.cmd_bind_pipeline(
|
||||||
|
*command_buffer,
|
||||||
|
vk::PipelineBindPoint::GRAPHICS,
|
||||||
|
self.pipeline.as_ref().unwrap().pipeline,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
let viewport = vk::Viewport::default()
|
||||||
|
.width(swapchain.surface_resolution.width as f32)
|
||||||
|
.height(swapchain.surface_resolution.height as f32)
|
||||||
|
.max_depth(1.0);
|
||||||
|
|
||||||
|
unsafe { device.handle.cmd_set_viewport(*command_buffer, 0, &[viewport]) }
|
||||||
|
|
||||||
|
let scissor = swapchain.surface_resolution.into();
|
||||||
|
|
||||||
|
unsafe { device.handle.cmd_set_scissor(*command_buffer, 0, &[scissor]) }
|
||||||
|
|
||||||
|
unsafe { device.handle.cmd_draw(*command_buffer, 3, 1, 0, 0) };
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
39
src/scene/vertex.rs
Normal file
39
src/scene/vertex.rs
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
use ash::prelude::VkResult;
|
||||||
|
use ash::vk;
|
||||||
|
use crate::renderer::vulkan::{Vertex, VkBuffer, VkDevice};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct VertexScene {
|
||||||
|
vertices: Vec<Vertex>,
|
||||||
|
|
||||||
|
vertices_buffer: Option<VkBuffer>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VertexScene {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let vertices = vec![
|
||||||
|
Vertex::new([0.0, -0.5], [1.0, 0.0, 0.0]),
|
||||||
|
Vertex::new([0.5, 0.5], [0.0, 1.0, 0.0]),
|
||||||
|
Vertex::new([-0.5, 0.5], [0.0, 0.0, 1.0]),
|
||||||
|
];
|
||||||
|
|
||||||
|
Self {
|
||||||
|
vertices,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn create_buffer(&mut self, device: &Arc<VkDevice>) -> VkResult<()> {
|
||||||
|
let buffer_info = vk::BufferCreateInfo::default()
|
||||||
|
.usage(vk::BufferUsageFlags::VERTEX_BUFFER)
|
||||||
|
.sharing_mode(vk::SharingMode::EXCLUSIVE)
|
||||||
|
.size(self.vertices.len() as u64 * size_of::<Vertex>() as u64);
|
||||||
|
|
||||||
|
let buffer = VkBuffer::new(device, &buffer_info)?;
|
||||||
|
self.vertices_buffer = Some(buffer);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue