Merge branch 'dev' into 'master'

Implemented triangle display

See merge request Steins7/iv!16
This commit is contained in:
Steins7 2021-02-05 17:22:16 +01:00
commit 7f9964b627
27 changed files with 2750 additions and 873 deletions

50
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,50 @@
stages:
- build
- test
- doc
stable:cargo:build:
stage: build
script:
- rustup toolchain install stable
- rustup default stable
- rustc --version && cargo --version
- cargo build
stable:cargo:test:
stage: test
dependencies:
- stable:cargo:build
needs:
- stable:cargo:build
script:
- rustup default stable
- rustc --version && cargo --version
- cargo test --jobs 1
nightly:cargo:build:
stage: build
script:
- rustup toolchain install nightly
- rustup default nightly
- rustc --version && cargo --version
- cargo build
allow_failure: true
nightly:cargo:test:
stage: test
dependencies:
- nightly:cargo:build
needs:
- nightly:cargo:build
script:
- rustup default nightly
- rustc --version && cargo --version
- cargo test --jobs 1
allow_failure: true
stable:cargo:doc:
stage: doc
needs: []
script:
- cargo doc

306
Cargo.lock generated
View File

@ -37,18 +37,29 @@ checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
[[package]] [[package]]
name = "ash" name = "ash"
version = "0.30.0" version = "0.31.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69daec0742947f33a85931fa3cb0ce5f07929159dcbd1f0cbb5b2912e2978509" checksum = "c69a8137596e84c22d57f3da1b5de1d4230b1742a710091c85f4d7ce50f00f38"
dependencies = [ dependencies = [
"libloading", "libloading",
] ]
[[package]] [[package]]
name = "autocfg" name = "atty"
version = "1.0.0" version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi 0.3.9",
]
[[package]]
name = "autocfg"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
@ -81,9 +92,9 @@ dependencies = [
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.50" version = "1.0.59"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" checksum = "66120af515773fb005778dc07c261bd201ec8ce50bd6e7144c927753fe013381"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
@ -93,9 +104,9 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]] [[package]]
name = "chrono" name = "chrono"
version = "0.4.11" version = "0.4.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" checksum = "942f72db697d8767c22d46a598e01f2d3b475501ea43d0db4f16d90259182d0b"
dependencies = [ dependencies = [
"num-integer", "num-integer",
"num-traits", "num-traits",
@ -112,27 +123,57 @@ dependencies = [
] ]
[[package]] [[package]]
name = "cocoa" name = "cmake"
version = "0.20.1" version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f7b6f3f7f4f0b3ec5c5039aaa9e8c3cef97a7a480a400fd62944841314f293d" checksum = "eb6210b637171dfba4cda12e579ac6dc73f5165ad56133e5d72ef3131f320855"
dependencies = [
"cc",
]
[[package]]
name = "cocoa"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c49e86fc36d5704151f5996b7b3795385f50ce09e3be0f47a0cfde869681cf8"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"block", "block",
"core-foundation", "core-foundation 0.7.0",
"core-graphics", "core-graphics",
"foreign-types", "foreign-types",
"libc", "libc",
"objc", "objc",
] ]
[[package]]
name = "colored"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59"
dependencies = [
"atty",
"lazy_static",
"winapi 0.3.9",
]
[[package]] [[package]]
name = "core-foundation" name = "core-foundation"
version = "0.7.0" version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171" checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171"
dependencies = [ dependencies = [
"core-foundation-sys", "core-foundation-sys 0.7.0",
"libc",
]
[[package]]
name = "core-foundation"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b5ed8e7e76c45974e15e41bfa8d5b0483cd90191639e01d8f5f1e606299d3fb"
dependencies = [
"core-foundation-sys 0.8.0",
"libc", "libc",
] ]
@ -143,13 +184,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac"
[[package]] [[package]]
name = "core-graphics" name = "core-foundation-sys"
version = "0.19.0" version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59e78b2e0aaf43f08e7ae0d6bc96895ef72ff0921c7d4ff4762201b2dba376dd" checksum = "9a21fa21941700a3cd8fcb4091f361a6a712fac632f85d9f487cc892045d55c6"
[[package]]
name = "core-graphics"
version = "0.19.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3889374e6ea6ab25dba90bb5d96202f61108058361f6dc72e8b03e6f8bbe923"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"core-foundation", "core-foundation 0.7.0",
"foreign-types",
"libc",
]
[[package]]
name = "core-graphics-types"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e92f5d519093a4178296707dbaa3880eae85a5ef5386675f361a1cf25376e93c"
dependencies = [
"bitflags",
"core-foundation 0.9.0",
"foreign-types", "foreign-types",
"libc", "libc",
] ]
@ -161,7 +220,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34ecad23610ad9757664d644e369246edde1803fcb43ed72876565098a5d3828" checksum = "34ecad23610ad9757664d644e369246edde1803fcb43ed72876565098a5d3828"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"core-foundation-sys", "core-foundation-sys 0.7.0",
"core-graphics", "core-graphics",
"libc", "libc",
"objc", "objc",
@ -173,7 +232,7 @@ version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb582b60359da160a9477ee80f15c8d784c477e69c217ef2cdd4169c24ea380f" checksum = "cb582b60359da160a9477ee80f15c8d784c477e69c217ef2cdd4169c24ea380f"
dependencies = [ dependencies = [
"proc-macro2 1.0.18", "proc-macro2 1.0.20",
"quote 1.0.7", "quote 1.0.7",
"syn", "syn",
] ]
@ -186,18 +245,18 @@ checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
[[package]] [[package]]
name = "dlib" name = "dlib"
version = "0.4.1" version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77e51249a9d823a4cb79e3eca6dcd756153e8ed0157b6c04775d04bf1b13b76a" checksum = "b11f15d1e3268f140f68d390637d5e76d849782d971ae7063e0da69fe9709a76"
dependencies = [ dependencies = [
"libloading", "libloading",
] ]
[[package]] [[package]]
name = "downcast-rs" name = "downcast-rs"
version = "1.1.1" version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52ba6eb47c2131e784a38b726eb54c1e1484904f013e576a25354d0124161af6" checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
[[package]] [[package]]
name = "fern" name = "fern"
@ -205,6 +264,7 @@ version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c9a4820f0ccc8a7afd67c39a0f1a0f4b07ca1725164271a64939d7aeb9af065" checksum = "8c9a4820f0ccc8a7afd67c39a0f1a0f4b07ca1725164271a64939d7aeb9af065"
dependencies = [ dependencies = [
"colored",
"log", "log",
] ]
@ -241,39 +301,55 @@ checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
[[package]] [[package]]
name = "gfx-backend-vulkan" name = "gfx-backend-vulkan"
version = "0.5.2" version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebd1dee09bd8d8f1ba52c5ba22d1f70c7ffa990c5eb245eb3ef2d0206f631673" checksum = "a84bda4200a82e1912d575801e2bb76ae19c6256359afbc0adfbbaec02fcadc6"
dependencies = [ dependencies = [
"arrayvec", "arrayvec",
"ash", "ash",
"byteorder", "byteorder",
"core-graphics", "core-graphics-types",
"gfx-hal", "gfx-hal",
"inplace_it",
"lazy_static", "lazy_static",
"log", "log",
"objc", "objc",
"raw-window-handle", "raw-window-handle",
"smallvec", "smallvec",
"winapi 0.3.8", "winapi 0.3.9",
"x11", "x11",
] ]
[[package]] [[package]]
name = "gfx-hal" name = "gfx-hal"
version = "0.5.0" version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc96180204064c9493e0fe4a9efeb721e0ac59fe8e1906d0c659142a93114fb1" checksum = "18d0754f5b7a43915fd7466883b2d1bb0800d7cc4609178d0b27bf143b9e5123"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"raw-window-handle", "raw-window-handle",
] ]
[[package]] [[package]]
name = "instant" name = "hermit-abi"
version = "0.1.2" version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c346c299e3fe8ef94dc10c2c0253d858a69aac1245157a3bf4125915d528caf" checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9"
dependencies = [
"libc",
]
[[package]]
name = "inplace_it"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd01a2a73f2f399df96b22dc88ea687ef4d76226284e7531ae3c7ee1dc5cb534"
[[package]]
name = "instant"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b141fdc7836c525d4d594027d318c84161ca17aaf8113ab1f81ab93ae897485"
[[package]] [[package]]
name = "iovec" name = "iovec"
@ -293,6 +369,9 @@ dependencies = [
"gfx-backend-vulkan", "gfx-backend-vulkan",
"gfx-hal", "gfx-hal",
"log", "log",
"num-traits",
"raw-window-handle",
"shaderc",
"winit", "winit",
] ]
@ -320,24 +399,24 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "lazycell" name = "lazycell"
version = "1.2.1" version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.68" version = "0.2.76"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" checksum = "755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3"
[[package]] [[package]]
name = "libloading" name = "libloading"
version = "0.5.2" version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753" checksum = "2443d8f0478b16759158b2f66d525991a05491138bc05814ef52a250148ef4f9"
dependencies = [ dependencies = [
"cc", "cfg-if",
"winapi 0.3.8", "winapi 0.3.9",
] ]
[[package]] [[package]]
@ -351,18 +430,18 @@ dependencies = [
[[package]] [[package]]
name = "lock_api" name = "lock_api"
version = "0.3.3" version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79b2de95ecb4691949fea4716ca53cdbcfccb2c612e19644a8bad05edcf9f47b" checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75"
dependencies = [ dependencies = [
"scopeguard", "scopeguard",
] ]
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.8" version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
] ]
@ -389,14 +468,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
dependencies = [ dependencies = [
"libc", "libc",
"winapi 0.3.8", "winapi 0.3.9",
] ]
[[package]] [[package]]
name = "mio" name = "mio"
version = "0.6.21" version = "0.6.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "302dec22bcf6bae6dfb69c647187f4b4d0fb6f535521f7bc022430ce8e12008f" checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"fuchsia-zircon", "fuchsia-zircon",
@ -468,13 +547,13 @@ checksum = "2b2820aca934aba5ed91c79acc72b6a44048ceacc5d36c035ed4e051f12d887d"
[[package]] [[package]]
name = "net2" name = "net2"
version = "0.2.33" version = "0.2.34"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" checksum = "2ba7c918ac76704fb42afcbbb43891e72731f3dcca3bef2a19786297baf14af7"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
"winapi 0.3.8", "winapi 0.3.9",
] ]
[[package]] [[package]]
@ -492,9 +571,9 @@ dependencies = [
[[package]] [[package]]
name = "num-integer" name = "num-integer"
version = "0.1.42" version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"num-traits", "num-traits",
@ -502,9 +581,9 @@ dependencies = [
[[package]] [[package]]
name = "num-traits" name = "num-traits"
version = "0.2.11" version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611"
dependencies = [ dependencies = [
"autocfg", "autocfg",
] ]
@ -526,7 +605,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffa5a33ddddfee04c0283a7653987d634e880347e96b5b2ed64de07efb59db9d" checksum = "ffa5a33ddddfee04c0283a7653987d634e880347e96b5b2ed64de07efb59db9d"
dependencies = [ dependencies = [
"proc-macro-crate", "proc-macro-crate",
"proc-macro2 1.0.18", "proc-macro2 1.0.20",
"quote 1.0.7", "quote 1.0.7",
"syn", "syn",
] ]
@ -542,18 +621,18 @@ dependencies = [
[[package]] [[package]]
name = "ordered-float" name = "ordered-float"
version = "1.0.2" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518" checksum = "3741934be594d77de1c8461ebcbbe866f585ea616a9753aa78f2bdc69f0e4579"
dependencies = [ dependencies = [
"num-traits", "num-traits",
] ]
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.10.0" version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92e98c49ab0b7ce5b222f2cc9193fc4efe11c6d0bd4f648e374684a6857b1cfc" checksum = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e"
dependencies = [ dependencies = [
"lock_api", "lock_api",
"parking_lot_core", "parking_lot_core",
@ -561,16 +640,16 @@ dependencies = [
[[package]] [[package]]
name = "parking_lot_core" name = "parking_lot_core"
version = "0.7.0" version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7582838484df45743c8434fbff785e8edf260c28748353d44bc0da32e0ceabf1" checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"cloudabi", "cloudabi",
"libc", "libc",
"redox_syscall", "redox_syscall",
"smallvec", "smallvec",
"winapi 0.3.8", "winapi 0.3.9",
] ]
[[package]] [[package]]
@ -581,15 +660,15 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]] [[package]]
name = "pkg-config" name = "pkg-config"
version = "0.3.17" version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" checksum = "d36492546b6af1463394d46f0c834346f31548646f6ba10849802c9c9a27ac33"
[[package]] [[package]]
name = "proc-macro-crate" name = "proc-macro-crate"
version = "0.1.4" version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e10d4b51f154c8a7fb96fd6dad097cb74b863943ec010ac94b9fd1be8861fe1e" checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785"
dependencies = [ dependencies = [
"toml", "toml",
] ]
@ -605,11 +684,11 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.18" version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa" checksum = "175c513d55719db99da20232b06cda8bab6b83ec2d04e3283edf0213c37c1a29"
dependencies = [ dependencies = [
"unicode-xid 0.2.0", "unicode-xid 0.2.1",
] ]
[[package]] [[package]]
@ -627,7 +706,7 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
dependencies = [ dependencies = [
"proc-macro2 1.0.18", "proc-macro2 1.0.20",
] ]
[[package]] [[package]]
@ -641,9 +720,9 @@ dependencies = [
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.1.56" version = "0.1.57"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
[[package]] [[package]]
name = "rusttype" name = "rusttype"
@ -651,17 +730,16 @@ version = "0.7.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "310942406a39981bed7e12b09182a221a29e0990f3e7e0c971f131922ed135d5" checksum = "310942406a39981bed7e12b09182a221a29e0990f3e7e0c971f131922ed135d5"
dependencies = [ dependencies = [
"rusttype 0.8.2", "rusttype 0.8.3",
] ]
[[package]] [[package]]
name = "rusttype" name = "rusttype"
version = "0.8.2" version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14a911032fb5791ccbeec9f28fdcb9bf0983b81f227bafdfd227c658d0731c8a" checksum = "9f61411055101f7b60ecf1041d87fb74205fb20b0c7a723f07ef39174cf6b4c0"
dependencies = [ dependencies = [
"approx", "approx",
"arrayvec",
"ordered-float", "ordered-float",
"stb_truetype", "stb_truetype",
] ]
@ -683,9 +761,29 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.112" version = "1.0.115"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "736aac72d1eafe8e5962d1d1c3d99b0df526015ba40915cb3c49d042e92ec243" checksum = "e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5"
[[package]]
name = "shaderc"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03f0cb8d1f8667fc9c50d5054be830a117af5f9a15f87c66b72bbca0c2fca484"
dependencies = [
"libc",
"shaderc-sys",
]
[[package]]
name = "shaderc-sys"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c89175f80244b82f882033a81bd188f87307c4c39b2fe8d0f194314f270bdea9"
dependencies = [
"cmake",
"libc",
]
[[package]] [[package]]
name = "slab" name = "slab"
@ -695,9 +793,9 @@ checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
[[package]] [[package]]
name = "smallvec" name = "smallvec"
version = "1.2.0" version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc" checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252"
[[package]] [[package]]
name = "smithay-client-toolkit" name = "smithay-client-toolkit"
@ -726,24 +824,24 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.31" version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5304cfdf27365b7585c25d4af91b35016ed21ef88f17ced89c7093b43dba8b6" checksum = "963f7d3cc59b59b9325165add223142bbf1df27655d07789f109896d353d8350"
dependencies = [ dependencies = [
"proc-macro2 1.0.18", "proc-macro2 1.0.20",
"quote 1.0.7", "quote 1.0.7",
"unicode-xid 0.2.0", "unicode-xid 0.2.1",
] ]
[[package]] [[package]]
name = "time" name = "time"
version = "0.1.42" version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
dependencies = [ dependencies = [
"libc", "libc",
"redox_syscall", "wasi",
"winapi 0.3.8", "winapi 0.3.9",
] ]
[[package]] [[package]]
@ -763,9 +861,9 @@ checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
[[package]] [[package]]
name = "unicode-xid" name = "unicode-xid"
version = "0.2.0" 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 = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]] [[package]]
name = "void" name = "void"
@ -780,10 +878,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
dependencies = [ dependencies = [
"same-file", "same-file",
"winapi 0.3.8", "winapi 0.3.9",
"winapi-util", "winapi-util",
] ]
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]] [[package]]
name = "wayland-client" name = "wayland-client"
version = "0.23.6" version = "0.23.6"
@ -852,9 +956,9 @@ checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.8" 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 = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [ dependencies = [
"winapi-i686-pc-windows-gnu", "winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu",
@ -874,11 +978,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]] [[package]]
name = "winapi-util" name = "winapi-util"
version = "0.1.4" version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa515c5163a99cc82bab70fd3bfdd36d827be85de63737b40fcef2ce084a436e" checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [ dependencies = [
"winapi 0.3.8", "winapi 0.3.9",
] ]
[[package]] [[package]]
@ -895,7 +999,7 @@ checksum = "1e4ccbf7ddb6627828eace16cacde80fc6bf4dbb3469f88487262a02cf8e7862"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"cocoa", "cocoa",
"core-foundation", "core-foundation 0.7.0",
"core-graphics", "core-graphics",
"core-video-sys", "core-video-sys",
"dispatch", "dispatch",
@ -914,7 +1018,7 @@ dependencies = [
"raw-window-handle", "raw-window-handle",
"smithay-client-toolkit", "smithay-client-toolkit",
"wayland-client", "wayland-client",
"winapi 0.3.8", "winapi 0.3.9",
"x11-dl", "x11-dl",
] ]
@ -958,6 +1062,6 @@ checksum = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57"
[[package]] [[package]]
name = "xml-rs" name = "xml-rs"
version = "0.8.2" version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bb76e5c421bbbeb8924c60c030331b345555024d56261dae8f3e786ed817c23" checksum = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a"

