diff --git a/Cargo.lock b/Cargo.lock index af141b5..a3e7735 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,6 +6,35 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2" +[[package]] +name = "andrew" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7f09f89872c2b6b29e319377b1fbe91c6f5947df19a25596e121cf19a7b35e" +dependencies = [ + "bitflags", + "line_drawing", + "rusttype 0.7.9", + "walkdir", + "xdg", + "xml-rs", +] + +[[package]] +name = "android_glue" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407" + +[[package]] +name = "approx" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3" +dependencies = [ + "num-traits", +] + [[package]] name = "arrayvec" version = "0.5.1" @@ -21,18 +50,50 @@ dependencies = [ "libloading", ] +[[package]] +name = "ash-window" +version = "0.3.0" +source = "git+https://github.com/norse-rs/ash-window.git?branch=dyn_trait#ff8cd779b339067f00e808add1203f6c0d074ba5" +dependencies = [ + "ash", + "raw-window-handle", +] + +[[package]] +name = "autocfg" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" + [[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + [[package]] name = "byteorder" version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +[[package]] +name = "calloop" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aa2097be53a00de9e8fc349fea6d76221f398f5c4fa550d420669906962d160" +dependencies = [ + "mio", + "mio-extras", + "nix", +] + [[package]] name = "cc" version = "1.0.50" @@ -45,6 +106,71 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags", +] + +[[package]] +name = "cocoa" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29f7768b2d1be17b96158e3285951d366b40211320fb30826a76cb7a0da6400" +dependencies = [ + "bitflags", + "block", + "core-foundation", + "core-graphics", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "core-foundation" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" + +[[package]] +name = "core-graphics" +version = "0.17.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56790968ab1c8a1202a102e6de05fc6e1ec87da99e4e93e9a7d13efbfc1e95a9" +dependencies = [ + "bitflags", + "core-foundation", + "foreign-types", + "libc", +] + +[[package]] +name = "core-video-sys" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dc065219542086f72d1e9f7aadbbab0989e980263695d129d502082d063a9d0" +dependencies = [ + "cfg-if", + "core-foundation-sys", + "core-graphics", + "libc", + "objc", +] + [[package]] name = "crc32fast" version = "1.2.0" @@ -64,6 +190,58 @@ dependencies = [ "byteorder", ] +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "dlib" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77e51249a9d823a4cb79e3eca6dcd756153e8ed0157b6c04775d04bf1b13b76a" +dependencies = [ + "libloading", +] + +[[package]] +name = "downcast-rs" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ba6eb47c2131e784a38b726eb54c1e1484904f013e576a25354d0124161af6" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "fuchsia-zircon" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +dependencies = [ + "bitflags", + "fuchsia-zircon-sys", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" + [[package]] name = "getrandom" version = "0.1.14" @@ -90,6 +268,31 @@ dependencies = [ "adler32", ] +[[package]] +name = "instant" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7152d2aed88aa566e7a342250f21ba2222c1ae230ad577499dbfa3c18475b80" + +[[package]] +name = "iovec" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" +dependencies = [ + "libc", +] + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + [[package]] name = "kurbo" version = "0.5.11" @@ -98,6 +301,18 @@ dependencies = [ "arrayvec", ] +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lazycell" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" + [[package]] name = "libc" version = "0.2.69" @@ -111,7 +326,144 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753" dependencies = [ "cc", - "winapi", + "winapi 0.3.8", +] + +[[package]] +name = "line_drawing" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc7ad3d82c845bdb5dde34ffdcc7a5fb4d2996e1e1ee0f19c33bc80e15196b9" +dependencies = [ + "num-traits", +] + +[[package]] +name = "lock_api" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "maybe-uninit" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" + +[[package]] +name = "memmap" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" +dependencies = [ + "libc", + "winapi 0.3.8", +] + +[[package]] +name = "mio" +version = "0.6.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430" +dependencies = [ + "cfg-if", + "fuchsia-zircon", + "fuchsia-zircon-sys", + "iovec", + "kernel32-sys", + "libc", + "log", + "miow", + "net2", + "slab", + "winapi 0.2.8", +] + +[[package]] +name = "mio-extras" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19" +dependencies = [ + "lazycell", + "log", + "mio", + "slab", +] + +[[package]] +name = "miow" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" +dependencies = [ + "kernel32-sys", + "net2", + "winapi 0.2.8", + "ws2_32-sys", +] + +[[package]] +name = "net2" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ba7c918ac76704fb42afcbbb43891e72731f3dcca3bef2a19786297baf14af7" +dependencies = [ + "cfg-if", + "libc", + "winapi 0.3.8", +] + +[[package]] +name = "nix" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce" +dependencies = [ + "bitflags", + "cc", + "cfg-if", + "libc", + "void", +] + +[[package]] +name = "num-traits" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" +dependencies = [ + "autocfg", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", ] [[package]] @@ -120,6 +472,45 @@ version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1c601810575c99596d4afc46f78a678c80105117c379eb3650cf99b8a21ce5b" +[[package]] +name = "ordered-float" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518" +dependencies = [ + "num-traits", +] + +[[package]] +name = "parking_lot" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3" +dependencies = [ + "cfg-if", + "cloudabi", + "libc", + "redox_syscall", + "smallvec", + "winapi 0.3.8", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + [[package]] name = "piet" version = "0.0.12" @@ -140,14 +531,15 @@ dependencies = [ "png", "rand", "roxmltree", + "winit", ] [[package]] name = "piet-gpu-derive" version = "0.0.0" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.10", + "quote 1.0.3", "syn", ] @@ -156,7 +548,9 @@ name = "piet-gpu-hal" version = "0.1.0" dependencies = [ "ash", + "ash-window", "once_cell", + "raw-window-handle", ] [[package]] @@ -167,6 +561,12 @@ dependencies = [ "piet-gpu-derive", ] +[[package]] +name = "pkg-config" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" + [[package]] name = "png" version = "0.16.2" @@ -185,13 +585,31 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +dependencies = [ + "unicode-xid 0.1.0", +] + [[package]] name = "proc-macro2" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3" dependencies = [ - "unicode-xid", + "unicode-xid 0.2.0", +] + +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +dependencies = [ + "proc-macro2 0.4.30", ] [[package]] @@ -200,7 +618,7 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" dependencies = [ - "proc-macro2", + "proc-macro2 1.0.10", ] [[package]] @@ -244,6 +662,21 @@ dependencies = [ "rand_core", ] +[[package]] +name = "raw-window-handle" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a441a7a6c80ad6473bd4b74ec1c9a4c951794285bf941c2126f607c72e48211" +dependencies = [ + "libc", +] + +[[package]] +name = "redox_syscall" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" + [[package]] name = "roxmltree" version = "0.11.0" @@ -253,29 +686,190 @@ dependencies = [ "xmlparser", ] +[[package]] +name = "rusttype" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "310942406a39981bed7e12b09182a221a29e0990f3e7e0c971f131922ed135d5" +dependencies = [ + "rusttype 0.8.3", +] + +[[package]] +name = "rusttype" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f61411055101f7b60ecf1041d87fb74205fb20b0c7a723f07ef39174cf6b4c0" +dependencies = [ + "approx", + "ordered-float", + "stb_truetype", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "slab" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" + +[[package]] +name = "smallvec" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4" + +[[package]] +name = "smithay-client-toolkit" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "421c8dc7acf5cb205b88160f8b4cc2c5cfabe210e43b2f80f009f4c1ef910f1d" +dependencies = [ + "andrew", + "bitflags", + "dlib", + "lazy_static", + "memmap", + "nix", + "wayland-client", + "wayland-protocols", +] + +[[package]] +name = "stb_truetype" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f77b6b07e862c66a9f3e62a07588fee67cd90a9135a2b942409f195507b4fb51" +dependencies = [ + "byteorder", +] + [[package]] name = "syn" version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03" dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", + "proc-macro2 1.0.10", + "quote 1.0.3", + "unicode-xid 0.2.0", ] +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" + [[package]] name = "unicode-xid" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "walkdir" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" +dependencies = [ + "same-file", + "winapi 0.3.8", + "winapi-util", +] + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +[[package]] +name = "wayland-client" +version = "0.23.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1080ebe0efabcf12aef2132152f616038f2d7dcbbccf7b2d8c5270fe14bcda" +dependencies = [ + "bitflags", + "calloop", + "downcast-rs", + "libc", + "mio", + "nix", + "wayland-commons", + "wayland-scanner", + "wayland-sys", +] + +[[package]] +name = "wayland-commons" +version = "0.23.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb66b0d1a27c39bbce712b6372131c6e25149f03ffb0cd017cf8f7de8d66dbdb" +dependencies = [ + "nix", + "wayland-sys", +] + +[[package]] +name = "wayland-protocols" +version = "0.23.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cc286643656742777d55dc8e70d144fa4699e426ca8e9d4ef454f4bf15ffcf9" +dependencies = [ + "bitflags", + "wayland-client", + "wayland-commons", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.23.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93b02247366f395b9258054f964fe293ddd019c3237afba9be2ccbe9e1651c3d" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "xml-rs", +] + +[[package]] +name = "wayland-sys" +version = "0.23.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d94e89a86e6d6d7c7c9b19ebf48a03afaac4af6bc22ae570e9a24124b75358f4" +dependencies = [ + "dlib", + "lazy_static", +] + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" + [[package]] name = "winapi" version = "0.3.8" @@ -286,18 +880,96 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu", ] +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" + [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi 0.3.8", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "winit" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc53342d3d1a3d57f3949e0692d93d5a8adb7814d8683cef4a09c2b550e94246" +dependencies = [ + "android_glue", + "bitflags", + "cocoa", + "core-foundation", + "core-graphics", + "core-video-sys", + "dispatch", + "instant", + "lazy_static", + "libc", + "log", + "mio", + "mio-extras", + "objc", + "parking_lot", + "percent-encoding", + "raw-window-handle", + "smithay-client-toolkit", + "wayland-client", + "winapi 0.3.8", + "x11-dl", +] + +[[package]] +name = "ws2_32-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + +[[package]] +name = "x11-dl" +version = "2.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf981e3a5b3301209754218f962052d4d9ee97e478f4d26d4a6eced34c1fef8" +dependencies = [ + "lazy_static", + "libc", + "maybe-uninit", + "pkg-config", +] + +[[package]] +name = "xdg" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57" + +[[package]] +name = "xml-rs" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a" + [[package]] name = "xmlparser" version = "0.13.1" diff --git a/piet-gpu-hal/Cargo.toml b/piet-gpu-hal/Cargo.toml index 7019002..d2edbd7 100644 --- a/piet-gpu-hal/Cargo.toml +++ b/piet-gpu-hal/Cargo.toml @@ -9,3 +9,5 @@ edition = "2018" [dependencies] ash = "0.30" once_cell = "1.3.1" +ash-window = { git = "https://github.com/norse-rs/ash-window.git", branch = "dyn_trait" } +raw-window-handle = "0.3" diff --git a/piet-gpu-hal/examples/collatz.rs b/piet-gpu-hal/examples/collatz.rs index a4777b4..fed6a1d 100644 --- a/piet-gpu-hal/examples/collatz.rs +++ b/piet-gpu-hal/examples/collatz.rs @@ -2,9 +2,9 @@ use piet_gpu_hal::vulkan::VkInstance; use piet_gpu_hal::{CmdBuf, Device, MemFlags}; fn main() { - let instance = VkInstance::new().unwrap(); + let (instance, _) = VkInstance::new(None).unwrap(); unsafe { - let device = instance.device().unwrap(); + let device = instance.device(None).unwrap(); let mem_flags = MemFlags::host_coherent(); let src = (0..256).map(|x| x + 1).collect::>(); let buffer = device diff --git a/piet-gpu-hal/src/lib.rs b/piet-gpu-hal/src/lib.rs index d215490..67fe18e 100644 --- a/piet-gpu-hal/src/lib.rs +++ b/piet-gpu-hal/src/lib.rs @@ -5,28 +5,49 @@ pub mod vulkan; /// This isn't great but is expedient. -type Error = Box; +pub type Error = Box; + +#[derive(Copy, Clone, Debug)] +pub enum ImageLayout { + Undefined, + Present, + BlitSrc, + BlitDst, + General, +} pub trait Device: Sized { type Buffer; + type Image; type MemFlags: MemFlags; type Pipeline; type DescriptorSet; type QueryPool; type CmdBuf: CmdBuf; + type Fence; + type Semaphore; fn create_buffer(&self, size: u64, mem_flags: Self::MemFlags) -> Result; + unsafe fn create_image2d( + &self, + width: u32, + height: u32, + mem_flags: Self::MemFlags, + ) -> Result; + unsafe fn create_simple_compute_pipeline( &self, code: &[u8], n_buffers: u32, + n_images: u32, ) -> Result; unsafe fn create_descriptor_set( &self, pipeline: &Self::Pipeline, bufs: &[&Self::Buffer], + images: &[&Self::Image], ) -> Result; fn create_cmd_buf(&self) -> Result; @@ -40,9 +61,15 @@ pub trait Device: Sized { /// /// # Safety /// All submitted commands that refer to this query pool must have completed. - unsafe fn reap_query_pool(&self, pool: Self::QueryPool) -> Result, Error>; + unsafe fn reap_query_pool(&self, pool: &Self::QueryPool) -> Result, Error>; - unsafe fn run_cmd_buf(&self, cmd_buf: &Self::CmdBuf) -> Result<(), Error>; + unsafe fn run_cmd_buf( + &self, + cmd_buf: &Self::CmdBuf, + wait_semaphores: &[Self::Semaphore], + signal_semaphores: &[Self::Semaphore], + fence: Option<&Self::Fence>, + ) -> Result<(), Error>; unsafe fn read_buffer( &self, @@ -55,6 +82,10 @@ pub trait Device: Sized { buffer: &Self::Buffer, contents: &[T], ) -> Result<(), Error>; + + unsafe fn create_semaphore(&self) -> Result; + unsafe fn create_fence(&self, signaled: bool) -> Result; + unsafe fn wait_and_reset(&self, fences: &[Self::Fence]) -> Result<(), Error>; } pub trait CmdBuf { @@ -71,6 +102,13 @@ pub trait CmdBuf { unsafe fn memory_barrier(&mut self); + unsafe fn image_barrier( + &mut self, + image: &D::Image, + src_layout: ImageLayout, + dst_layout: ImageLayout, + ); + /// Clear the buffer. /// /// This is readily supported in Vulkan, but for portability it is remarkably @@ -80,6 +118,11 @@ pub trait CmdBuf { unsafe fn copy_buffer(&self, src: &D::Buffer, dst: &D::Buffer); + unsafe fn copy_image_to_buffer(&self, src: &D::Image, dst: &D::Buffer); + + // low portability, dx12 doesn't support it natively + unsafe fn blit_image(&self, src: &D::Image, dst: &D::Image); + /// Reset the query pool. /// /// The query pool must be reset before each use, to avoid validation errors. diff --git a/piet-gpu-hal/src/vulkan.rs b/piet-gpu-hal/src/vulkan.rs index 2a5abd9..ff4587e 100644 --- a/piet-gpu-hal/src/vulkan.rs +++ b/piet-gpu-hal/src/vulkan.rs @@ -4,12 +4,12 @@ use std::borrow::Cow; use std::ffi::{CStr, CString}; use std::sync::Arc; -use ash::extensions::ext::DebugUtils; +use ash::extensions::{ext::DebugUtils, khr}; use ash::version::{DeviceV1_0, EntryV1_0, InstanceV1_0}; use ash::{vk, Device, Entry, Instance}; use once_cell::sync::Lazy; -use crate::Error; +use crate::{Device as DeviceTrait, Error, ImageLayout}; pub struct VkInstance { /// Retain the dynamic lib. @@ -22,6 +22,7 @@ pub struct VkInstance { pub struct VkDevice { device: Arc, + physical_device: vk::PhysicalDevice, device_mem_props: vk::PhysicalDeviceMemoryProperties, queue: vk::Queue, qfi: u32, @@ -32,6 +33,23 @@ struct RawDevice { device: Device, } +pub struct VkSurface { + surface: vk::SurfaceKHR, + surface_fn: khr::Surface, +} + +pub struct VkSwapchain { + swapchain: vk::SwapchainKHR, + swapchain_fn: khr::Swapchain, + + present_queue: vk::Queue, + + acquisition_idx: usize, + acquisition_semaphores: Vec, // same length as `images` + images: Vec, + extent: vk::Extent2D, +} + /// A handle to a buffer. /// /// There is no lifetime tracking at this level; the caller is responsible @@ -42,6 +60,13 @@ pub struct Buffer { size: u64, } +pub struct Image { + image: vk::Image, + image_memory: vk::DeviceMemory, + image_view: vk::ImageView, + extent: vk::Extent3D, +} + pub struct Pipeline { pipeline: vk::Pipeline, descriptor_set_layout: vk::DescriptorSetLayout, @@ -88,11 +113,7 @@ unsafe extern "system" fn vulkan_debug_callback( println!( "{:?}:\n{:?} [{} ({})] : {}\n", - message_severity, - message_type, - message_id_name, - message_id_number, - message, + message_severity, message_type, message_id_name, message_id_number, message, ); vk::FALSE @@ -119,40 +140,59 @@ impl VkInstance { /// /// There's more to be done to make this suitable for integration with other /// systems, but for now the goal is to make things simple. - pub fn new() -> Result { + /// + /// The caller is responsible for making sure that window which owns the raw window handle + /// outlives the surface. + pub fn new( + window_handle: Option<&dyn raw_window_handle::HasRawWindowHandle>, + ) -> Result<(VkInstance, Option), Error> { unsafe { let app_name = CString::new("VkToy").unwrap(); let entry = Entry::new()?; - let exist_layers = entry - .enumerate_instance_layer_properties()?; - let layers = LAYERS.iter().filter_map(|&lyr| { - exist_layers - .iter() - .find(|x| - CStr::from_ptr(x.layer_name.as_ptr()) == lyr - ) - .map(|_| lyr.as_ptr()) - .or_else(|| { - println!("Unable to find layer: {}, have you installed the Vulkan SDK?", lyr.to_string_lossy()); - None - }) - }).collect::>(); + let exist_layers = entry.enumerate_instance_layer_properties()?; + let layers = LAYERS + .iter() + .filter_map(|&lyr| { + exist_layers + .iter() + .find(|x| CStr::from_ptr(x.layer_name.as_ptr()) == lyr) + .map(|_| lyr.as_ptr()) + .or_else(|| { + println!( + "Unable to find layer: {}, have you installed the Vulkan SDK?", + lyr.to_string_lossy() + ); + None + }) + }) + .collect::>(); - let exist_exts = entry - .enumerate_instance_extension_properties()?; - let exts = EXTS.iter().filter_map(|&ext| { - exist_exts - .iter() - .find(|x| - CStr::from_ptr(x.extension_name.as_ptr()) == ext - ) - .map(|_| ext.as_ptr()) - .or_else(|| { - println!("Unable to find extension: {}, have you installed the Vulkan SDK?", ext.to_string_lossy()); - None - }) - }).collect::>(); + let exist_exts = entry.enumerate_instance_extension_properties()?; + let mut exts = EXTS + .iter() + .filter_map(|&ext| { + exist_exts + .iter() + .find(|x| CStr::from_ptr(x.extension_name.as_ptr()) == ext) + .map(|_| ext.as_ptr()) + .or_else(|| { + println!( + "Unable to find extension: {}, have you installed the Vulkan SDK?", + ext.to_string_lossy() + ); + None + }) + }) + .collect::>(); + + let surface_extensions = match window_handle { + Some(ref handle) => ash_window::enumerate_required_extensions(*handle)?, + None => vec![], + }; + for extension in surface_extensions { + exts.push(extension.as_ptr()); + } let instance = entry.create_instance( &vk::InstanceCreateInfo::builder() @@ -185,37 +225,51 @@ impl VkInstance { (None, None) }; - Ok(VkInstance { + let vk_surface = match window_handle { + Some(handle) => Some(VkSurface { + surface: ash_window::create_surface(&entry, &instance, handle, None)?, + surface_fn: khr::Surface::new(&entry, &instance), + }), + None => None, + }; + + let vk_instance = VkInstance { entry, instance, _dbg_loader, _dbg_callbk, - }) + }; + + Ok((vk_instance, vk_surface)) } } - /// Create a device from the instance, suitable for compute. + /// Create a device from the instance, suitable for compute, with an optional surface. /// /// # Safety /// - /// The caller is responsible for making sure that the instance outlives the device. - /// We could enforce that, for example having an `Arc` of the raw instance, but for - /// now keep things simple. - pub unsafe fn device(&self) -> Result { + /// The caller is responsible for making sure that the instance outlives the device + /// and surface. We could enforce that, for example having an `Arc` of the raw instance, + /// but for now keep things simple. + pub unsafe fn device(&self, surface: Option<&VkSurface>) -> Result { let devices = self.instance.enumerate_physical_devices()?; let (pdevice, qfi) = - choose_compute_device(&self.instance, &devices).ok_or("no suitable device")?; + choose_compute_device(&self.instance, &devices, surface).ok_or("no suitable device")?; - let device = self.instance.create_device( - pdevice, - &vk::DeviceCreateInfo::builder().queue_create_infos(&[ - vk::DeviceQueueCreateInfo::builder() - .queue_family_index(qfi) - .queue_priorities(&[1.0]) - .build(), - ]), - None, - )?; + let queue_priorities = [1.0]; + let queue_create_infos = [vk::DeviceQueueCreateInfo::builder() + .queue_family_index(qfi) + .queue_priorities(&queue_priorities) + .build()]; + let extensions = match surface { + Some(_) => vec![khr::Swapchain::name().as_ptr()], + None => vec![], + }; + let create_info = vk::DeviceCreateInfo::builder() + .queue_create_infos(&queue_create_infos) + .enabled_extension_names(&extensions) + .build(); + let device = self.instance.create_device(pdevice, &create_info, None)?; let device_mem_props = self.instance.get_physical_device_memory_properties(pdevice); @@ -229,21 +283,98 @@ impl VkInstance { Ok(VkDevice { device, + physical_device: pdevice, device_mem_props, qfi, queue, timestamp_period, }) } + + pub unsafe fn swapchain( + &self, + device: &VkDevice, + surface: &VkSurface, + ) -> Result { + let formats = surface + .surface_fn + .get_physical_device_surface_formats(device.physical_device, surface.surface)?; + let surface_format = formats + .iter() + .map(|surface_fmt| match surface_fmt.format { + vk::Format::UNDEFINED => { + vk::SurfaceFormatKHR { + format: vk::Format::B8G8R8A8_UNORM, // most common format on desktop + color_space: surface_fmt.color_space, + } + } + _ => *surface_fmt, + }) + .next() + .ok_or("no surface format found")?; + + let capabilities = surface + .surface_fn + .get_physical_device_surface_capabilities(device.physical_device, surface.surface)?; + + let present_modes = surface + .surface_fn + .get_physical_device_surface_present_modes(device.physical_device, surface.surface)?; + + let present_mode = present_modes + .into_iter() + .find(|mode| mode == &vk::PresentModeKHR::MAILBOX) + .unwrap_or(vk::PresentModeKHR::FIFO); + + let image_count = 2; // TODO + let extent = capabilities.current_extent; // TODO: wayland for example will complain here .. + + let create_info = vk::SwapchainCreateInfoKHR::builder() + .surface(surface.surface) + .min_image_count(image_count) + .image_format(surface_format.format) + .image_color_space(surface_format.color_space) + .image_extent(extent) + .image_array_layers(1) + .image_usage(vk::ImageUsageFlags::TRANSFER_DST) + .image_sharing_mode(vk::SharingMode::EXCLUSIVE) + .pre_transform(vk::SurfaceTransformFlagsKHR::IDENTITY) + .composite_alpha(vk::CompositeAlphaFlagsKHR::OPAQUE) + .present_mode(present_mode) + .clipped(true); + + let swapchain_fn = khr::Swapchain::new(&self.instance, &device.device.device); + let swapchain = swapchain_fn.create_swapchain(&create_info, None)?; + + let images = swapchain_fn.get_swapchain_images(swapchain)?; + let acquisition_semaphores = (0..images.len()) + .map(|_| device.create_semaphore()) + .collect::, Error>>()?; + + Ok(VkSwapchain { + swapchain, + swapchain_fn, + + present_queue: device.queue, + + images, + acquisition_semaphores, + acquisition_idx: 0, + extent, + }) + } } impl crate::Device for VkDevice { type Buffer = Buffer; + type Image = Image; type CmdBuf = CmdBuf; type DescriptorSet = DescriptorSet; type Pipeline = Pipeline; type QueryPool = QueryPool; type MemFlags = MemFlags; + type Fence = vk::Fence; + type Semaphore = vk::Semaphore; fn create_buffer(&self, size: u64, mem_flags: MemFlags) -> Result { unsafe { @@ -281,25 +412,127 @@ impl crate::Device for VkDevice { } } + unsafe fn create_image2d( + &self, + width: u32, + height: u32, + mem_flags: Self::MemFlags, + ) -> Result { + let device = &self.device.device; + let extent = vk::Extent3D { + width, + height, + depth: 1, + }; + let image = device.create_image( + &vk::ImageCreateInfo::builder() + .image_type(vk::ImageType::TYPE_2D) + .format(vk::Format::R8G8B8A8_UNORM) + .extent(extent) + .mip_levels(1) + .array_layers(1) + .samples(vk::SampleCountFlags::TYPE_1) + .tiling(vk::ImageTiling::OPTIMAL) + .initial_layout(vk::ImageLayout::UNDEFINED) + .usage(vk::ImageUsageFlags::STORAGE | vk::ImageUsageFlags::TRANSFER_SRC) // write in compute and blit src + .sharing_mode(vk::SharingMode::EXCLUSIVE), + None, + )?; + let mem_requirements = device.get_image_memory_requirements(image); + let mem_type = find_memory_type( + mem_requirements.memory_type_bits, + mem_flags.0, + &self.device_mem_props, + ) + .unwrap(); // TODO: proper error + let image_memory = device.allocate_memory( + &vk::MemoryAllocateInfo::builder() + .allocation_size(mem_requirements.size) + .memory_type_index(mem_type), + None, + )?; + device.bind_image_memory(image, image_memory, 0)?; + let image_view = device.create_image_view( + &vk::ImageViewCreateInfo::builder() + .view_type(vk::ImageViewType::TYPE_2D) + .image(image) + .format(vk::Format::R8G8B8A8_UNORM) + .subresource_range(vk::ImageSubresourceRange { + aspect_mask: vk::ImageAspectFlags::COLOR, + base_mip_level: 0, + level_count: 1, + base_array_layer: 0, + layer_count: 1, + }) + .components(vk::ComponentMapping { + r: vk::ComponentSwizzle::IDENTITY, + g: vk::ComponentSwizzle::IDENTITY, + b: vk::ComponentSwizzle::IDENTITY, + a: vk::ComponentSwizzle::IDENTITY, + }) + .build(), + None, + )?; + Ok(Image { + image, + image_memory, + image_view, + extent, + }) + } + + unsafe fn create_fence(&self, signaled: bool) -> Result { + let device = &self.device.device; + let mut flags = vk::FenceCreateFlags::empty(); + if signaled { + flags |= vk::FenceCreateFlags::SIGNALED; + } + Ok(device.create_fence(&vk::FenceCreateInfo::builder().flags(flags).build(), None)?) + } + + unsafe fn create_semaphore(&self) -> Result { + let device = &self.device.device; + Ok(device.create_semaphore(&vk::SemaphoreCreateInfo::default(), None)?) + } + + unsafe fn wait_and_reset(&self, fences: &[Self::Fence]) -> Result<(), Error> { + let device = &self.device.device; + device.wait_for_fences(fences, true, !0)?; + device.reset_fences(fences)?; + Ok(()) + } + /// This creates a pipeline that runs over the buffer. /// - /// The descriptor set layout is just some number of buffers (this will change). + /// The descriptor set layout is just some number of storage buffers and storage images (this might change). unsafe fn create_simple_compute_pipeline( &self, code: &[u8], n_buffers: u32, + n_images: u32, ) -> Result { let device = &self.device.device; - let bindings = (0..n_buffers) - .map(|i| { + let mut bindings = Vec::new(); + for i in 0..n_buffers { + bindings.push( vk::DescriptorSetLayoutBinding::builder() .binding(i) .descriptor_type(vk::DescriptorType::STORAGE_BUFFER) .descriptor_count(1) .stage_flags(vk::ShaderStageFlags::COMPUTE) - .build() - }) - .collect::>(); + .build(), + ); + } + for i in n_buffers..n_buffers + n_images { + bindings.push( + vk::DescriptorSetLayoutBinding::builder() + .binding(i) + .descriptor_type(vk::DescriptorType::STORAGE_IMAGE) + .descriptor_count(1) + .stage_flags(vk::ShaderStageFlags::COMPUTE) + .build(), + ); + } let descriptor_set_layout = device.create_descriptor_set_layout( &vk::DescriptorSetLayoutCreateInfo::builder().bindings(&bindings), None, @@ -344,12 +577,26 @@ impl crate::Device for VkDevice { &self, pipeline: &Pipeline, bufs: &[&Buffer], + images: &[&Image], ) -> Result { let device = &self.device.device; - let descriptor_pool_sizes = [vk::DescriptorPoolSize::builder() - .ty(vk::DescriptorType::STORAGE_BUFFER) - .descriptor_count(bufs.len() as u32) - .build()]; + let mut descriptor_pool_sizes = Vec::new(); + if !bufs.is_empty() { + descriptor_pool_sizes.push( + vk::DescriptorPoolSize::builder() + .ty(vk::DescriptorType::STORAGE_BUFFER) + .descriptor_count(bufs.len() as u32) + .build(), + ); + } + if !images.is_empty() { + descriptor_pool_sizes.push( + vk::DescriptorPoolSize::builder() + .ty(vk::DescriptorType::STORAGE_IMAGE) + .descriptor_count(images.len() as u32) + .build(), + ); + } let descriptor_pool = device.create_descriptor_pool( &vk::DescriptorPoolCreateInfo::builder() .pool_sizes(&descriptor_pool_sizes) @@ -380,6 +627,23 @@ impl crate::Device for VkDevice { &[], ); } + for (i, image) in images.iter().enumerate() { + let binding = i + bufs.len(); + let image_info = vk::DescriptorImageInfo::builder() + .sampler(vk::Sampler::null()) + .image_view(image.image_view) + .image_layout(vk::ImageLayout::GENERAL) + .build(); + device.update_descriptor_sets( + &[vk::WriteDescriptorSet::builder() + .dst_set(descriptor_sets[0]) + .dst_binding(binding as u32) + .descriptor_type(vk::DescriptorType::STORAGE_IMAGE) + .image_info(&[image_info]) + .build()], + &[], + ); + } Ok(DescriptorSet { descriptor_set: descriptor_sets[0], }) @@ -390,7 +654,7 @@ impl crate::Device for VkDevice { let device = &self.device.device; let command_pool = device.create_command_pool( &vk::CommandPoolCreateInfo::builder() - .flags(vk::CommandPoolCreateFlags::empty()) + .flags(vk::CommandPoolCreateFlags::RESET_COMMAND_BUFFER) .queue_family_index(self.qfi), None, )?; @@ -421,7 +685,7 @@ impl crate::Device for VkDevice { } } - unsafe fn reap_query_pool(&self, pool: Self::QueryPool) -> Result, Error> { + unsafe fn reap_query_pool(&self, pool: &Self::QueryPool) -> Result, Error> { let device = &self.device.device; let mut buf = vec![0u64; pool.n_queries as usize]; device.get_query_pool_results( @@ -431,7 +695,6 @@ impl crate::Device for VkDevice { &mut buf, vk::QueryResultFlags::TYPE_64, )?; - device.destroy_query_pool(pool.pool, None); let ts0 = buf[0]; let tsp = self.timestamp_period as f64 * 1e-9; let result = buf[1..] @@ -444,23 +707,33 @@ impl crate::Device for VkDevice { /// Run the command buffer. /// /// This version simply blocks until it's complete. - unsafe fn run_cmd_buf(&self, cmd_buf: &CmdBuf) -> Result<(), Error> { + unsafe fn run_cmd_buf( + &self, + cmd_buf: &CmdBuf, + wait_semaphores: &[Self::Semaphore], + signal_semaphores: &[Self::Semaphore], + fence: Option<&Self::Fence>, + ) -> Result<(), Error> { let device = &self.device.device; - // Run the command buffer. - let fence = device.create_fence( - &vk::FenceCreateInfo::builder().flags(vk::FenceCreateFlags::empty()), - None, - )?; + let fence = match fence { + Some(fence) => *fence, + None => vk::Fence::null(), + }; + let wait_stages = wait_semaphores + .iter() + .map(|_| vk::PipelineStageFlags::ALL_COMMANDS) + .collect::>(); device.queue_submit( self.queue, &[vk::SubmitInfo::builder() .command_buffers(&[cmd_buf.cmd_buf]) + .wait_semaphores(wait_semaphores) + .signal_semaphores(signal_semaphores) + .wait_dst_stage_mask(&wait_stages) .build()], fence, )?; - device.wait_for_fences(&[fence], true, 100_000_000)?; - // TODO: handle errors better (currently leaks fence and can lead to other problems) Ok(()) } @@ -556,6 +829,37 @@ impl crate::CmdBuf for CmdBuf { ); } + unsafe fn image_barrier( + &mut self, + image: &Image, + src_layout: ImageLayout, + dst_layout: ImageLayout, + ) { + let device = &self.device.device; + device.cmd_pipeline_barrier( + self.cmd_buf, + vk::PipelineStageFlags::ALL_COMMANDS, + vk::PipelineStageFlags::ALL_COMMANDS, + vk::DependencyFlags::empty(), + &[], + &[], + &[vk::ImageMemoryBarrier::builder() + .image(image.image) + .src_access_mask(vk::AccessFlags::MEMORY_WRITE) + .dst_access_mask(vk::AccessFlags::MEMORY_READ) + .old_layout(map_image_layout(src_layout)) + .new_layout(map_image_layout(dst_layout)) + .subresource_range(vk::ImageSubresourceRange { + aspect_mask: vk::ImageAspectFlags::COLOR, + base_mip_level: 0, + level_count: vk::REMAINING_MIP_LEVELS, + base_array_layer: 0, + layer_count: vk::REMAINING_MIP_LEVELS, + }) + .build()], + ); + } + unsafe fn clear_buffer(&self, buffer: &Buffer) { let device = &self.device.device; device.cmd_fill_buffer(self.cmd_buf, buffer.buffer, 0, vk::WHOLE_SIZE, 0); @@ -572,14 +876,74 @@ impl crate::CmdBuf for CmdBuf { ); } + unsafe fn copy_image_to_buffer(&self, src: &Image, dst: &Buffer) { + let device = &self.device.device; + device.cmd_copy_image_to_buffer( + self.cmd_buf, + src.image, + vk::ImageLayout::TRANSFER_SRC_OPTIMAL, + dst.buffer, + &[vk::BufferImageCopy { + buffer_offset: 0, + buffer_row_length: 0, // tight packing + buffer_image_height: 0, // tight packing + image_subresource: vk::ImageSubresourceLayers { + aspect_mask: vk::ImageAspectFlags::COLOR, + mip_level: 0, + base_array_layer: 0, + layer_count: 1, + }, + image_offset: vk::Offset3D { x: 0, y: 0, z: 0 }, + image_extent: src.extent, + }], + ); + } + + unsafe fn blit_image(&self, src: &Image, dst: &Image) { + let device = &self.device.device; + device.cmd_blit_image( + self.cmd_buf, + src.image, + vk::ImageLayout::TRANSFER_SRC_OPTIMAL, + dst.image, + vk::ImageLayout::TRANSFER_DST_OPTIMAL, + &[vk::ImageBlit { + src_subresource: vk::ImageSubresourceLayers { + aspect_mask: vk::ImageAspectFlags::COLOR, + mip_level: 0, + base_array_layer: 0, + layer_count: 1, + }, + src_offsets: [ + vk::Offset3D { x: 0, y: 0, z: 0 }, + vk::Offset3D { + x: src.extent.width as i32, + y: src.extent.height as i32, + z: src.extent.depth as i32, + }, + ], + dst_subresource: vk::ImageSubresourceLayers { + aspect_mask: vk::ImageAspectFlags::COLOR, + mip_level: 0, + base_array_layer: 0, + layer_count: 1, + }, + dst_offsets: [ + vk::Offset3D { x: 0, y: 0, z: 0 }, + vk::Offset3D { + x: dst.extent.width as i32, + y: dst.extent.height as i32, + z: dst.extent.depth as i32, + }, + ], + }], + vk::Filter::LINEAR, + ); + } + unsafe fn reset_query_pool(&mut self, pool: &QueryPool) { let device = &self.device.device; - device.cmd_reset_query_pool( - self.cmd_buf, - pool.pool, - 0, - pool.n_queries, - ); + device.cmd_reset_query_pool(self.cmd_buf, pool.pool, 0, pool.n_queries); } unsafe fn write_timestamp(&mut self, pool: &QueryPool, query: u32) { @@ -603,13 +967,68 @@ impl crate::MemFlags for MemFlags { } } +impl VkSwapchain { + pub unsafe fn next(&mut self) -> Result<(usize, vk::Semaphore), Error> { + let acquisition_semaphore = self.acquisition_semaphores[self.acquisition_idx]; + let (image_idx, _suboptimal) = self.swapchain_fn.acquire_next_image( + self.swapchain, + !0, + self.acquisition_semaphores[self.acquisition_idx], + vk::Fence::null(), + )?; + self.acquisition_idx = (self.acquisition_idx + 1) % self.acquisition_semaphores.len(); + + Ok((image_idx as usize, acquisition_semaphore)) + } + + pub unsafe fn image(&self, idx: usize) -> Image { + Image { + image: self.images[idx], + image_memory: vk::DeviceMemory::null(), + image_view: vk::ImageView::null(), + extent: vk::Extent3D { + width: self.extent.width, + height: self.extent.height, + depth: 1, + }, + } + } + + pub unsafe fn present( + &self, + image_idx: usize, + semaphores: &[vk::Semaphore], + ) -> Result { + Ok(self.swapchain_fn.queue_present( + self.present_queue, + &vk::PresentInfoKHR::builder() + .swapchains(&[self.swapchain]) + .image_indices(&[image_idx as u32]) + .wait_semaphores(semaphores) + .build(), + )?) + } +} + unsafe fn choose_compute_device( instance: &Instance, devices: &[vk::PhysicalDevice], + surface: Option<&VkSurface>, ) -> Option<(vk::PhysicalDevice, u32)> { for pdevice in devices { let props = instance.get_physical_device_queue_family_properties(*pdevice); for (ix, info) in props.iter().enumerate() { + // Check for surface presentation support + if let Some(surface) = surface { + if !surface + .surface_fn + .get_physical_device_surface_support(*pdevice, ix as u32, surface.surface) + .unwrap() + { + continue; + } + } + if info.queue_flags.contains(vk::QueueFlags::COMPUTE) { return Some((*pdevice, ix as u32)); } @@ -644,3 +1063,13 @@ fn convert_u32_vec(src: &[u8]) -> Vec { }) .collect() } + +fn map_image_layout(layout: ImageLayout) -> vk::ImageLayout { + match layout { + ImageLayout::Undefined => vk::ImageLayout::UNDEFINED, + ImageLayout::Present => vk::ImageLayout::PRESENT_SRC_KHR, + ImageLayout::BlitSrc => vk::ImageLayout::TRANSFER_SRC_OPTIMAL, + ImageLayout::BlitDst => vk::ImageLayout::TRANSFER_DST_OPTIMAL, + ImageLayout::General => vk::ImageLayout::GENERAL, + } +} diff --git a/piet-gpu/Cargo.toml b/piet-gpu/Cargo.toml index 2555e62..a922a46 100644 --- a/piet-gpu/Cargo.toml +++ b/piet-gpu/Cargo.toml @@ -6,6 +6,14 @@ description = "A compute-centric GPU 2D renderer." license = "MIT/Apache-2.0" edition = "2018" +[[bin]] +name = "cli" +path = "bin/cli.rs" + +[[bin]] +name = "winit" +path = "bin/winit.rs" + [dependencies.piet-gpu-hal] path = "../piet-gpu-hal" @@ -18,3 +26,4 @@ piet = "0.0.12" png = "0.16.2" rand = "0.7.3" roxmltree = "0.11" +winit = "0.22" diff --git a/piet-gpu/bin/cli.rs b/piet-gpu/bin/cli.rs new file mode 100644 index 0000000..1a3c37a --- /dev/null +++ b/piet-gpu/bin/cli.rs @@ -0,0 +1,89 @@ +use std::fs::File; +use std::io::BufWriter; +use std::path::Path; + + +use piet::Color; + +use piet_gpu_hal::vulkan::VkInstance; +use piet_gpu_hal::{CmdBuf, Device, Error, MemFlags}; + +use piet_gpu::{PietGpuRenderContext, Renderer, render_scene, WIDTH, HEIGHT}; + +#[allow(unused)] +fn dump_scene(buf: &[u8]) { + for i in 0..(buf.len() / 4) { + let mut buf_u32 = [0u8; 4]; + buf_u32.copy_from_slice(&buf[i * 4..i * 4 + 4]); + println!("{:4x}: {:8x}", i * 4, u32::from_le_bytes(buf_u32)); + } +} + +fn main() -> Result<(), Error> { + let (instance, _) = VkInstance::new(None)?; + unsafe { + let device = instance.device(None)?; + + let fence = device.create_fence(false)?; + let mut cmd_buf = device.create_cmd_buf()?; + let query_pool = device.create_query_pool(6)?; + + let mut ctx = PietGpuRenderContext::new(); + render_scene(&mut ctx); + let scene = ctx.get_scene_buf(); + //dump_scene(&scene); + + let renderer = Renderer::new(&device, scene)?; + let image_buf = device.create_buffer((WIDTH * HEIGHT * 4) as u64, MemFlags::host_coherent())?; + + cmd_buf.begin(); + renderer.record(&mut cmd_buf, &query_pool); + cmd_buf.copy_image_to_buffer(&renderer.image_dev, &image_buf); + cmd_buf.finish(); + device.run_cmd_buf(&cmd_buf, &[], &[], Some(&fence))?; + device.wait_and_reset(&[fence])?; + let timestamps = device.reap_query_pool(&query_pool).unwrap(); + println!("Kernel 1 time: {:.3}ms", timestamps[0] * 1e3); + println!( + "Kernel 2s time: {:.3}ms", + (timestamps[1] - timestamps[0]) * 1e3 + ); + println!( + "Kernel 2f time: {:.3}ms", + (timestamps[2] - timestamps[1]) * 1e3 + ); + println!( + "Kernel 3 time: {:.3}ms", + (timestamps[3] - timestamps[2]) * 1e3 + ); + println!( + "Render time: {:.3}ms", + (timestamps[4] - timestamps[3]) * 1e3 + ); + + /* + let mut k1_data: Vec = Default::default(); + device.read_buffer(&segment_buf, &mut k1_data).unwrap(); + dump_k1_data(&k1_data); + */ + + let mut img_data: Vec = Default::default(); + // Note: because png can use a `&[u8]` slice, we could avoid an extra copy + // (probably passing a slice into a closure). But for now: keep it simple. + device.read_buffer(&image_buf, &mut img_data).unwrap(); + + // Write image as PNG file. + let path = Path::new("image.png"); + let file = File::create(path).unwrap(); + let ref mut w = BufWriter::new(file); + + let mut encoder = png::Encoder::new(w, WIDTH as u32, HEIGHT as u32); + encoder.set_color(png::ColorType::RGBA); + encoder.set_depth(png::BitDepth::Eight); + let mut writer = encoder.write_header().unwrap(); + + writer.write_image_data(&img_data).unwrap(); + } + + Ok(()) +} diff --git a/piet-gpu/bin/winit.rs b/piet-gpu/bin/winit.rs new file mode 100644 index 0000000..e5f174a --- /dev/null +++ b/piet-gpu/bin/winit.rs @@ -0,0 +1,122 @@ +use piet_gpu_hal::vulkan::VkInstance; +use piet_gpu_hal::{CmdBuf, Device, Error, ImageLayout}; + +use piet_gpu::{PietGpuRenderContext, Renderer, render_scene, WIDTH, HEIGHT}; + +use winit::{ + event::{Event, WindowEvent}, + event_loop::{ControlFlow, EventLoop}, + window::WindowBuilder, +}; + +const NUM_FRAMES: usize = 2; + +fn main() -> Result<(), Error> { + let event_loop = EventLoop::new(); + let window = WindowBuilder::new() + .with_inner_size(winit::dpi::LogicalSize { + width: (WIDTH / 2) as f64, + height: (HEIGHT / 2) as f64, + }) + .with_resizable(false) // currently not supported + .build(&event_loop)?; + + let (instance, surface) = VkInstance::new(Some(&window))?; + unsafe { + let device = instance.device(surface.as_ref())?; + let mut swapchain = instance.swapchain(&device, surface.as_ref().unwrap())?; + + let mut current_frame = 0; + let present_semaphores = (0..NUM_FRAMES) + .map(|_| device.create_semaphore()) + .collect::, Error>>()?; + let frame_fences = (0..NUM_FRAMES) + .map(|_| device.create_fence(false)) + .collect::, Error>>()?; + let mut cmd_buffers = (0..NUM_FRAMES) + .map(|_| device.create_cmd_buf()) + .collect::, Error>>()?; + let query_pools = (0..NUM_FRAMES) + .map(|_| device.create_query_pool(6)) + .collect::, Error>>()?; + + let mut ctx = PietGpuRenderContext::new(); + render_scene(&mut ctx); + let scene = ctx.get_scene_buf(); + + let renderer = Renderer::new(&device, scene)?; + + event_loop.run(move |event, _, control_flow| { + *control_flow = ControlFlow::Poll; // `ControlFlow::Wait` if only re-render on event + + match event { + Event::WindowEvent { event, window_id } if window_id == window.id() => { + match event { + WindowEvent::CloseRequested => { + *control_flow = ControlFlow::Exit; + } + _ => (), + } + } + Event::MainEventsCleared => { + window.request_redraw(); + } + Event::RedrawRequested(window_id) if window_id == window.id() => { + let frame_idx = current_frame % NUM_FRAMES; + let query_pool = &query_pools[frame_idx]; + + if current_frame >= NUM_FRAMES { + device.wait_and_reset(&[frame_fences[frame_idx]]).unwrap(); + + let timestamps = device.reap_query_pool(query_pool).unwrap(); + window.set_title(&format!("k1: {:.3}ms, k2s: {:.3}ms, k2f: {:.3}ms, k3: {:.3}ms, k4: {:.3}ms", + timestamps[0] * 1e3, + (timestamps[1] - timestamps[0]) * 1e3, + (timestamps[2] - timestamps[1]) * 1e3, + (timestamps[3] - timestamps[2]) * 1e3, + (timestamps[4] - timestamps[3]) * 1e3, + )); + } + + let (image_idx, acquisition_semaphore) = swapchain.next().unwrap(); + let swap_image = swapchain.image(image_idx); + let cmd_buf = &mut cmd_buffers[frame_idx]; + cmd_buf.begin(); + cmd_buf.reset_query_pool(&query_pool); + + renderer.record(cmd_buf, &query_pool); + + // Image -> Swapchain + cmd_buf.image_barrier( + &swap_image, + ImageLayout::Undefined, + ImageLayout::BlitDst, + ); + cmd_buf.blit_image(&renderer.image_dev, &swap_image); + cmd_buf.image_barrier( + &swap_image, + ImageLayout::BlitDst, + ImageLayout::Present, + ); + cmd_buf.finish(); + + device + .run_cmd_buf( + &cmd_buf, + &[acquisition_semaphore], + &[present_semaphores[frame_idx]], + Some(&frame_fences[frame_idx]), + ) + .unwrap(); + + swapchain + .present(image_idx, &[present_semaphores[frame_idx]]) + .unwrap(); + + current_frame += 1; + } + _ => (), + } + }) + } +} diff --git a/piet-gpu/shader/kernel4.comp b/piet-gpu/shader/kernel4.comp index 1754bba..d6f33b7 100644 --- a/piet-gpu/shader/kernel4.comp +++ b/piet-gpu/shader/kernel4.comp @@ -24,9 +24,7 @@ layout(set = 0, binding = 2) buffer FillSegBuf { uint[] fill_seg; }; -layout(set = 0, binding = 3) buffer ImageBuf { - uint[] image; -}; +layout(rgba8, set = 0, binding = 3) uniform writeonly image2D image; #include "ptcl.h" #include "segment.h" @@ -118,8 +116,5 @@ void main() { cmd_ref.offset += Cmd_size; } - // TODO: sRGB - uvec4 s = uvec4(round(vec4(rgb, 1.0) * 255.0)); - uint rgba_packed = s.r | (s.g << 8) | (s.b << 16) | (s.a << 24); - image[xy_uint.y * IMAGE_WIDTH + xy_uint.x] = rgba_packed; + imageStore(image, ivec2(xy_uint), vec4(rgb, 1.0)); } diff --git a/piet-gpu/shader/kernel4.spv b/piet-gpu/shader/kernel4.spv index db03dde..d9dacc0 100644 Binary files a/piet-gpu/shader/kernel4.spv and b/piet-gpu/shader/kernel4.spv differ diff --git a/piet-gpu/src/main.rs b/piet-gpu/src/lib.rs similarity index 60% rename from piet-gpu/src/main.rs rename to piet-gpu/src/lib.rs index c40b4d5..2adbfc1 100644 --- a/piet-gpu/src/main.rs +++ b/piet-gpu/src/lib.rs @@ -1,6 +1,7 @@ -use std::fs::File; -use std::io::BufWriter; -use std::path::Path; +mod render_ctx; +mod pico_svg; + +pub use render_ctx::PietGpuRenderContext; use rand::{Rng, RngCore}; @@ -8,16 +9,12 @@ use piet::kurbo::{BezPath, Circle, Line, Point, Vec2}; use piet::{Color, RenderContext}; use piet_gpu_hal::vulkan::VkInstance; -use piet_gpu_hal::{CmdBuf, Device, MemFlags}; +use piet_gpu_hal::{CmdBuf, Device, Error, ImageLayout, MemFlags}; -mod pico_svg; -mod render_ctx; - -use render_ctx::PietGpuRenderContext; use pico_svg::PicoSvg; -const WIDTH: usize = 2048; -const HEIGHT: usize = 1536; +pub const WIDTH: usize = TILE_W * WIDTH_IN_TILES; +pub const HEIGHT: usize = TILE_H * HEIGHT_IN_TILES; const TILE_W: usize = 16; const TILE_H: usize = 16; @@ -34,7 +31,7 @@ const K2_PER_TILE_SIZE: usize = 8; const N_CIRCLES: usize = 1; -fn render_scene(rc: &mut impl RenderContext) { +pub fn render_scene(rc: &mut impl RenderContext) { let mut rng = rand::thread_rng(); for _ in 0..N_CIRCLES { let color = Color::from_rgba32_u32(rng.next_u32()); @@ -108,72 +105,94 @@ fn dump_k1_data(k1_buf: &[u32]) { } } -fn main() { - let instance = VkInstance::new().unwrap(); - unsafe { - let device = instance.device().unwrap(); +pub struct Renderer { + pub image_dev: D::Image, // resulting image + + scene_buf: D::Buffer, + scene_dev: D::Buffer, + + k1_alloc_buf_host: D::Buffer, + k1_alloc_buf_dev: D::Buffer, + k2s_alloc_buf_host: D::Buffer, + k2s_alloc_buf_dev: D::Buffer, + k2f_alloc_buf_host: D::Buffer, + k2f_alloc_buf_dev: D::Buffer, + k3_alloc_buf_host: D::Buffer, + k3_alloc_buf_dev: D::Buffer, + tilegroup_buf: D::Buffer, + ptcl_buf: D::Buffer, + + k1_pipeline: D::Pipeline, + k1_ds: D::DescriptorSet, + k2s_pipeline: D::Pipeline, + k2s_ds: D::DescriptorSet, + k2f_pipeline: D::Pipeline, + k2f_ds: D::DescriptorSet, + k3_pipeline: D::Pipeline, + k3_ds: D::DescriptorSet, + k4_pipeline: D::Pipeline, + k4_ds: D::DescriptorSet, +} + +impl Renderer { + pub unsafe fn new(device: &D, scene: &[u8]) -> Result { let host = MemFlags::host_coherent(); let dev = MemFlags::device_local(); - let mut ctx = PietGpuRenderContext::new(); - render_scene(&mut ctx); - let scene = ctx.get_scene_buf(); - //dump_scene(&scene); + let scene_buf = device .create_buffer(std::mem::size_of_val(&scene[..]) as u64, host) .unwrap(); let scene_dev = device .create_buffer(std::mem::size_of_val(&scene[..]) as u64, dev) .unwrap(); - device.write_buffer(&scene_buf, &scene).unwrap(); - let tilegroup_buf = device.create_buffer(4 * 1024 * 1024, dev).unwrap(); - let ptcl_buf = device.create_buffer(48 * 1024 * 1024, dev).unwrap(); - let segment_buf = device.create_buffer(64 * 1024 * 1024, dev).unwrap(); - let fill_seg_buf = device.create_buffer(64 * 1024 * 1024, dev).unwrap(); - let image_buf = device - .create_buffer((WIDTH * HEIGHT * 4) as u64, host) - .unwrap(); - let image_dev = device - .create_buffer((WIDTH * HEIGHT * 4) as u64, dev) - .unwrap(); + device.write_buffer(&scene_buf, &scene)?; - let k1_alloc_buf_host = device.create_buffer(4, host).unwrap(); - let k1_alloc_buf_dev = device.create_buffer(4, dev).unwrap(); + let tilegroup_buf = device.create_buffer(4 * 1024 * 1024, dev)?; + let ptcl_buf = device.create_buffer(48 * 1024 * 1024, dev)?; + let segment_buf = device.create_buffer(64 * 1024 * 1024, dev)?; + let fill_seg_buf = device.create_buffer(64 * 1024 * 1024, dev)?; + let image_dev = device.create_image2d(WIDTH as u32, HEIGHT as u32, dev)?; + + let k1_alloc_buf_host = device.create_buffer(4, host)?; + let k1_alloc_buf_dev = device.create_buffer(4, dev)?; let k1_alloc_start = WIDTH_IN_TILEGROUPS * HEIGHT_IN_TILEGROUPS * TILEGROUP_STRIDE; - device - .write_buffer(&k1_alloc_buf_host, &[k1_alloc_start as u32]) - .unwrap(); + device.write_buffer(&k1_alloc_buf_host, &[k1_alloc_start as u32])?; let k1_code = include_bytes!("../shader/kernel1.spv"); - let k1_pipeline = device.create_simple_compute_pipeline(k1_code, 3).unwrap(); + let k1_pipeline = device + .create_simple_compute_pipeline(k1_code, 3, 0)?; let k1_ds = device .create_descriptor_set( &k1_pipeline, &[&scene_dev, &tilegroup_buf, &k1_alloc_buf_dev], - ) - .unwrap(); + &[], + )?; - let k2s_alloc_buf_host = device.create_buffer(4, host).unwrap(); - let k2s_alloc_buf_dev = device.create_buffer(4, dev).unwrap(); + let k2s_alloc_buf_host = device.create_buffer(4, host)?; + let k2s_alloc_buf_dev = device.create_buffer(4, dev)?; let k2s_alloc_start = WIDTH_IN_TILES * HEIGHT_IN_TILES * K2_PER_TILE_SIZE; device .write_buffer(&k2s_alloc_buf_host, &[k2s_alloc_start as u32]) - .unwrap(); + ?; let k2s_code = include_bytes!("../shader/kernel2s.spv"); - let k2s_pipeline = device.create_simple_compute_pipeline(k2s_code, 4).unwrap(); + let k2s_pipeline = device + .create_simple_compute_pipeline(k2s_code, 4, 0) + ?; let k2s_ds = device .create_descriptor_set( &k2s_pipeline, &[&scene_dev, &tilegroup_buf, &segment_buf, &k2s_alloc_buf_dev], + &[], ) - .unwrap(); + ?; - let k2f_alloc_buf_host = device.create_buffer(4, host).unwrap(); - let k2f_alloc_buf_dev = device.create_buffer(4, dev).unwrap(); + let k2f_alloc_buf_host = device.create_buffer(4, host)?; + let k2f_alloc_buf_dev = device.create_buffer(4, dev)?; let k2f_alloc_start = WIDTH_IN_TILES * HEIGHT_IN_TILES * K2_PER_TILE_SIZE; device .write_buffer(&k2f_alloc_buf_host, &[k2f_alloc_start as u32]) - .unwrap(); + ?; let k2f_code = include_bytes!("../shader/kernel2f.spv"); - let k2f_pipeline = device.create_simple_compute_pipeline(k2f_code, 4).unwrap(); + let k2f_pipeline = device.create_simple_compute_pipeline(k2f_code, 4, 0)?; let k2f_ds = device .create_descriptor_set( &k2f_pipeline, @@ -183,17 +202,18 @@ fn main() { &fill_seg_buf, &k2f_alloc_buf_dev, ], + &[], ) - .unwrap(); + ?; - let k3_alloc_buf_host = device.create_buffer(4, host).unwrap(); - let k3_alloc_buf_dev = device.create_buffer(4, dev).unwrap(); + let k3_alloc_buf_host = device.create_buffer(4, host)?; + let k3_alloc_buf_dev = device.create_buffer(4, dev)?; let k3_alloc_start = WIDTH_IN_TILES * HEIGHT_IN_TILES * PTCL_INITIAL_ALLOC; device .write_buffer(&k3_alloc_buf_host, &[k3_alloc_start as u32]) - .unwrap(); + ?; let k3_code = include_bytes!("../shader/kernel3.spv"); - let k3_pipeline = device.create_simple_compute_pipeline(k3_code, 6).unwrap(); + let k3_pipeline = device.create_simple_compute_pipeline(k3_code, 6, 0)?; let k3_ds = device .create_descriptor_set( &k3_pipeline, @@ -205,45 +225,69 @@ fn main() { &ptcl_buf, &k3_alloc_buf_dev, ], + &[], ) - .unwrap(); + ?; let k4_code = include_bytes!("../shader/kernel4.spv"); - let k4_pipeline = device.create_simple_compute_pipeline(k4_code, 4).unwrap(); + let k4_pipeline = device.create_simple_compute_pipeline(k4_code, 3, 1)?; let k4_ds = device - .create_descriptor_set( - &k4_pipeline, - &[&ptcl_buf, &segment_buf, &fill_seg_buf, &image_dev], - ) - .unwrap(); + .create_descriptor_set(&k4_pipeline, &[&ptcl_buf, &segment_buf, &fill_seg_buf], &[&image_dev]) + ?; - let query_pool = device.create_query_pool(6).unwrap(); - let mut cmd_buf = device.create_cmd_buf().unwrap(); - cmd_buf.begin(); - cmd_buf.copy_buffer(&scene_buf, &scene_dev); + Ok(Renderer { + scene_buf, + scene_dev, + image_dev, + k1_alloc_buf_host, + k1_alloc_buf_dev, + k2s_alloc_buf_host, + k2s_alloc_buf_dev, + k2f_alloc_buf_host, + k2f_alloc_buf_dev, + k3_alloc_buf_host, + k3_alloc_buf_dev, + tilegroup_buf, + ptcl_buf, + k1_pipeline, + k1_ds, + k2s_pipeline, + k2s_ds, + k2f_pipeline, + k2f_ds, + k3_pipeline, + k3_ds, + k4_pipeline, + k4_ds, + }) + } + + pub unsafe fn record(&self, cmd_buf: &mut impl CmdBuf, query_pool: &D::QueryPool) { + cmd_buf.copy_buffer(&self.scene_buf, &self.scene_dev); // Note: we could use one alloc buf and reuse it. But we'll stick with // multiple ones for clarity. - cmd_buf.copy_buffer(&k1_alloc_buf_host, &k1_alloc_buf_dev); - cmd_buf.copy_buffer(&k2s_alloc_buf_host, &k2s_alloc_buf_dev); - cmd_buf.copy_buffer(&k2f_alloc_buf_host, &k2f_alloc_buf_dev); - cmd_buf.copy_buffer(&k3_alloc_buf_host, &k3_alloc_buf_dev); + cmd_buf.copy_buffer(&self.k1_alloc_buf_host, &self.k1_alloc_buf_dev); + cmd_buf.copy_buffer(&self.k2s_alloc_buf_host, &self.k2s_alloc_buf_dev); + cmd_buf.copy_buffer(&self.k2f_alloc_buf_host, &self.k2f_alloc_buf_dev); + cmd_buf.copy_buffer(&self.k3_alloc_buf_host, &self.k3_alloc_buf_dev); // Note: these clears aren't necessary, and are here to make inspection // of the buffers cleaner. Can likely be removed. - cmd_buf.clear_buffer(&tilegroup_buf); - cmd_buf.clear_buffer(&ptcl_buf); + cmd_buf.clear_buffer(&self.tilegroup_buf); + cmd_buf.clear_buffer(&self.ptcl_buf); cmd_buf.memory_barrier(); + cmd_buf.image_barrier(&self.image_dev, ImageLayout::Undefined, ImageLayout::General); cmd_buf.reset_query_pool(&query_pool); cmd_buf.write_timestamp(&query_pool, 0); cmd_buf.dispatch( - &k1_pipeline, - &k1_ds, + &self.k1_pipeline, + &self.k1_ds, ((WIDTH / 512) as u32, (HEIGHT / 512) as u32, 1), ); cmd_buf.write_timestamp(&query_pool, 1); cmd_buf.memory_barrier(); cmd_buf.dispatch( - &k2s_pipeline, - &k2s_ds, + &self.k2s_pipeline, + &self.k2s_ds, ((WIDTH / 512) as u32, (HEIGHT / 16) as u32, 1), ); cmd_buf.write_timestamp(&query_pool, 2); @@ -252,69 +296,26 @@ fn main() { // of performance. cmd_buf.memory_barrier(); cmd_buf.dispatch( - &k2f_pipeline, - &k2f_ds, + &self.k2f_pipeline, + &self.k2f_ds, ((WIDTH / 512) as u32, (HEIGHT / 16) as u32, 2), ); cmd_buf.write_timestamp(&query_pool, 3); cmd_buf.memory_barrier(); cmd_buf.dispatch( - &k3_pipeline, - &k3_ds, + &self.k3_pipeline, + &self.k3_ds, ((WIDTH / 512) as u32, (HEIGHT / 16) as u32, 3), ); cmd_buf.write_timestamp(&query_pool, 4); cmd_buf.memory_barrier(); cmd_buf.dispatch( - &k4_pipeline, - &k4_ds, + &self.k4_pipeline, + &self.k4_ds, ((WIDTH / TILE_W) as u32, (HEIGHT / TILE_H) as u32, 1), ); cmd_buf.write_timestamp(&query_pool, 5); cmd_buf.memory_barrier(); - cmd_buf.copy_buffer(&image_dev, &image_buf); - cmd_buf.finish(); - device.run_cmd_buf(&cmd_buf).unwrap(); - let timestamps = device.reap_query_pool(query_pool).unwrap(); - println!("Kernel 1 time: {:.3}ms", timestamps[0] * 1e3); - println!( - "Kernel 2s time: {:.3}ms", - (timestamps[1] - timestamps[0]) * 1e3 - ); - println!( - "Kernel 2f time: {:.3}ms", - (timestamps[2] - timestamps[1]) * 1e3 - ); - println!( - "Kernel 3 time: {:.3}ms", - (timestamps[3] - timestamps[2]) * 1e3 - ); - println!( - "Render time: {:.3}ms", - (timestamps[4] - timestamps[3]) * 1e3 - ); - - /* - let mut k1_data: Vec = Default::default(); - device.read_buffer(&segment_buf, &mut k1_data).unwrap(); - dump_k1_data(&k1_data); - */ - - let mut img_data: Vec = Default::default(); - // Note: because png can use a `&[u8]` slice, we could avoid an extra copy - // (probably passing a slice into a closure). But for now: keep it simple. - device.read_buffer(&image_buf, &mut img_data).unwrap(); - - // Write image as PNG file. - let path = Path::new("image.png"); - let file = File::create(path).unwrap(); - let ref mut w = BufWriter::new(file); - - let mut encoder = png::Encoder::new(w, WIDTH as u32, HEIGHT as u32); - encoder.set_color(png::ColorType::RGBA); - encoder.set_depth(png::BitDepth::Eight); - let mut writer = encoder.write_header().unwrap(); - - writer.write_image_data(&img_data).unwrap(); + cmd_buf.image_barrier(&self.image_dev, ImageLayout::General, ImageLayout::BlitSrc); } }