View File

@ -7,14 +7,17 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
log = "0.4.8" log = "^0.4.8"
chrono = "0.4.11" chrono = "^0.4.11"
fern = "0.6.0" fern = { version = "^0.6.0", features = ["colored"] }
gfx-hal = "0.5.0" gfx-hal = "^0.6.0"
winit = "0.22.0" winit = "^0.22.0"
raw-window-handle = "^0.3.3"
num-traits = "^0.2.12"
shaderc = "^0.7"
[dependencies.gfx-backend-vulkan] [dependencies.gfx-backend-vulkan]
version = "0.5" version = "^0.6.1"
features = ["x11"] features = ["x11"]
[lib] [lib]
@ -23,5 +26,5 @@ path = "src/lib.rs"
[[bin]] [[bin]]
name = "iv" name = "iv"
path = "src/bin/main.rs" path = "main.rs"

1
doc/architecture Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,17 +1,26 @@
#[allow(unused_imports)] #[allow(unused_imports)]
use log::{debug, error, info, trace, warn}; use log::{debug, error, info, trace, warn};
use chrono; use chrono;
use ::iv::run; use ::iv::run;
fn setup_logger() -> Result<(), fern::InitError> { fn setup_logger() -> Result<(), fern::InitError> {
use fern::colors::{Color, ColoredLevelConfig};
let colors = ColoredLevelConfig::new()
.info(Color::Green)
.debug(Color::Magenta)
.warn(Color::Yellow)
.error(Color::Red);
fern::Dispatch::new() fern::Dispatch::new()
.format(|out, message, record| { .format(move |out, message, record| {
out.finish(format_args!( out.finish(format_args!(
"{}[{}][{}] {}", "{}[{}][{}] {}",
chrono::Local::now().format("[%H:%M:%S]"), chrono::Local::now().format("[%H:%M:%S]"),
record.level(), colors.color(record.level()),
record.target(), record.target(),
message message
)) ))
@ -23,17 +32,11 @@ fn setup_logger() -> Result<(), fern::InitError> {
Ok(()) Ok(())
} }
//pub fn draw_frame(hal : &mut HalState, local : &LocalState) -> Result<(), &'static str> {
//
// hal.draw_clear_frame(local.color());
//}
pub fn main() -> Result<(), &'static str> { pub fn main() -> Result<(), &'static str> {
setup_logger().unwrap(); setup_logger().unwrap();
run()?; run()?;
//print!("test");
Ok(()) Ok(())
} }

217
src/controller.rs Normal file
View File

@ -0,0 +1,217 @@
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use crate::{
io::{Input, Output},
subengine::SubenginePipeline,
};
//--Controller Implementation-----------------------------------------------------------------------
pub struct Controller<'a, I, W, O>
where
I: Input,
W: raw_window_handle::HasRawWindowHandle,
O: Output<W>,
{
pipelines: Vec<SubenginePipeline<'a, I, W, O>>,
mouse_pos: [f32; 2],
color: [f32; 3],
}
impl<I, W, O> Controller<'_, I, W, O>
where
I: Input,
W: raw_window_handle::HasRawWindowHandle,
O: Output<W>,
{
pub fn new<'a, Ip>(pipelines: Ip) -> Controller<'a, I, W, O>
where
I: 'a + Input,
W: raw_window_handle::HasRawWindowHandle,
O: 'a + Output<W>,
Ip: IntoIterator<Item = SubenginePipeline<'a, I, W, O>>,
{
let pipelines_vec = pipelines
.into_iter()
.map(|pipeline| pipeline)
.collect();
Controller {
pipelines: pipelines_vec,
mouse_pos: [0.5, 0.5],
color: [1.0, 1.0, 1.0],
}
}
pub fn run(&mut self) {
use std::time::Duration; //, SystemTime};
use crate::{
subengine::subengine_controller::SubengineCommand,
io::Key,
utils::Triangle,
};
let mut input_keys: Vec<Key> = Vec::new();
loop {
// let frame_start = SystemTime::now();
for pipeline in &mut self.pipelines {
for input in &pipeline.inputs {
match input.borrow().read(Duration::from_millis(1)) {
Ok(key) => input_keys.push(key),
Err(_err) => (),
}
}
for input_key in &input_keys {
match input_key {
Key::MouseMove{x,y} => {
self.mouse_pos = [
(x/1280.0 * 2.0 - 1.0) as f32,
(y/720.0 * 2.0 - 1.0) as f32,
];
self.color = [
(x/1280.0) as f32,
(y/720.0) as f32,
(((x + y)/2.0)/((1280.0 + 720.0)/2.0)) as f32,
];
},
Key::Close => {
info!("Shutting down IV !");
return;
}
_ => (),
};
}
for subengines in &pipeline.subengines {
for subengine in subengines {
subengine.exec(SubengineCommand::Run);
}
for subengine in subengines {
subengine.wait_for_exec(Duration::from_millis(10)).unwrap();
}
}
let triangle = Triangle {
points: [self.mouse_pos, [-0.5, 0.5], [-0.5, -0.5]],
};
let colors = [
[self.color[0], self.color[1], self.color[2]],
[self.color[2], self.color[0], self.color[1]],
[self.color[1], self.color[2], self.color[0]],
];
for (renderer, output) in &mut pipeline.renderers {
// match renderer.draw_clear_frame(output, self.color) {
// Err(err) => warn!("{}", err),
// _ => (),
// }
match renderer.draw_triangle_frame(output, triangle, colors) {
Err(err) => warn!("{}", err),
_ => (),
};
};
};
// let frame_time = SystemTime::now()
// .duration_since(frame_start)
// .unwrap();
//
// let sleep_time = Duration::from_secs_f32(1.0/60.0)
// .checked_sub(frame_time)
// .unwrap_or_else(|| {
// info!("Engine overloaded !");
// Duration::from_secs(0)
// });
// std::thread::sleep(sleep_time);
//
// info!("FPS : {}", 1.0/frame_time.as_secs_f32());// + sleep_time.as_secs_f32()));
}
}
}
//These tests are disabled because of some stange issue with cargo not waiting for the drop
//functions to execute before executing the next test or something like that...
#[cfg(test)]
#[allow(dead_code)]
mod tests {
use super::*;
use std::iter;
use crate::{
io::WinitWindow,
renderer::Renderer,
utils::Rect,
subengine::{SubengineController, TestSubengine},
};
use gfx_backend_vulkan as vk_back;
//#[test]
fn test_new() {
use std::cell::RefCell;
//creating windows
let window1 = RefCell::new(WinitWindow::new("IV", Rect {w: 1280, h: 720}).unwrap());
let window2 = RefCell::new(WinitWindow::new("IV 2", Rect {w: 720, h: 480}).unwrap());
//creating renderers
let renderer1 = Renderer::<vk_back::Backend>::new(&mut iter::once(&window1)).unwrap();
let renderer2 = Renderer::<vk_back::Backend>::new(&mut iter::once(&window2)).unwrap();
//creating subengines
let (test_subengine1, _test_rx1) = TestSubengine::new("run1");
let test_controller1 = SubengineController::new(test_subengine1);
let (test_subengine2, _test_rx2) = TestSubengine::new("run2");
let test_controller2 = SubengineController::new(test_subengine2);
//preparing data
let inputs = vec![&window1, &window2];
let subengines = vec![vec![test_controller1, test_controller2]];
let renderers = vec![(renderer1, &window1), (renderer2, &window2)];
//creating pipeline
let subengine_pipeline = SubenginePipeline::new(inputs, subengines, renderers);
//creating controller
let _controller = Controller::new(vec![subengine_pipeline]);
}
//#[test]
fn test_run() {
use std::cell::RefCell;
//creating windows
let window1 = RefCell::new(WinitWindow::new("IV", Rect {w: 1280, h: 720}).unwrap());
let window2 = RefCell::new(WinitWindow::new("IV 2", Rect {w: 720, h: 480}).unwrap());
//creating renderers
let renderer1 = Renderer::<vk_back::Backend>::new(&mut iter::once(&window1)).unwrap();
let renderer2 = Renderer::<vk_back::Backend>::new(&mut iter::once(&window2)).unwrap();
//creating subengines
let (test_subengine1, _test_rx1) = TestSubengine::new("run1");
let test_controller1 = SubengineController::new(test_subengine1);
let (test_subengine2, _test_rx2) = TestSubengine::new("run2");
let test_controller2 = SubengineController::new(test_subengine2);
//preparing data
let inputs = vec![&window1, &window2];
let subengines = vec![vec![test_controller1, test_controller2]];
let renderers = vec![(renderer1, &window1), (renderer2, &window2)];
//creating pipeline
let subengine_pipeline = SubenginePipeline::new(inputs, subengines, renderers);
//running controller
let mut controller = Controller::new(vec![subengine_pipeline]);
for _i in 0..10 {
controller.run();
}
}
}

View File

@ -1,42 +0,0 @@
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use winit::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
};
#[derive(Debug)]
pub struct Input {
pub close_request: bool,
pub new_frame_size: Option<(f64, f64)>,
pub new_mouse_pos: Option<(f64, f64)>,
}
impl Input {
pub fn poll_events_loop(event_loop: &mut EventLoop<()>) -> Self {
let mut input = Input::default();
event_loop.run(|event, _, control_flow| {
*control_flow = ControlFlow::Wait;
match event {
Event::WindowEvent{window_id: _, event} => match event {
WindowEvent::CloseRequested => (),
_ => (),
}
_ => (),
}
});
input
}
pub fn default() -> Self {
Input {
close_request: false,
new_frame_size: None,
new_mouse_pos: None,
}
}
}

84
src/io.rs Normal file
View File

@ -0,0 +1,84 @@
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use std::time::Duration;
use raw_window_handle::HasRawWindowHandle;
use crate::utils::Rect;
pub mod winit_window;
pub use self::winit_window::WinitWindow;
//--Output trait------------------------------------------------------------------------------------
/// A trait for the ability of a type to be used as an output by the engine.
///
/// The `Output` trait defines functions to be used by different components of the engine. This
/// allows to display with any window manager as long as the trait is defined for it.
///
/// Types that implement the `Output` trait should manage the underlying window and settings.
///
/// Implementation : the ID and size stored by the type implementing this trait don't need to be
/// initialized to anything specific as the engine will take care of it.
pub trait Output<W>
where
W: HasRawWindowHandle,
{
/// Return the ID stored internally. Used to select the right swapchain by the render engine.
/// For internal use only.
fn get_id(&self) -> usize;
/// Store the given ID internally. For internal use only.
fn set_id(&mut self, id: usize);
//TODO clean that
/// Give mutable acces to the size of the output. The size is a simple rectangle containing the
/// width and height of the `Output`.
fn size(&mut self) -> &mut Rect<i32>;
/// Give reference acces to the underlying window. This is used by the engine during setup to
/// create the revelant ressources.
fn window(&self) -> &W;
}
//--Input trait-------------------------------------------------------------------------------------
/// A trait for the ability of a type to be used as an input by the engine
///
/// The `Input` trait defines functions used by different components of the engine. The allow to
/// read inputs from any window manzger as long as the is defined for it.
///
/// Types that implement the `Input` trait should manage the EventLoop. This can be done in any way
/// (polling, interrupt, synchronous, asynchronous, ...) depending on how the input should be
/// handled.
pub trait Input {
/// Return the next input available or a ReadError if an error occured of the timeout duration
/// was reached. How inputs are handled depends on the implementation.
//TODO change timeout
fn read(&self, timeout: Duration) -> Result<Key, ReadError>;
fn write(&self, signal: Signal);
}
//--Key enum----------------------------------------------------------------------------------------
#[derive(Debug)]
pub enum Key {
Close,
Closed,
Test,
MouseMove { x: f64, y: f64 },
}
//--Signal enum-------------------------------------------------------------------------------------
#[derive(Debug)]
pub enum Signal {
Exit,
Test,
}
//--ReadError enum----------------------------------------------------------------------------------
#[derive(Debug)]
pub enum ReadError {
Timeout,
}

177
src/io/: Normal file
View File

@ -0,0 +1,177 @@
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use std::{
thread,
sync::mpsc,
time::Duration,
};
use winit::{
dpi::PhysicalSize,
event_loop::{EventLoop, EventLoopProxy},
window::{WindowBuilder, Window},
};
//TODO fix that
use crate::{
io::{Output, Input, Key, Signal, ReadError},
utils::Rect,
};
#[derive(Debug)]
pub struct WinitWindow {
pub name: String,
size: Rect<i32>,
id: usize,
receiver: mpsc::Receiver<Key>,
window: Window,
event_loop_proxy: EventLoopProxy<Signal>,
}
impl Drop for WinitWindow {
fn drop(&mut self) {
use winit::event::Event;
// kill event_loop
if self.event_loop_proxy.send_event(Signal::Exit).is_err() {
warn!("EventLoop thread is dead before Exit signal");
}
//while match self.read(Duration::from_millis(1)) {
// Ok(Key::Closed) => false,
// _ => true,
//} {}
}
}
impl WinitWindow {
pub fn new(title: &str, size: Rect<i32>) -> Result<WinitWindow, &'static str> {
use winit::platform::unix::EventLoopExtUnix;
debug!("Creating window");
let name = title.to_string();
let id = 0;
//Since we can't move the EventLoop from one thread to another, we need to create it in the
//right thread and then move the Window back to the main thread instead
let cloned_name = name.clone();
let (tx, rx) = mpsc::channel();
let (tmp_tx, tmp_rx) = mpsc::sync_channel(1);
let builder = thread::Builder::new().name(title);
//the EventLoop hijacks the thread so there is no need to join it later...
thread::spawn(move || {
trace!("Creating Window in EventLoop thread");
//winit doesn't like us creating the EventLoop in another thread either so we have to
//drop crossplatform compatibility :/
let event_loop = EventLoop::new_any_thread();
let window = WindowBuilder::new()
.with_inner_size(PhysicalSize {width: size.w, height: size.h})
.with_title(cloned_name)
.build(&event_loop).unwrap();
let event_loop_proxy = event_loop.create_proxy();
trace!("Sending Window back to main thread");
tmp_tx.send((window, event_loop_proxy)).unwrap();
event_loop.run(move |event: winit::event::Event<'_, Signal>, _, control_flow| {
use winit::{
event_loop::ControlFlow,
event::Event,
event,
};
*control_flow = ControlFlow::Wait;
match event {
Event::LoopDestroyed => {
tx.send(Key::Closed).unwrap();
debug!("Closed EventLoop");
},
Event::WindowEvent{window_id: _, event} => match event {
event::WindowEvent::CloseRequested => {
debug!("Close requested");
tx.send(Key::Close).unwrap();
},
event::WindowEvent::CursorMoved{position, ..} => {
tx.send(Key::MouseMove{
x: position.x,
y: position.y,
}).unwrap();
},
_ => (),
},
Event::UserEvent(signal) => match signal {
Signal::Exit => {
debug!("Stopping input thread...");
*control_flow = ControlFlow::Exit;
},
Signal::Test => {
tx.send(Key::Test).unwrap();
},
},
_ => (),
}})
});
let (window, event_loop_proxy) = tmp_rx.recv().unwrap();
trace!("Received Window in main thread");
Ok(Self {
name,
size,
id,
receiver: rx,
window,
event_loop_proxy,
})
}
}
impl Output<Window> for WinitWindow {
fn get_id(&self) -> usize { self.id }
fn set_id(&mut self, id: usize) { self.id = id; }
fn size(&mut self) -> &mut Rect<i32> { &mut self.size }
fn window(&self) -> &Window { &self.window }
}
impl Input for WinitWindow {
fn read(&self, timeout: Duration) -> Result<Key, ReadError> {
match self.receiver.recv_timeout(timeout) {
Ok(key) => Ok(key),
Err(_) => Err(ReadError::Timeout),
}
}
fn write(&self, signal: Signal) {
self.event_loop_proxy.send_event(signal)
.map_err(|_| "Could not send Signal to EventLoop").unwrap();
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::utils::Rect;
#[test]
fn test_new_drop() {
let _window1 = WinitWindow::new("IV", Rect {w: 1280, h: 720}).unwrap();
let _window2 = WinitWindow::new("IV", Rect {w: 1280, h: 720}).unwrap();
panic!("test");
}
#[test]
fn test_read_write() {
let window = WinitWindow::new("IV", Rect {w: 1280, h: 720}).unwrap();
window.write(Signal::Test);
let input = window.read(Duration::from_millis(1)).unwrap();
assert!(matches!(input, Key::Test));
}
}

225
src/io/winit_window.rs Normal file
View File

@ -0,0 +1,225 @@
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use std::{
thread,
sync::mpsc,
time::Duration,
};
use winit::{
dpi::PhysicalSize,
event_loop::{EventLoop, EventLoopProxy},
window::{WindowBuilder, Window},
};
use crate::{
io::{Output, Input, Key, Signal, ReadError},
utils::Rect,
};
#[derive(Debug)]
pub struct WinitWindow {
pub name: String,
size: Rect<i32>,
id: usize,
receiver: mpsc::Receiver<Key>,
window: Window,
event_loop_proxy: EventLoopProxy<Signal>,
}
impl Drop for WinitWindow {
fn drop(&mut self) {
// kill event_loop
debug!("Sending kill signal...");
if self.event_loop_proxy.send_event(Signal::Exit).is_err() {
warn!("EventLoop thread is dead before Exit signal");
}
trace!("Kill signal sent");
while match self.read(Duration::from_millis(1)) {
Ok(Key::Closed) => false,
Err(err) => match err {
ReadError::Timeout => false,
//_ => true,
},
_ => true,
} {}
trace!("Dropped window !");
}
}
impl WinitWindow {
pub fn new(title: &str, size: Rect<i32>) -> Result<WinitWindow, &'static str> {
use winit::platform::unix::EventLoopExtUnix;
debug!("Creating window");
let name = title.to_string();
let id = 0;
//Since we can't move the EventLoop from one thread to another, we need to create it in the
//right thread and then move the Window back to the main thread instead
let cloned_name = name.clone();
let (tx, rx) = mpsc::sync_channel(1);
let (tmp_tx, tmp_rx) = mpsc::sync_channel(1);
let builder = thread::Builder::new().name(title.into());
//the EventLoop hijacks the thread so there is no need to join it later...
//TODO manage errors here
let _ = builder.spawn(move || {
trace!("Creating Window in EventLoop thread");
//winit doesn't like us creating the EventLoop in another thread either so we have to
//drop crossplatform compatibility :/
let event_loop = EventLoop::new_any_thread();
let window = WindowBuilder::new()
.with_inner_size(PhysicalSize {width: size.w, height: size.h})
.with_title(cloned_name)
.build(&event_loop).unwrap();
let event_loop_proxy = event_loop.create_proxy();
trace!("Sending Window back to main thread");
tmp_tx.send((window, event_loop_proxy)).unwrap();
event_loop.run(move |event: winit::event::Event<'_, Signal>, _, control_flow| {
use winit::{
event_loop::ControlFlow,
event::Event,
event,
};
*control_flow = ControlFlow::Wait;
match event {
Event::LoopDestroyed => {
tx.send(Key::Closed).unwrap();
debug!("Closed EventLoop");
return;
},
Event::WindowEvent{window_id: _, event} => match event {
event::WindowEvent::CloseRequested => {
debug!("Close requested");
tx.send(Key::Close).unwrap();
},
event::WindowEvent::CursorMoved{position, ..} => {
let _ = tx.try_send(Key::MouseMove{
x: position.x,
y: position.y,
});
},
_ => (),
},
Event::UserEvent(signal) => match signal {
Signal::Exit => {
debug!("Stopping input thread...");
*control_flow = ControlFlow::Exit;
},
Signal::Test => {
tx.send(Key::Test).unwrap();
},
},
_ => (),
}})
});
let (window, event_loop_proxy) = tmp_rx.recv().unwrap();
trace!("Received Window in main thread");
Ok(Self {
name,
size,
id,
receiver: rx,
window,
event_loop_proxy,
})
}
}
impl Output<Window> for WinitWindow {
fn get_id(&self) -> usize { self.id }
fn set_id(&mut self, id: usize) { self.id = id; }
fn size(&mut self) -> &mut Rect<i32> { &mut self.size }
fn window(&self) -> &Window { &self.window }
}
impl Input for WinitWindow {
fn read(&self, timeout: Duration) -> Result<Key, ReadError> {
match self.receiver.recv_timeout(timeout) {
Ok(key) => Ok(key),
Err(_) => Err(ReadError::Timeout),
}
}
fn write(&self, signal: Signal) {
self.event_loop_proxy.send_event(signal)
.map_err(|_| "Could not send Signal to EventLoop").unwrap();
}
}
//These tests are disabled for now because they cause some sort of bug with cargo where it doesn't
//take into account other failed tests, even inn single threaded tests. No idea what's going on...
#[cfg(test)]
#[allow(dead_code)]
mod tests {
use super::*;
use crate::utils::Rect;
fn setup_logger() -> Result<(), fern::InitError> {
use fern::colors::{Color, ColoredLevelConfig};
let colors = ColoredLevelConfig::new()
.info(Color::Green)
.debug(Color::Magenta)
.warn(Color::Yellow)
.error(Color::Red);
fern::Dispatch::new()
.format(move |out, message, record| {
out.finish(format_args!(
"{}[{}][{}] {}",
chrono::Local::now().format("[%H:%M:%S]"),
colors.color(record.level()),
record.target(),
message
))
})
.level(log::LevelFilter::Trace)
.chain(std::io::stdout())
.chain(fern::log_file("output.log")?)
.apply()?;
Ok(())
}
//#[test]
fn test_new_drop() {
use std::mem::ManuallyDrop;
let _ = setup_logger();
let mut window1 = ManuallyDrop::new(WinitWindow::new("IV",
Rect {w: 1280, h: 720}).unwrap());
let mut window2 = ManuallyDrop::new(WinitWindow::new("IV 2",
Rect {w: 1280, h: 720}).unwrap());
unsafe {
ManuallyDrop::drop(&mut window1);
ManuallyDrop::drop(&mut window2);
}
}
//#[test]
fn test_read_write() {
let window = WinitWindow::new("IV", Rect {w: 1280, h: 720}).unwrap();
window.write(Signal::Test);
let input = window.read(Duration::from_millis(1)).unwrap();
assert!(matches!(input, Key::Test));
}
}

View File

@ -5,26 +5,29 @@
#[allow(unused_imports)] #[allow(unused_imports)]
use log::{debug, error, info, trace, warn}; use log::{debug, error, info, trace, warn};
use std::{ use gfx_backend_vulkan as vk_back;
sync::mpsc,
thread,
collections::HashMap,
cell::RefCell,
};
mod winit_state; pub mod io;
use winit_state::WinitState;
use winit::{ pub mod subengine;
event::{Event, WindowEvent}, use subengine::SubenginePipeline;
event_loop::ControlFlow,
}; pub mod controller;
use controller::Controller;
pub mod utils;
//use utils::Rect;
mod renderer; mod renderer;
use renderer::Renderer; //use renderer::Renderer;
//mod local_state; //mod controller;
//use local_state::LocalState; //use controller::Controller;
//use crate::engine::{
// EngineController,
// TestEngine,
//};
pub enum Command { pub enum Command {
NoCommand, NoCommand,
@ -51,101 +54,44 @@ pub enum Input {
/// The main function of the library /// The main function of the library
pub fn run() -> Result<(), &'static str> { pub fn run() -> Result<(), &'static str> {
let winit_state = WinitState::default(); use std::{
let mut renderer = Renderer::new(&winit_state.window)?; iter,
//let local_state = LocalState::default(); cell::RefCell,
let (input_tx, input_rx) = mpsc::channel();
let mut window_senders = HashMap::with_capacity(1);
window_senders.insert(1, input_tx);
let control_thread = RefCell::new(Some(thread::spawn(move || {
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
let (cmd_tx, cmd_rx) = mpsc::channel();
let render_thread = thread::spawn(move || {
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
let mut color = [0.0, 0.0, 0.0, 0.0];
loop {
//TODO manage errors
let _ = renderer.draw_clear_frame(color);
match cmd_rx.try_recv().unwrap_or(Command::NoCommand) {
Command::NoCommand => (),
Command::Stop => {
warn!("Stop render thread");
return;
},
Command::Color{r, g, b, a} => {
color = [r, g, b, a];
},
}
}
});
loop {
match input_rx.recv().unwrap() {
Input::Close => {
cmd_tx.send(Command::Stop).unwrap();
//TODO stop event_loop
warn!("wait for render thread");
render_thread.join().unwrap();
warn!("Stop control thread");
return;
},
Input::Mouse{x, y} => {
let pos = Command::Color{
r: (x/1280.0) as f32,
g: (y/720.0) as f32,
b: ((x/1280.0 + y/720.0)/2.0) as f32,
a: 1.0,
}; };
cmd_tx.send(pos).unwrap();
},
}
}
})));
winit_state.event_loop.run(move |event, _, control_flow| { use crate::{
#[allow(unused_imports)] io::WinitWindow,
use log::{debug, error, info, trace, warn}; renderer::Renderer,
utils::Rect,
subengine::{SubengineController, TestSubengine},
};
*control_flow = ControlFlow::Wait; //creating windows
let window1 = RefCell::new(WinitWindow::new("IV", Rect {w: 1280, h: 720}).unwrap());
//let window2 = RefCell::new(WinitWindow::new("IV 2", Rect {w: 720, h: 480}).unwrap());
//TODO manage errors //creating renderers
let input_tx = window_senders.get(&1).unwrap(); let renderer1 = Renderer::<vk_back::Backend>::new(&mut iter::once(&window1)).unwrap();
match event { //let renderer2 = Renderer::<vk_back::Backend>::new(&mut iter::once(&window2)).unwrap();
Event::WindowEvent{window_id: _, event} => match event {
WindowEvent::CloseRequested => { //creating subengines
input_tx.send(Input::Close).unwrap(); let (test_subengine1, _test_rx1) = TestSubengine::new("run1");
let handle = control_thread.replace(None).unwrap(); let test_controller1 = SubengineController::new(test_subengine1);
warn!("Wait for control thread"); //let (test_subengine2, _test_rx2) = TestSubengine::new("run2");
handle.join().unwrap(); //let test_controller2 = SubengineController::new(test_subengine2);
warn!("Stop input thread");
*control_flow = ControlFlow::Exit; //preparing data
}, let inputs = vec![&window1];
WindowEvent::CursorMoved{position, ..} => { let subengines = vec![vec![test_controller1/*, test_controller2*/]];
input_tx let renderers = vec![(renderer1, &window1)/*, (renderer2, &window2)*/];
.send(Input::Mouse{
x: position.x, //creating pipeline
y: position.y}) let subengine_pipeline = SubenginePipeline::new(inputs, subengines, renderers);
.unwrap();
}, //running controller
_ => (), let mut controller = Controller::new(vec![subengine_pipeline]);
} controller.run();
_ => (),
} Ok(())
});
} }
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}

View File

@ -1,42 +1,278 @@
use std::mem::ManuallyDrop; #[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use gfx_hal::{ use std::{
queue::QueueGroup, mem::ManuallyDrop,
Backend, iter,
pso::Rect, cell::RefCell,
}; };
use gfx_backend_vulkan as vk_back; use crate::{
io::Output,
utils::Triangle,
pub mod init; };
pub mod render;
mod gpu;
use self::gpu::Gpu;
mod swap_system;
use self::swap_system::SwapSystem;
mod pipeline;
use self::pipeline::Pipeline;
//--Renderer implementation-------------------------------------------------------------------------
#[derive(Debug)] #[derive(Debug)]
pub struct Renderer { pub struct Renderer<B: gfx_hal::Backend> {
//items need to communicate with the GPU instance: ManuallyDrop<B::Instance>,
instance: ManuallyDrop<<vk_back::Backend as Backend>::Instance>, gpu: ManuallyDrop<Gpu<B>>,
surface: ManuallyDrop<<vk_back::Backend as Backend>::Surface>, swap_systems: Vec<SwapSystem<B>>,
adapter: ManuallyDrop<gfx_hal::adapter::Adapter<vk_back::Backend>>, pipelines: Vec<Pipeline<B>>,
device: vk_back::Device, }
queue_group: ManuallyDrop<QueueGroup<vk_back::Backend>>,
render_pass: ManuallyDrop<<vk_back::Backend as Backend>::RenderPass>, impl<B> Drop for Renderer<B>
swapchain: ManuallyDrop<<vk_back::Backend as Backend>::Swapchain>, where
extent: gfx_hal::window::Extent2D, B: gfx_hal::Backend,
format: gfx_hal::format::Format, {
render_area: Rect, fn drop(&mut self) {
use gfx_hal::{
//items needed to render the images Instance,
sems_image_available: Vec<<vk_back::Backend as Backend>::Semaphore>, device::Device,
sems_render_finished: Vec<<vk_back::Backend as Backend>::Semaphore>, };
fences: Vec<<vk_back::Backend as Backend>::Fence>,
image_views: Vec<<vk_back::Backend as Backend>::ImageView>, debug!("Waiting for device to idle...");
framebuffers: Vec<<vk_back::Backend as Backend>::Framebuffer>, let _ = self.gpu
.device()
command_pool: ManuallyDrop<<vk_back::Backend as Backend>::CommandPool>, .wait_idle();
command_buffers: Vec<<vk_back::Backend as Backend>::CommandBuffer>,
debug!("Dropping Pipelines...");
//items needed to keep track of the images for pipeline in self.pipelines.drain(..) {
image_count: usize, pipeline.drop(&mut self.gpu);
current_image: usize, }
info!("Dropping Renderer...");
unsafe {
debug!("Dropping SwapSystems...");
for mut swap_system in self.swap_systems.drain(..) {
self.instance.destroy_surface(swap_system.drop(&mut self.gpu));
}
ManuallyDrop::drop(&mut self.gpu);
ManuallyDrop::drop(&mut self.instance);
}
debug!("Renderer dropped !");
}
}
impl<B> Renderer<B>
where
B: gfx_hal::Backend,
{
pub fn new<'a, W: 'a, O: 'a, I>(outputs: &mut I) -> Result<Renderer<B>, &'static str>
where
W: raw_window_handle::HasRawWindowHandle,
O: Output<W>,
I: Iterator<Item = &'a RefCell<O>>,
{
use gfx_hal::Instance;
info!("Creating renderer...");
let instance = B::Instance::create("IV", 1)
.map_err(|_| "Could not create instance")?;
let (mut gpu, mut surfaces) = Gpu::new(&instance, outputs)
.map_err(|err| err)?;
let swap_systems = {
surfaces
.drain(..)
.map(|surface| SwapSystem::new(&mut gpu, surface))
.collect::<Result<Vec<_>, &str>>()?
};
let pipelines = vec!(Pipeline::new(&mut gpu, &swap_systems[0]) //TODO improve that
.map_err(|err| err)?);
debug!("Renderer created !");
Ok( Renderer {
instance: ManuallyDrop::new(instance),
gpu: ManuallyDrop::new(gpu),
swap_systems,
pipelines,
})
}
pub fn draw_clear_frame<W, O>(&mut self, output: &RefCell<O>, color: [f32; 4])
-> Result<(), &'static str>
where
W: raw_window_handle::HasRawWindowHandle,
O: Output<W>,
{
use gfx_hal::{
window::AcquireError,
device::Device,
queue::Submission,
};
let swap_system = &mut self.swap_systems[output.borrow_mut().get_id()];
let mut frame = match swap_system.acquire_frame(&self.gpu) {
Ok(frame) => frame,
Err(err) => match err {
AcquireError::NotReady => {
return Err("Frame acquisition failed because all Frames are in use");
},
AcquireError::OutOfDate => {
swap_system.recreate(&mut self.gpu)?;
debug!("SwapSystem : {:#?}", swap_system);
return Ok(());
},
_ => Err("Could not acquire Frame from SwapSystem")?,
}};
trace!("Waiting for Frame...");
unsafe {
let _ = self.gpu.device()
.wait_for_fence(&frame.fences[0], !0)
.map_err(|_| "Failed to wait for Fence")?;
let _ = self.gpu.device()
.reset_fence(&frame.fences[0])
.map_err(|_| "Failed to reset fence")?;
}
trace!("Recording CommandBuffer...");
unsafe {
use gfx_hal::command::{
CommandBufferFlags,
SubpassContents,
ClearValue,
ClearColor,
CommandBuffer,
};
frame.command_buffer.begin_primary(CommandBufferFlags::ONE_TIME_SUBMIT);
let clear_value = ClearValue {color: ClearColor{float32: color}};
frame.command_buffer.begin_render_pass(
&swap_system.render_pass,
&frame.framebuffer.as_ref().unwrap(),
swap_system.render_area,
iter::once(clear_value),
SubpassContents::Inline,
);
frame.command_buffer.end_render_pass();
frame.command_buffer.finish();
}
trace!("Submiting to queue...");
let submission = Submission {
command_buffers: iter::once(&*frame.command_buffer),
wait_semaphores: None,
signal_semaphores: iter::once(&frame.signal_semaphores[0]),
};
unsafe {
use gfx_hal::queue::CommandQueue;
self.gpu.queue_mut().submit(submission, Some(&frame.fences[0]));
}
let result = swap_system.present_frame(frame, &mut self.gpu);
if result.is_err() {
swap_system.recreate(&mut self.gpu).unwrap();
}
Ok(())
}
pub fn draw_triangle_frame<W, O>(&mut self,
output: &RefCell<O>,
triangle: Triangle,
colors: [[f32; 3]; 3])
-> Result<(), &'static str>
where
W: raw_window_handle::HasRawWindowHandle,
O: Output<W>,
{
use gfx_hal::{
window::AcquireError,
queue::Submission,
};
let swap_system = &mut self.swap_systems[output.borrow_mut().get_id()];
let mut frame = match swap_system.acquire_frame(&self.gpu) {
Ok(frame) => frame,
Err(err) => match err {
AcquireError::NotReady => {
return Err("Frame acquisition failed because all Frames are in use");
},
AcquireError::OutOfDate => {
swap_system.recreate(&mut self.gpu)?;
debug!("SwapSystem : {:#?}", swap_system);
return Ok(());
},
_ => Err("Could not acquire Frame from SwapSystem")?,
}};
trace!("Uploading triangle data...");
let points = triangle.points_flat();
self.pipelines[0].write_vertex_buffer(&self.gpu, 0, (&points).to_vec())?; //TODO meh
let colors_flat = colors.iter().flatten().copied().collect();
self.pipelines[0].write_vertex_buffer(&self.gpu, 1, colors_flat)?;
trace!("Recording CommandBuffer...");
unsafe {
use gfx_hal::command::{
CommandBufferFlags,
SubpassContents,
ClearValue,
ClearColor,
CommandBuffer,
};
frame.command_buffer.begin_primary(CommandBufferFlags::ONE_TIME_SUBMIT);
const TRIANGLE_CLEAR: ClearValue =
ClearValue {color : ClearColor{float32 : [0.5, 0.5, 0.5, 1.0]}};
frame.command_buffer.begin_render_pass(
&swap_system.render_pass,
&frame.framebuffer.as_ref().unwrap(),
swap_system.render_area,
iter::once(TRIANGLE_CLEAR),
SubpassContents::Inline,
);
frame.command_buffer.bind_graphics_pipeline(self.pipelines[0].raw_pipeline());
// storing const data via the CommandBuffer
//let buffer_ref: &B::Buffer = &self.buffer;
//let buffers: Vec<[_; 1]> = vec![(buffer_ref, 0)].into();
frame.command_buffer.bind_vertex_buffers(0, self.pipelines[0].raw_vertex_buffers());
frame.command_buffer.draw(0..3, 0..1);
frame.command_buffer.end_render_pass();
frame.command_buffer.finish();
}
trace!("Submiting to queue...");
let submission = Submission {
command_buffers: iter::once(&*frame.command_buffer),
wait_semaphores: None,
signal_semaphores: iter::once(&frame.signal_semaphores[0]),
};
unsafe {
use gfx_hal::queue::CommandQueue;
self.gpu.queue_mut().submit(submission, Some(&frame.fences[0]));
}
let result = swap_system.present_frame(frame, &mut self.gpu);
if result.is_err() {
swap_system.recreate(&mut self.gpu).unwrap();
}
Ok(())
}
} }

214
src/renderer/gpu.rs Normal file
View File

@ -0,0 +1,214 @@
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use std::{
mem::ManuallyDrop,
ptr::read,
cell::RefCell,
};
use gfx_hal::{
adapter::Adapter,
queue::QueueGroup,
};
use gfx_hal::adapter::Gpu as GfxGpu;
use crate::io::Output;
//--Gpu implementation------------------------------------------------------------------------------
/// A struct managing all things related to a specific GPU
///
/// The `GPU` struct manages the structs from the gfx_hal[gfx_hal] related to the physical device.
/// It implements constructor and destructors as well as acces functions. This is done to make the
/// usage of the HAL easier and make the higher level code less dependant on changes in it.
#[derive(Debug)]
pub struct Gpu<B: gfx_hal::Backend> {
adapter: ManuallyDrop<Adapter<B>>,
device: ManuallyDrop<B::Device>,
queue_group: ManuallyDrop<QueueGroup<B>>,
command_pool: ManuallyDrop<B::CommandPool>,
}
impl<B> Drop for Gpu<B>
where
B: gfx_hal::Backend,
{
fn drop(&mut self) {
use gfx_hal::device::Device;
debug!("Dropping Gpu...");
unsafe {
self.device.destroy_command_pool(
ManuallyDrop::into_inner(read(&mut self.command_pool)));
ManuallyDrop::drop(&mut self.queue_group);
ManuallyDrop::drop(&mut self.device);
ManuallyDrop::drop(&mut self.adapter);
}
trace!("Gpu dropped !");
}
}
impl<B> Gpu<B>
where
B: gfx_hal::Backend,
{
/// Create a new `GPU` based on an `instance` of the gfx_hal[gfx_hal].
pub fn new<'a, W, O: 'a, I>(instance: &B::Instance, outputs: &mut I)
-> Result<(Gpu<B>, Vec<B::Surface>), &'static str>
where
W: raw_window_handle::HasRawWindowHandle,
O: Output<W>,
I: Iterator<Item = &'a RefCell<O>>,
{
use gfx_hal::{
queue::family::QueueFamily,
};
debug!("Creating Gpu...");
trace!("Creating Surfaces...");
let surfaces: Vec<_> = {
use gfx_hal::Instance;
let mut id = 0;
outputs
.by_ref()
.map(|output| unsafe {
output.borrow_mut().set_id(id);
id += 1;
instance
.create_surface(output.borrow().window())
.map_err(|_| "Could not create surface")
})
.collect::<Result<Vec<_>, &str>>()?
};
let adapter = {
use gfx_hal::{
Instance,
window::Surface,
adapter::DeviceType,
};
// dry run to print all adapters for debug purposes
trace!("Listing Adapters...");
let adapters = instance
.enumerate_adapters()
.into_iter();
debug!("Adapters : {:#?}", adapters);
// selecting an adapter suitabe for all surfaces used
//TODO improve selection
trace!("Selecting Adapter...");
let adapter = instance
.enumerate_adapters()
.into_iter()
.filter(|a| {
a.queue_families
.iter()
.any(|qf|
QueueFamily::queue_type(qf).supports_graphics()
&& surfaces
.iter()
.all(|surface|
surface.supports_queue_family(&qf)
))})
.max_by_key(|adapter| {
match adapter.info.device_type {
DeviceType::DiscreteGpu => 4,
DeviceType::IntegratedGpu => 3,
DeviceType::VirtualGpu => 2,
DeviceType::Other => 1,
DeviceType::Cpu => 0,
}})
.ok_or("Could not find a graphical adapter")?;
info!("Selected adapter : {}", adapter.info.name);
adapter
};
let (device, queue_group) = {
// get the previously found QueueFamily index
trace!("Getting QueueFamily index...");
let queue_family = adapter
.queue_families
.iter()
.find(|qf|
QueueFamily::queue_type(*qf).supports_graphics())
//&& Surface::supports_queue_family(&surface, &qf))
.ok_or("Could not find suitable queue_family")?;
// get the related PhysicalDevice and QueueFamily list
trace!("Get Device and QueueGroups...");
let GfxGpu {device, queue_groups} = unsafe {
use gfx_hal::{
adapter::PhysicalDevice,
Features,
};
adapter
.physical_device
.open(&[(&queue_family, &[1.0; 1])], Features::empty())
.map_err(|_| "Could not open physical device")?
};
// retrieve the selected QueueFamily
trace!("Selecting QueueGroup...");
let queue_group = queue_groups
.into_iter()
.find(|qg| qg.family == queue_family.id())
.ok_or("Could not take ownership of the queue")?;
// check the QueueGroup
trace!("Checking selected QueueGroup...");
if queue_group.queues.len() <= 0 {
return Err("The QueueGroup does not have any CommandQueues available");
};
(device, queue_group)
};
let command_pool = unsafe {
use gfx_hal::{
pool::CommandPoolCreateFlags,
device::Device,
};
trace!("Creating CommandPool...");
device
.create_command_pool(queue_group.family,
CommandPoolCreateFlags::RESET_INDIVIDUAL)
.map_err(|_| "Could not create CommandPool")?
};
debug!("Gpu created !");
Ok((
Gpu {
adapter: ManuallyDrop::new(adapter),
device: ManuallyDrop::new(device),
queue_group: ManuallyDrop::new(queue_group),
command_pool: ManuallyDrop::new(command_pool),
},
surfaces
))
}
pub fn adapter(&self) -> &Adapter<B> {
&self.adapter
}
pub fn device(&self) -> &B::Device {
&self.device
}
pub fn command_pool_mut(&mut self) -> &mut B::CommandPool {
&mut self.command_pool
}
pub fn queue_mut(&mut self) -> &mut B::CommandQueue {
&mut self.queue_group.queues[0]
}
}

View File

@ -1,415 +0,0 @@
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use std::{
mem::ManuallyDrop,
};
use core::ptr::read;
use gfx_hal::{
Instance,
device::Device,
Backend,
pool::CommandPool,
pso::Rect,
};
use gfx_backend_vulkan as vk_back;
use winit::window::Window;
use crate::renderer::Renderer;
impl core::ops::Drop for Renderer {
//----------------------------------------------------------------------------------------------
fn drop(&mut self) {
let _ = self.device.wait_idle();
//destroy all underlying ressources
debug!("Destroying Renderer ressources");
unsafe {
self.command_pool.free(self.command_buffers.drain(..));
self.device.destroy_command_pool(
ManuallyDrop::into_inner(read(&mut self.command_pool)));
for buffer in self.framebuffers.drain(..) {
self.device.destroy_framebuffer(buffer);
}
for view in self.image_views.drain(..) {
self.device.destroy_image_view(view);
}
for fence in self.fences.drain(..) {
self.device.destroy_fence(fence);
}
for sem in self.sems_image_available.drain(..) {
self.device.destroy_semaphore(sem);
}
for sem in self.sems_render_finished.drain(..) {
self.device.destroy_semaphore(sem);
}
self.device.destroy_swapchain(ManuallyDrop::into_inner(read(&mut self.swapchain)));
self.device.destroy_render_pass(ManuallyDrop::into_inner(read(&mut self.render_pass)));
ManuallyDrop::drop(&mut self.queue_group);
ManuallyDrop::drop(&mut self.adapter);
self.instance.destroy_surface(ManuallyDrop::into_inner(read(&mut self.surface)));
ManuallyDrop::drop(&mut self.instance);
}
info!("Renderer ressources destroyed");
}
}
impl Renderer {
//----------------------------------------------------------------------------------------------
pub fn update_swapchain(&mut self) -> Result<(), &'static str> {
use gfx_hal::window::{
SwapchainConfig,
Surface,
PresentationSurface,
};
debug!("Updating swapchain");
//creating new swapchain config
let capabilities = self.surface.capabilities(&self.adapter.physical_device);
let swapchain_config = SwapchainConfig::from_caps(&capabilities, self.format, self.extent);
info!("{:?}", swapchain_config);
self.device
.wait_idle()
.map_err(|_| "Failed to to wait for device to be idle")?;
unsafe {
self.surface
.configure_swapchain(&self.device, swapchain_config)
.map_err(|_| "Failed to updtate swapchain")?;
debug!("update succesfull !");
}
Ok(())
}
//----------------------------------------------------------------------------------------------
pub fn new(window: &Window) -> Result<Renderer, &'static str> {
use gfx_hal::adapter::Gpu;
// create top level
let instance = vk_back::Instance::create("IV", 1)
.map_err(|_| "Could not create instance")?;
let mut surface = unsafe {
instance
.create_surface(window)
.map_err(|_| "Could not create Surface")?
};
let (adapter, device, queue_group) = {
use gfx_hal::{
window::Surface,
queue::family::QueueFamily,
};
// find a adapter with a suitable queue family
// TODO add weight for adapters
let adapter =
Instance::enumerate_adapters(&instance)
.into_iter();
// .find(|a| {
// a.queue_families
// .iter()
// .any(|qf|
// QueueFamily::queue_type(qf).supports_graphics()
// && Surface::supports_queue_family(&surface, &qf)
// )})
// .ok_or("Could not find a graphical adapter")?;
debug!("Adapters : {:#?}", adapter);
let adapter =
Instance::enumerate_adapters(&instance)
.into_iter()
.find(|a| {
a.queue_families
.iter()
.any(|qf|
QueueFamily::queue_type(qf).supports_graphics()
&& Surface::supports_queue_family(&surface, &qf)
)})
.ok_or("Could not find a graphical adapter")?;
info!("Selected adapter : {}", adapter.info.name);
// get the suitable queue family index
let queue_family = adapter
.queue_families
.iter()
.find(|qf|
QueueFamily::queue_type(*qf).supports_graphics()
&& Surface::supports_queue_family(&surface, &qf))
.ok_or("Could not find suitable queue_family")?;
// get the related physical device and queue family list
let Gpu {device, queue_groups} = unsafe {
use gfx_hal::{
adapter::PhysicalDevice,
Features,
};
adapter
.physical_device
.open(&[(&queue_family, &[1.0; 1])], Features::empty())
.map_err(|_| "Could not open physical device")?
};
// retrieve the selected queue family
let queue_group = queue_groups
.into_iter()
.find(|qg| qg.family == queue_family.id())
.ok_or("Could not take ownership of the queue")?;
// check our harvest
if queue_group.queues.len() <= 0 {
return Err("The QueueGroup does not have any CommandQueues available");
};
(adapter, device, queue_group)
};
let (swapchain, extent, backbuffer, format, image_count) = {
use gfx_hal::window::{
SwapchainConfig,
Surface,
};
let capabilities = surface.capabilities(&adapter.physical_device);
debug!("{:#?}", capabilities);
// select optimal presentation mode (vsync, triple buffuring, ...)
let present_mode = {
use gfx_hal::window::PresentMode;
[PresentMode::MAILBOX, PresentMode::FIFO,
PresentMode::RELAXED, PresentMode::IMMEDIATE]
.iter()
.cloned()
.find(|pm| capabilities.present_modes.contains(*pm))
.ok_or("No PresentMode found")?
};
// select optimal alpha composition
// let composite_alpha_mode = {
// use gfx_hal::window::CompositeAlphaMode;
//
// [CompositeAlphaMode::OPAQUE, CompositeAlphaMode::INHERIT,
// CompositeAlphaMode::PREMULTIPLIED, CompositeAlphaMode::POSTMULTIPLIED]
// .iter()
// .cloned()
// .find(|cam| capabilities.composite_alpha_modes.contains(*cam))
// .ok_or("No CompositeAlphaMode found")?
// };
// select optimal format (sRGB)
let format = {
use gfx_hal::format::{Format, ChannelType};
match surface.supported_formats(&adapter.physical_device) {
None => Format::Rgba8Srgb,
Some(formats) => formats
.iter()
.find(|f| f.base_format().1 == ChannelType::Srgb)
.cloned()
.ok_or("Could no find suitabe format")?
}};
let extent = capabilities.extents.end().clone();
// verify swapchain size
let image_count = {
use gfx_hal::window::PresentMode;
capabilities.image_count.end()
.min(capabilities.image_count.start()
.max(match present_mode {
PresentMode::MAILBOX => &3,
PresentMode::FIFO => &2,
_ => &1,
})).clone()
};
debug!("image count : {}", image_count);
// // a surface support at least one layer
// let image_layers = 1;
//
// // verify surface compatibility
// let image_usage = {
// use gfx_hal::image::Usage;
//
// if capabilities.usage.contains(Usage::COLOR_ATTACHMENT) {
// Ok(Usage::COLOR_ATTACHMENT)
// } else {
// Err("This surface does not support color")
// }
// }?;
let swapchain_config = SwapchainConfig::from_caps(&capabilities, format, extent);
debug!("{:?}", swapchain_config);
let (swapchain, backbuffer) = unsafe {
device
.create_swapchain(&mut surface, swapchain_config, None)
.map_err(|_| "Failed to create swapchain and backbuffer")?
};
(swapchain, extent, backbuffer, format, image_count as usize)
};
// creating semaphores and fences
let (sems_image_available, sems_render_finished, fences) = {
let mut sems_image_available : Vec<<vk_back::Backend as Backend>::Semaphore> = vec![];
let mut sems_render_finished : Vec<<vk_back::Backend as Backend>::Semaphore> = vec![];
let mut fences :Vec<<vk_back::Backend as Backend>::Fence> = vec![];
for _ in 0..image_count {
sems_image_available
.push(device
.create_semaphore()
.map_err(|_| "Could not create sempahore")?
);
sems_render_finished
.push(device
.create_semaphore()
.map_err(|_| "Could not create sempahore")?
);
fences
.push(device
.create_fence(true)
.map_err(|_| "Could not create fence")?
);
}
(sems_image_available, sems_render_finished, fences)
};
// creating RenderPass
let render_pass = {
use gfx_hal::{
pass::{Attachment, AttachmentOps, AttachmentLoadOp, AttachmentStoreOp, SubpassDesc},
image::Layout,
};
let color_attachment = Attachment {
format : Some(format),
samples : 1,
ops : AttachmentOps {
load : AttachmentLoadOp::Clear,
store : AttachmentStoreOp::Store,
},
stencil_ops : AttachmentOps::DONT_CARE,
layouts : (Layout::Undefined..Layout::Present),
};
let subpass = SubpassDesc {
colors : &[(0, Layout::ColorAttachmentOptimal)],
depth_stencil : None,
inputs : &[],
resolves : &[],
preserves : &[],
};
unsafe {
device.create_render_pass(&[color_attachment], &[subpass], &[])
.map_err(|_| "Could not create render pass")?
}
};
// add ImageView "headers" to images in BackBuffer
let image_views : Vec<_> = {
use gfx_hal::{
image::{ViewKind, SubresourceRange},
format::{Swizzle, Aspects},
};
backbuffer
.iter()
.map(|img| unsafe {
device
.create_image_view(
&img,
ViewKind::D2,
format,
Swizzle::NO,
SubresourceRange {
aspects : Aspects::COLOR,
levels : 0..1,
layers : 0..1,
},
)
.map_err(|_| "Could not create ImageViews")
})
.collect::<Result<Vec<_>, &str>>()?
};
let framebuffers: Vec<_> = {
image_views
.iter()
.map(|image_view|
unsafe {
device
.create_framebuffer(&render_pass, vec![image_view], extent.to_extent())
.map_err(|_| "Could not create FrameBuffer")
},
)
.collect::<Result<Vec<_>, &str>>()?
};
let mut command_pool = unsafe {
use gfx_hal::pool::CommandPoolCreateFlags;
device
.create_command_pool(queue_group.family, CommandPoolCreateFlags::RESET_INDIVIDUAL)
.map_err(|_| "Could not create CommandPool")?
};
let command_buffers: Vec<_> = unsafe {
use gfx_hal::command::Level;
framebuffers
.iter()
.map(|_| command_pool.allocate_one(Level::Primary))
.collect()
};
info!("HAL successfully initialized");
Ok(
Renderer {
instance: ManuallyDrop::new(instance),
surface: ManuallyDrop::new(surface),
adapter: ManuallyDrop::new(adapter),
device: device,
queue_group: ManuallyDrop::new(queue_group),
render_pass: ManuallyDrop::new(render_pass),
swapchain: ManuallyDrop::new(swapchain),
extent: extent,
format: format,
render_area: Rect{x: 0, y: 0, w: 1280, h: 720},
sems_image_available,
sems_render_finished,
fences,
image_views,
framebuffers,
command_pool: ManuallyDrop::new(command_pool),
command_buffers,
image_count,
current_image: 0,
}
)
}
}

306
src/renderer/pipeline.rs Normal file
View File

@ -0,0 +1,306 @@
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use std::mem::{ManuallyDrop, size_of};
use gfx_hal::{
buffer::SubRange,
};
use super::{
gpu::Gpu,
swap_system::SwapSystem,
};
mod attachement;
use self::attachement::Attachement;
static VERT_SRC: &'static str = include_str!("shaders/base.vert");
static FRAG_SRC: &'static str = include_str!("shaders/base.frag");
//--Pipeline implementation-------------------------------------------------------------------------
#[derive(Debug)]
pub struct Pipeline<B: gfx_hal::Backend> {
set_layout: Vec<B::DescriptorSetLayout>,
layout: ManuallyDrop<B::PipelineLayout>,
gfx_pipeline: ManuallyDrop<B::GraphicsPipeline>,
vertex_buffers: Vec<Attachement<B>>,
}
impl<B> Pipeline<B>
where
B: gfx_hal::Backend,
{
pub fn drop(mut self, gpu: &mut Gpu<B>) {
use std::ptr::read;
use gfx_hal::device::Device;
debug!("Dropping Pipeline...");
for buffer in self.vertex_buffers.drain(..) {
buffer.drop(gpu);
}
unsafe {
gpu.device()
.destroy_graphics_pipeline(
ManuallyDrop::into_inner(read(&mut self.gfx_pipeline)));
gpu.device()
.destroy_pipeline_layout(
ManuallyDrop::into_inner(read(&mut self.layout)));
for layout in self.set_layout.drain(..) {
gpu.device().destroy_descriptor_set_layout(layout);
}}
}
pub fn new(gpu: &mut Gpu<B>, swap_system: &SwapSystem<B>) -> Result<Pipeline<B>, &'static str> {
use gfx_hal::{
device::Device,
pso::{EntryPoint, Specialization, VertexBufferDesc, VertexInputRate, AttributeDesc,
Element, InputAssemblerDesc, Primitive, PrimitiveAssemblerDesc, Rasterizer,
PolygonMode, Face, FrontFace, State, DepthStencilDesc, BakedStates, Viewport,
DescriptorSetLayoutBinding, ShaderStageFlags
},
format::Format,
};
use std::borrow::Cow;
debug!("Compiling shaders...");
let mut compiler = shaderc::Compiler::new().ok_or("shaderc not found")?;
let vertex_compile_artifact = compiler
.compile_into_spirv(VERT_SRC, shaderc::ShaderKind::Vertex, "vertex.vert",
"main",
None)
.map_err(|err| {error!("{}", err);
"Could not compile vertex shader"})?;
let fragment_compile_artifact = compiler
.compile_into_spirv(FRAG_SRC, shaderc::ShaderKind::Fragment, "fragement.frag",
"main",
None)
.map_err(|err| {error!("{}", err);
"Could not compile fragment shader"})?;
trace!("Creating ShaderModules...");
let vertex_shader_module = unsafe {
gpu.device()
.create_shader_module(vertex_compile_artifact.as_binary())
.map_err(|err| {error!("{}", err);
"Could not create vertex shader module"})?
};
let fragment_shader_module = unsafe {
gpu.device()
.create_shader_module(fragment_compile_artifact.as_binary())
.map_err(|err| {error!("{}", err);
"Could not create fragment shader module"})?
};
trace!("Creating shader set...");
let (vs_entry, fs_entry) = (
EntryPoint {
entry: "main",
module: &vertex_shader_module,
specialization: Specialization {
constants: Cow::Borrowed{0: &[]},
data: Cow::Borrowed{0: &[]},
},
},
EntryPoint {
entry: "main",
module: &fragment_shader_module,
specialization: Specialization {
constants: Cow::Borrowed{0: &[]},
data: Cow::Borrowed{0: &[]},
},
},
);
trace!("Creating PrimitiveAssembler...");
let buffers: Vec<VertexBufferDesc> =
vec![
VertexBufferDesc {
binding: 0,
stride: (size_of::<f32>()*2) as u32,
rate: VertexInputRate::Vertex,
},
VertexBufferDesc {
binding: 1,
stride: (size_of::<f32>()*3) as u32,
rate: VertexInputRate::Vertex,
}];
let attributes: Vec<AttributeDesc> =
vec![
AttributeDesc {
location: 0,
binding: 0,
element: Element {
format: Format::Rgb32Sfloat,
offset: 0,
},
},
AttributeDesc {
location: 1,
binding: 1,
element: Element {
format: Format::Rgb32Sfloat,
offset: 0,
},
}];
let input_assembler = InputAssemblerDesc {
primitive: Primitive::TriangleList, //TODO switch to strips
with_adjacency: false,
restart_index: None,
};
let primitive_assembler = PrimitiveAssemblerDesc::Vertex {
buffers: &buffers,
attributes: &attributes,
input_assembler,
vertex: vs_entry,
tessellation: None,
geometry: None,
};
trace!("Creating Rasterizer...");
let rasterizer = Rasterizer {
polygon_mode: PolygonMode::Fill,
cull_face: Face::NONE, //TODO adjut that
front_face: FrontFace::CounterClockwise,
depth_clamping: false,
depth_bias: None,
conservative: false,
line_width: State::Static{0: 1.0}, //TODO may need to be changed
};
trace!("Configuring color blending...");
let blender = {
use gfx_hal::pso::{BlendState, BlendOp, Factor, BlendDesc, LogicOp, ColorBlendDesc,
ColorMask};
let blend_state = BlendState {
color: BlendOp::Add {
src: Factor::One,
dst: Factor::Zero,
},
alpha: BlendOp::Add {
src: Factor::One,
dst: Factor::Zero,
}};
BlendDesc {
logic_op: Some(LogicOp::Copy),
targets: vec![
ColorBlendDesc {
mask: ColorMask::ALL,
blend: Some(blend_state),
}]}
};
trace!("Configuring depth options...");
let depth_stencil = DepthStencilDesc {
depth: None,
depth_bounds: false,
stencil: None,
};
trace!("Configuring baked-in pipeline states...");
let baked_states = BakedStates {
viewport: Some(Viewport {
rect: swap_system.render_area.clone(),
depth: (0.0..1.0),
}),
scissor: Some(swap_system.render_area.clone()),
blend_color: None,
depth_bounds: None,
};
trace!("Creating PipelineLayout...");
let set_layout = {
let bindings = Vec::<DescriptorSetLayoutBinding>::new();
let immutable_samplers = Vec::<B::Sampler>::new();
unsafe {
vec![gpu.device()
.create_descriptor_set_layout(bindings, immutable_samplers)
.map_err(|_| "Could not create DescriptorSetLayout")?
]}};
let layout = {
let push_constants = Vec::<(ShaderStageFlags, std::ops::Range<u32>)>::new();
unsafe {
gpu.device()
.create_pipeline_layout(&set_layout, push_constants)
.map_err(|_| "Could not create PipelineLayout")?
}};
debug!("Creating GraphicsPipeline...");
let gfx_pipeline = {
use gfx_hal::{
pso::{GraphicsPipelineDesc, PipelineCreationFlags, BasePipeline},
pass::Subpass,
};
//manual deref for ManuallyDrop to not cause troubles
let render_pass_ref: &B::RenderPass = &swap_system.render_pass;
let pipeline_desc = GraphicsPipelineDesc {
primitive_assembler,
rasterizer,
fragment: Some(fs_entry),
blender,
depth_stencil,
multisampling: None,
baked_states,
layout: &layout,
subpass: Subpass {
index: 0,
main_pass: render_pass_ref,
},
flags: PipelineCreationFlags::empty(),
parent: BasePipeline::None,
};
unsafe {
gpu.device()
.create_graphics_pipeline(&pipeline_desc, None)
.map_err(|_| "Could not create GraphicsPipeline")?
}};
trace!("Destroying no-longer-needed shader modules...");
unsafe {
gpu.device()
.destroy_shader_module(vertex_shader_module);
gpu.device()
.destroy_shader_module(fragment_shader_module);
};
let vertex_buffers = vec![
Attachement::new(gpu, (size_of::<f32>()*2*3) as u64)?,
Attachement::new(gpu, (size_of::<f32>()*3*3) as u64)?,
];
Ok( Pipeline {
set_layout,
layout: ManuallyDrop::new(layout),
gfx_pipeline: ManuallyDrop::new(gfx_pipeline),
vertex_buffers,
})
}
pub fn raw_pipeline(&self) -> &B::GraphicsPipeline {
&self.gfx_pipeline
}
pub fn raw_vertex_buffers(&self) -> Vec<(&B::Buffer, SubRange)> {
self.vertex_buffers
.iter()
//TODO move SubRange to Attachement ?
.map(|buffer| (buffer.get_buffer(), SubRange {offset: 0, size: None}))
.collect()
}
pub fn write_vertex_buffer(&mut self, gpu: &Gpu<B>, index: usize, data: Vec<f32>)
-> Result<(), &'static str>
{
self.vertex_buffers[index].write_buffer(gpu, data)
}
}

View File

@ -0,0 +1,136 @@
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use std::mem::ManuallyDrop;
use crate::renderer::gpu::Gpu;
//--Attachement implementation----------------------------------------------------------------------
#[derive(Debug)]
pub struct Attachement<B: gfx_hal::Backend> {
buffer: ManuallyDrop<B::Buffer>,
memory: ManuallyDrop<B::Memory>,
size: u64,
}
impl<B> Attachement<B>
where
B: gfx_hal::Backend,
{
pub fn drop(mut self, gpu: &mut Gpu<B>) {
use std::ptr::read;
use gfx_hal::device::Device;
debug!("Dropping Attachement...");
unsafe {
gpu.device()
.free_memory(ManuallyDrop::into_inner(read(&mut self.memory)));
gpu.device()
.destroy_buffer(ManuallyDrop::into_inner(read(&mut self.buffer)));
}
}
pub fn new(gpu: &mut Gpu<B>, size: u64) -> Result<Attachement<B>, &'static str> {
use gfx_hal::{
device::Device,
adapter::PhysicalDevice,
buffer::Usage,
};
debug!("Creating attachement...");
let mut buffer = unsafe {
gpu.device()
.create_buffer(size, Usage::VERTEX)
.map_err(|_| "Could not create buffer")?
};
trace!("Creating underlying attachement memory...");
let (memory, size) = {
use gfx_hal::{
memory::Properties,
MemoryTypeId,
};
let requirements = unsafe {
gpu.device().get_buffer_requirements(&buffer)
};
let memory_type = gpu.adapter()
.physical_device
.memory_properties()
.memory_types
.iter()
.enumerate()
.find(|&(id, memory_type)| {
requirements.type_mask & (1 << id) != 0 &&
memory_type.properties.contains(Properties::CPU_VISIBLE)})
.map(|(id, _)| MemoryTypeId(id))
.ok_or("Could not find a suitable memory type to allocate attachement memory")?;
(
unsafe {
gpu.device()
.allocate_memory(memory_type, requirements.size)
.map_err(|_| "Could not allocate buffer memory...")?
},
size,
)};
trace!("Binding memory to buffer...");
unsafe {
gpu.device()
.bind_buffer_memory(&memory, 0, &mut buffer)
.map_err(|__| "Could not bind memory to buffer")?;
}
Ok( Attachement {
buffer: ManuallyDrop::new(buffer),
memory: ManuallyDrop::new(memory),
size,
})
}
pub fn get_buffer(&self) -> &B::Buffer {
//manual deref for ManuallyDrop to not cause troubles
&self.buffer
}
pub fn write_buffer(&self, gpu: &Gpu<B>, data: Vec<f32>) -> Result<(), &'static str>
{
use gfx_hal::{
device::Device,
memory::Segment,
};
trace!("writing data to buffer...");
unsafe {
let mapped_memory = gpu.device()
.map_memory(&self.memory, Segment::ALL)
.map_err(|_| "Could not map buffer memory")?;
//debug!("data : {:?}", data);
//debug!("before : {:?}", std::slice::from_raw_parts(mapped_memory as *mut f32,
// (self.size/4) as usize));
std::ptr::copy_nonoverlapping(data.as_ptr() as *const u8,
mapped_memory, self.size as usize);
//debug!("after : {:?}", std::slice::from_raw_parts(mapped_memory as *mut f32,
// (self.size/4) as usize));
//manual deref for ManuallyDrop to not cause troubles
let memory_ref: &B::Memory = &self.memory;
gpu.device()
.flush_mapped_memory_ranges(std::iter::once((memory_ref, Segment::ALL)))
.map_err(|_| "Could not flush mapped buffer memory")?;
gpu.device().unmap_memory(&self.memory);
}
Ok(())
}
}

View File

@ -1,113 +0,0 @@
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use std::iter;
use gfx_hal::{
device::Device,
window::Swapchain,
command::CommandBuffer,
};
use crate::renderer::Renderer;
impl Renderer {
//----------------------------------------------------------------------------------------------
pub fn draw_clear_frame(&mut self, color: [f32; 4]) -> Result<(), &'static str> {
use gfx_hal::{
command::{SubpassContents, ClearValue, ClearColor, CommandBufferFlags},
queue::{Submission, CommandQueue},
pso::PipelineStage,
};
// get current frame fence
let fence = &self.fences[self.current_image];
//wait for current fence in case we are submiting too fast
unsafe {
self.device
.wait_for_fence(fence, !0)
.map_err(|_| "Failed to wait for fence")?;
self.device
.reset_fence(fence)
.map_err(|_| "Failed to reset fence")?;
}
// get current frame semaphores
let sem_image_available = &self.sems_image_available[self.current_image];
let sem_render_finished = &self.sems_render_finished[self.current_image];
// acquire image id in swapchain
let swp_image_id = unsafe {
match self.swapchain.acquire_image(core::u64::MAX, Some(sem_image_available), None) {
Ok((swp_image_id, suboptimal)) => match suboptimal {
Some(_) => {
return self.update_swapchain()
.map_err(|_| "Could not recreate swpachain");
},
None => swp_image_id,
}
Err(_) => {
return self.update_swapchain()
.map_err(|_| "Could not recreate swpachain");
},
}
};
// debug!("current image : {}", self.current_image);
// debug!("swapchain index : {}", swp_image_id);
unsafe {
let command_buffer = &mut self.command_buffers[self.current_image];
command_buffer.begin_primary(CommandBufferFlags::ONE_TIME_SUBMIT);
let clear_value = ClearValue {color: ClearColor{float32: color}};
command_buffer.begin_render_pass(
&self.render_pass,
&self.framebuffers[swp_image_id as usize],
self.render_area,
iter::once(clear_value),
SubpassContents::Inline,
);
command_buffer.end_render_pass();
command_buffer.finish();
}
let command_buffer = &self.command_buffers[self.current_image];
// prepare the submission
let submission = Submission {
command_buffers: iter::once(command_buffer),
wait_semaphores: iter::once((sem_image_available,
PipelineStage::COLOR_ATTACHMENT_OUTPUT)),
signal_semaphores: iter::once(sem_render_finished),
};
let mut queue = &mut self.queue_group.queues[0];
unsafe {
queue.submit(submission, Some(fence));
let result = self.swapchain.present(&mut queue, swp_image_id, Some(sem_render_finished))
.map_err(|_| "Failed to present into the swapchain")?;
if result.is_some() {
self.update_swapchain()
.map_err(|_| "Could not recreate swapchain")?;
}
}
self.current_image = (self.current_image + 1) % self.image_count;
// if self.current_image == 0 {
// panic!("Abort");
// }
Ok(())
}
}

View File

@ -0,0 +1,10 @@
#version 450
layout (location = 0) out vec4 frag_color;
layout (location = 1) in vec3 color;
void main()
{
frag_color = vec4(color, 1);
}

View File

@ -0,0 +1,16 @@
#version 450
layout (location = 0) in vec2 position;
layout (location = 1) in vec3 color;
layout (location = 0) out gl_PerVertex {
vec4 gl_Position;
};
layout (location = 1) out vec3 frag_color;
void main()
{
gl_Position = vec4(position, 0.0, 1.0);
frag_color = color;
}

342
src/renderer/swap_system.rs Normal file
View File

@ -0,0 +1,342 @@
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use std::{
mem::ManuallyDrop,
ptr::read,
collections::VecDeque,
};
use gfx_hal::{
window::{Extent2D, AcquireError, PresentationSurface, SurfaceCapabilities, SwapchainConfig},
pso::Rect as GfxRect,
format::Format,
};
mod frame;
use frame::Frame;
use super::gpu::Gpu;
//--SwapSystem implementation-----------------------------------------------------------------------
#[derive(Debug)]
pub struct SwapSystem<B: gfx_hal::Backend> {
surface: ManuallyDrop<B::Surface>,
format: Format,
extent: Extent2D,
pub render_area: GfxRect, //TODO may not be needed (duplicate of extent)
pub render_pass: ManuallyDrop<B::RenderPass>, //TODO move to Pipeline ?
frames: VecDeque<Frame<B>>,
frame_nb: usize,
}
impl<B> SwapSystem<B>
where
B: gfx_hal::Backend,
{
pub fn drop(&mut self, gpu: &mut Gpu<B>) -> B::Surface {
use gfx_hal::device::Device;
trace!("Dropping frames...");
for mut frame in self.frames.drain(..) {
frame.drop(gpu);
}
unsafe {
gpu.device().destroy_render_pass(
ManuallyDrop::into_inner(read(&mut self.render_pass)));
//render_area extent and format can be dropped automatically
self.surface.unconfigure_swapchain(gpu.device());
trace!("SwapSystem dropped !");
ManuallyDrop::take(&mut self.surface)
}
}
pub fn new(gpu: &mut Gpu<B>, mut surface: B::Surface)
-> Result<SwapSystem<B>, &'static str>
{
debug!("Creating SwapSystem...");
trace!("Obtaining surface capabilities...");
let capabilities = {
use gfx_hal::window::Surface;
surface.capabilities(&gpu.adapter().physical_device)
};
debug!("Surface capabitlities : {:#?}", capabilities);
trace!("Selecting image format...");
let format = {
use gfx_hal::{
format::ChannelType,
window::Surface,
};
match surface.supported_formats(&gpu.adapter().physical_device) {
None => Format::Rgba8Srgb,
Some(formats) => formats
.iter()
.find(|f| f.base_format().1 == ChannelType::Srgb)
.cloned()
.ok_or("Could no find suitable format")?
}};
trace!("Getting surface's render area size...");
let extent = capabilities.current_extent
.unwrap_or(*capabilities.extents.end())
.clone();
let render_area = GfxRect{x: 0, y: 0, w: extent.width as i16, h: extent.height as i16};
trace!("Generating Swapchain configuration...");
let (swapchain_config, frame_nb) =
generate_swapchain_config(capabilities, &format, &extent)?;
debug!("Swapchain configuration : {:#?}", swapchain_config);
trace!("Configuring Swapchain...");
let _ = unsafe {
surface
.configure_swapchain(gpu.device(), swapchain_config)
.map_err(|_| "Failed to create swapchain and backbuffer")?
};
trace!("Creating RenderPass...");
let render_pass = {
use gfx_hal::{
pass::{Attachment, AttachmentOps, AttachmentLoadOp, AttachmentStoreOp, SubpassDesc},
image::Layout,
device::Device,
};
let color_attachment = Attachment {
format : Some(format),
samples : 1,
ops : AttachmentOps {
load : AttachmentLoadOp::Clear,
store : AttachmentStoreOp::Store,
},
stencil_ops : AttachmentOps::DONT_CARE,
layouts : (Layout::Undefined..Layout::Present),
};
let subpass = SubpassDesc {
colors : &[(0, Layout::ColorAttachmentOptimal)],
depth_stencil : None,
inputs : &[],
resolves : &[],
preserves : &[],
};
unsafe {
gpu.device().create_render_pass(&[color_attachment], &[subpass], &[])
.map_err(|_| "Could not create render pass")?
}
};
warn!("Generating hard-coded number of frames ({}) !", frame_nb);
let mut frames = VecDeque::with_capacity(frame_nb);
for _ in 0..frame_nb {
let frame = Frame::new(gpu)
.map_err(|_| "Could not create frame")?;
frames.push_back(frame);
};
let frame_nb = frames.len();
trace!("Created SwapSystem !");
Ok( SwapSystem {
surface: ManuallyDrop::new(surface),
format,
extent,
render_area,
render_pass: ManuallyDrop::new(render_pass),
frames,
frame_nb,
})
}
pub fn recreate(&mut self, gpu: &mut Gpu<B>) -> Result<(), &'static str> {
trace!("Obtaining surface capabilities...");
let capabilities = {
use gfx_hal::window::Surface;
self.surface.capabilities(&gpu.adapter().physical_device)
};
debug!("Surface capabitlities : {:#?}", capabilities);
trace!("Getting surface's render area size...");
self.extent = capabilities.current_extent
.unwrap_or(*capabilities.extents.end())
.clone();
self.render_area =
GfxRect{x: 0, y: 0, w: self.extent.width as i16, h: self.extent.height as i16};
trace!("Generating Swapchain configuration...");
let (swapchain_config, _frame_nb) = //TODO check frame nb change
generate_swapchain_config(capabilities, &self.format, &self.extent)?;
debug!("Swapchain configuration : {:#?}", swapchain_config);
trace!("Configuring Swapchain...");
let _ = unsafe {
self.surface
.configure_swapchain(gpu.device(), swapchain_config)
.map_err(|_| "Failed to create swapchain and backbuffer")?
};
Ok(())
}
pub fn acquire_frame(&mut self, gpu: &Gpu<B>) -> Result<Frame<B>, AcquireError> {
//println!("Frame nb : {}", self.frames.len());
//TODO frames number diminish sometimes at resize...
//static mut id: i32 = 0;
let mut frame = self.frames.pop_back().unwrap();
//unsafe {
// id = (id+1)%3;
//}
trace!("Waiting for Frame...");
unsafe {
use gfx_hal::device::Device;
let _ = gpu.device()
.wait_for_fence(&frame.fences[0], !0)
.map_err(|_| "Failed to wait for Fence"); //TODO error
let _ = gpu.device()
.reset_fence(&frame.fences[0])
.map_err(|_| "Failed to reset Fence"); //TODO error
}
trace!("Reseting CommandBuffer...");
unsafe {
use gfx_hal::command::CommandBuffer;
frame.command_buffer.reset(false); //TODO may be needed at some point...
};
//unsafe {
// trace!("Acquiring Frame {}...", id);
//}
trace!("Acquiring Frame...");
let image = unsafe {
match self.surface.acquire_image(core::u64::MAX) {
Ok((image, suboptimal)) => {
match suboptimal {
Some(_) => return Err(AcquireError::OutOfDate),
None => image,
}},
Err(err) => return Err(err),
}};
trace!("Creating Framebuffer...");
let framebuffer = unsafe {
use gfx_hal::device::Device;
use std::borrow::Borrow;
gpu.device()
.create_framebuffer(&self.render_pass,
vec![image.borrow()],
self.extent.clone().to_extent())
.unwrap() //TODO improve that
};
//unsafe {
// use gfx_hal::{device::Device};
// gpu.device()
// .set_framebuffer_name(&mut framebuffer, format!("frambuffer {}", id).as_str());
//}
frame.link_swapchain_image(gpu, image, framebuffer);
Ok(frame)
}
pub fn present_frame(&mut self, mut frame: Frame<B>, gpu: &mut Gpu<B>)
-> Result<(), &'static str> {
use gfx_hal::queue::CommandQueue;
let image = frame
.unlink_swapchain_image()
.unwrap(); //TODO improve that
trace!("Presenting Frame...");
let _ = unsafe {
gpu.queue_mut()
.present(&mut self.surface, image, Some(&frame.signal_semaphores[0]))
.map_err(|_| "Failed to present into the swapchain")?;
};
frame.destroy_framebuffer(gpu);
self.frames.push_front(frame);
Ok(())
}
}
fn generate_swapchain_config(capabilities: SurfaceCapabilities,
format: &Format,
extent: &Extent2D)
-> Result<(SwapchainConfig, usize), &'static str> {
trace!("Generating Swapchain configuration...");
let present_mode = {
use gfx_hal::window::PresentMode;
[PresentMode::MAILBOX, PresentMode::FIFO, PresentMode::RELAXED,
PresentMode::IMMEDIATE]
.iter()
.cloned()
.find(|pm| capabilities.present_modes.contains(*pm))
.ok_or("No PresentMode values specified!")?
};
let composite_alpha_mode = {
use gfx_hal::window::CompositeAlphaMode;
[CompositeAlphaMode::OPAQUE, CompositeAlphaMode::INHERIT,
CompositeAlphaMode::PREMULTIPLIED, CompositeAlphaMode::POSTMULTIPLIED]
.iter()
.cloned()
.find(|ca| capabilities.composite_alpha_modes.contains(*ca))
.ok_or("No CompositeAlpha values specified!")?
};
let image_count = {
use std::cmp::{min, max};
use gfx_hal::window::PresentMode;
let count = match present_mode {
PresentMode::MAILBOX => 3,
_ => 2, //TODO to be checked
};
max(capabilities.image_count.start().clone(),
min(capabilities.image_count.end().clone(), count))
};
warn!("Hard-coding number of layers per image !");
let image_layers = 1;
let image_usage = {
use gfx_hal::image::Usage;
if capabilities.usage.contains(Usage::COLOR_ATTACHMENT) {
Usage::COLOR_ATTACHMENT
} else {
Err("The Surface isn't capable of supporting color!")?
}};
Ok ((
SwapchainConfig {
present_mode,
composite_alpha_mode,
format: format.clone(),
extent: extent.clone(),
image_count: image_count.clone(),
image_layers,
image_usage,
},
image_count as usize
))
}

View File

@ -0,0 +1,132 @@
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use std::{
mem::ManuallyDrop,
ptr::read,
iter,
};
use gfx_hal::window::{PresentationSurface};
use super::super::gpu::Gpu;
//--Frame implementation----------------------------------------------------------------------------
#[derive(Debug)]
pub struct Frame<B: gfx_hal::Backend> {
pub wait_semaphores: Vec<B::Semaphore>,
pub signal_semaphores: Vec<B::Semaphore>,
pub fences: Vec<B::Fence>,
pub command_buffer: ManuallyDrop<B::CommandBuffer>,
image_view: Option<<B::Surface as PresentationSurface<B>>::SwapchainImage>,
pub framebuffer: Option<B::Framebuffer>,
}
impl<B> Frame<B>
where
B: gfx_hal::Backend,
{
pub fn drop(&mut self, gpu: &mut Gpu<B>) {
use gfx_hal::{
device::Device,
pool::CommandPool,
};
unsafe {
if self.image_view.is_some() {
warn!("Dropping non-presented frame !");
}
gpu.command_pool_mut().free(
iter::once(ManuallyDrop::into_inner(read(&mut self.command_buffer))));
for fence in self.fences.drain(..) {
gpu.device().destroy_fence(fence);
}
for semaphore in self.signal_semaphores.drain(..) {
gpu.device().destroy_semaphore(semaphore);
}
for semaphore in self.wait_semaphores.drain(..) {
gpu.device().destroy_semaphore(semaphore);
}
trace!("Frame Dropped !");
}
}
pub fn new(gpu: &mut Gpu<B>) -> Result<Frame<B>, &'static str>
{
debug!("Creating Frame...");
trace!("Creating Semaphore and Fences...");
let (wait_semaphores, signal_semaphores, fences) = {
use gfx_hal::device::Device;
let wait_semaphores = vec!(
gpu.device()
.create_semaphore()
.map_err(|_| "Could not create Semaphore")?);
let signal_semaphores = vec!(
gpu.device()
.create_semaphore()
.map_err(|_| "Could not create Semaphore")?);
let fences = vec!(
gpu.device()
.create_fence(true)
.map_err(|_| "Could not create Fence")?);
(wait_semaphores, signal_semaphores, fences)
};
trace!("Allocating CommandBuffer...");
let command_buffer = unsafe {
use gfx_hal::{
command::Level,
pool::CommandPool,
};
gpu.command_pool_mut().allocate_one(Level::Primary)
};
trace!("Created Frame !");
Ok( Frame {
wait_semaphores,
signal_semaphores,
fences,
command_buffer: ManuallyDrop::new(command_buffer),
image_view: None,
framebuffer: None,
})
}
pub fn link_swapchain_image(&mut self,
_gpu: &Gpu<B>, //TODO clear that when framebuffer issue is fixed
image: <B::Surface as PresentationSurface<B>>::SwapchainImage,
framebuffer: B::Framebuffer) {
self.framebuffer = Some(framebuffer);
//match self.framebuffer.replace(framebuffer) {
// Some(old_framebuffer) => {
// trace!("Destroying Framebuffer...");
// unsafe { gpu.device().destroy_framebuffer(old_framebuffer) };
// },
// None => (),
//}
self.image_view = Some(image);
}
pub fn unlink_swapchain_image(&mut self)
-> Result<<B::Surface as PresentationSurface<B>>::SwapchainImage, &'static str> {
self.image_view
.take()
.ok_or("Can not unlink non-linked Frame !")
}
pub fn destroy_framebuffer(&mut self, gpu: &Gpu<B>) {
unsafe {
use gfx_hal::device::Device;
gpu.device().destroy_framebuffer(self.framebuffer.take().unwrap());
}
}
}

22
src/subengine.rs Normal file
View File

@ -0,0 +1,22 @@
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
pub mod subengine_controller;
pub use self::subengine_controller::SubengineController;
pub mod subengine_pipeline;
pub use self::subengine_pipeline::SubenginePipeline;
pub mod test_subengine;
pub use self::test_subengine::TestSubengine;
//--SubEngine trait------------------------------------------------------------------------------------
/// A trait that should be implemented by all subengines running it the game engine.
///
/// Allow the [`Controller`] to run custom subengines.
pub trait Subengine {
/// Main function of the subengine. Called byt the [`Controller`] for each frame.
fn run(&self);
}

View File

@ -0,0 +1,140 @@
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use std::{
sync::mpsc::{Sender, Receiver},
thread::JoinHandle,
mem::ManuallyDrop,
ptr::read,
time::Duration,
};
use crate::subengine::Subengine;
//--SubengineController Implementation--------------------------------------------------------------
/// Handle to manage an [`Subengine`].
///
/// The `SubengineController` runs the [`Engine`] in a separated thread with some control code to
/// allow control from the main thread. SubengineControllers are used by the [`Controller`] to
/// interact with Subengines.
#[derive(Debug)]
pub struct SubengineController {
tx: Sender<SubengineCommand>,
rx: Receiver<SubengineResponse>,
handle: ManuallyDrop<JoinHandle<()>>,
}
impl Drop for SubengineController {
fn drop(&mut self) {
self.exec(SubengineCommand::Stop);
unsafe { let _ = ManuallyDrop::into_inner(read(&mut self.handle)).join(); }
debug!("SubengineController dropped !");
}
}
impl SubengineController {
/// Creates a new `SubengineController` from a given [`Engine`]. Since the latter will be moved
/// to a separated thread, it must implement the [`Send`] trait.
pub fn new<E: 'static>(engine: E) -> SubengineController
where
E: Subengine + std::marker::Send,
{
use std::{
thread,
sync::mpsc::channel,
};
debug!("Creating SubengineController...");
let (tx, e_rx) = channel();
let (e_tx, rx) = channel();
let handle = thread::spawn(move || {
trace!("Subengine thread started !");
loop {
//TODO manage errors
match e_rx.recv().unwrap() {
SubengineCommand::Run => engine.run(),
SubengineCommand::Stop => return,
};
e_tx.send(SubengineResponse::Done).unwrap();
}
});
SubengineController {
tx,
rx,
handle: ManuallyDrop::new(handle),
}
}
/// Sends a command to the [`Subengine`]. This is function is not blocking and WILL NOT check if
/// the command was received.
pub fn exec(&self, cmd: SubengineCommand) {
self.tx.send(cmd).unwrap();
}
/// Blocking function, waits for the [`Subengine`] to finish executing the last command given.
pub fn wait_for_exec(&self, timeout: Duration) -> Result<(),SubengineWaitError> {
match self.rx.recv_timeout(timeout) {
Err(_) => Err(SubengineWaitError::NoResponse),
Ok(val) => match val {
SubengineResponse::Done => Ok(()),
//_ => Err(SubengineWaitError::BadResponse),
}}
}
}
//--SubengineCommand enum---------------------------------------------------------------------------
/// Commands that can be sent to an [`Subengine`] via an `EngineController`.
#[derive(Debug)]
pub enum SubengineCommand {
Run,
Stop,
}
//--SubengineWaitError enum-------------------------------------------------------------------------
/// Errors that can be returned by the wait_for_exec function.
#[derive(Debug)]
pub enum SubengineWaitError {
NoResponse,
BadResponse,
}
//--SubengineResponse enum--------------------------------------------------------------------------
#[derive(Debug)]
enum SubengineResponse {
Done,
}
//--Tests-------------------------------------------------------------------------------------------
#[cfg(test)]
mod tests {
use super::*;
use crate::subengine::TestSubengine;
#[test]
fn test_new_drop() {
let (test_subengine, _test_rx) = TestSubengine::new("run");
let _subengine_controller = SubengineController::new(test_subengine);
}
#[test]
fn test_exec() {
let (test_subengine, test_rx) = TestSubengine::new("run");
let subengine_controller = SubengineController::new(test_subengine);
subengine_controller.exec(SubengineCommand::Run);
let response = test_rx.recv_timeout(Duration::from_millis(10)).unwrap();
assert_eq!(response, "run");
}
#[test]
fn test_wait_for_exec() {
let (test_subengine, _test_rx) = TestSubengine::new("run");
let subengine_controller = SubengineController::new(test_subengine);
subengine_controller.exec(SubengineCommand::Run);
subengine_controller.wait_for_exec(Duration::from_millis(10)).unwrap();
}
}

View File

@ -0,0 +1,72 @@
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use std::{
cell::RefCell,
marker::PhantomData,
};
use gfx_backend_vulkan as vk_back;
use crate::{
io::{Input, Output},
subengine::SubengineController,
renderer::Renderer,
};
//--SubenginePipeline Implementation----------------------------------------------------------------
#[derive(Debug)]
pub struct SubenginePipeline<'a, I, W, O>
where
I: Input,
W: raw_window_handle::HasRawWindowHandle,
O: Output<W>,
{
pub inputs: Vec<&'a RefCell<I>>,
pub subengines: Vec<Vec<SubengineController>>,
pub renderers: Vec<(Renderer<vk_back::Backend>, &'a RefCell<O>)>,
phantom: PhantomData<W>, //needed because of compiler limitations
}
impl<'a, I, W, O> SubenginePipeline<'a, I, W, O>
where
I: Input,
W: raw_window_handle::HasRawWindowHandle,
O: Output<W>,
{
pub fn new<Ii, Is, Iss, Ir>(inputs: Ii, subengines: Is, renderers: Ir)
-> SubenginePipeline<'a, I, W, O>
where
Ii: IntoIterator<Item = &'a RefCell<I>>,
Iss: IntoIterator<Item = SubengineController>,
Is: IntoIterator<Item = Iss>,
Ir: IntoIterator<Item = (Renderer<vk_back::Backend>, &'a RefCell<O>)>,
{
let inputs_vec = inputs
.into_iter()
.map(|input| input)
.collect();
let subengines_vecs = subengines
.into_iter()
.map(|subengines_vec| subengines_vec
.into_iter()
.map(|subengine| subengine)
.collect())
.collect();
let renderers_vec = renderers
.into_iter()
.map(|renderer| renderer)
.collect();
SubenginePipeline{
inputs: inputs_vec,
subengines: subengines_vecs,
renderers: renderers_vec,
phantom: PhantomData,
}
}
}

View File

@ -0,0 +1,36 @@
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use std::sync::mpsc::{Sender, Receiver, channel};
use super::*;
//--TestSubengine Implementation--------------------------------------------------------------------
/// [`Subengine`] implementation used for tests.
///
/// Simply sends back the given [`str`] depending on the command.
#[derive(Debug)]
pub struct TestSubengine {
tx: Sender<&'static str>,
run: &'static str,
}
impl TestSubengine {
/// Creates a `TestSubengine` with specific [`str`]s to use.
pub fn new(run: &'static str)
-> (TestSubengine, Receiver<&'static str>) {
let (tx, rx) = channel();
(
TestSubengine { tx, run },
rx
)
}
}
impl Subengine for TestSubengine {
fn run(&self) {
self.tx.send(self.run).unwrap();
}
}

24
src/utils.rs Normal file
View File

@ -0,0 +1,24 @@
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use num_traits::Num;
#[derive(Debug, Copy, Clone)]
pub struct Rect<I: Num> {
pub w: I,
pub h: I,
}
#[derive(Debug, Copy, Clone)]
pub struct Triangle {
pub points: [[f32; 2]; 3],
}
impl Triangle {
pub fn points_flat(&self) -> [f32; 6] {
let [[a, b], [c, d], [e, f]] = self.points;
[a, b, c, d, e, f]
}
}

View File

@ -1,49 +0,0 @@
#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use winit::{
dpi::PhysicalSize,
event_loop::{EventLoop},
window::{WindowBuilder, Window},
error::OsError,
};
#[derive(Debug)]
pub struct WinitState {
pub event_loop: EventLoop<()>,
pub window: Window,
}
impl WinitState {
pub fn new (title: &str, size: PhysicalSize<u32>) -> Result<WinitState, OsError> {
let event_loop = EventLoop::new();
let window = WindowBuilder::new()
.with_inner_size(size)
.with_title(title)
.build(&event_loop)
.unwrap();
Ok(Self {
event_loop,
window,
})
}
}
impl Default for WinitState {
fn default() -> WinitState {
WinitState::new(
"IV",
PhysicalSize {
width : 1280,
height : 720
}
).unwrap()
}
}