From a9859b4bb4d6598e15a600bfe1f6d29410d05286 Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Sat, 23 May 2020 12:36:47 -0700 Subject: [PATCH] Refactor to generalize pipeline drawing sequence --- .gitignore | 1 + Cargo.lock | 289 ++++++++++++++++++++++--------------- Cargo.toml | 3 +- shaders/shader.frag | 22 ++- src/application.rs | 193 ++++++++----------------- src/bind_group_resource.rs | 13 ++ src/color.rs | 77 ++++++++++ src/color_palette.rs | 21 ++- src/draw_command.rs | 8 +- src/gui_attributes.rs | 42 ++++++ src/gui_node.rs | 83 +++++++++++ src/gui_rect.rs | 23 --- src/gui_tree.rs | 9 -- src/main.rs | 7 +- src/pipeline.rs | 129 +++++++++++++---- src/texture.rs | 10 ++ src/window_events.rs | 17 ++- src/window_uniform.rs | 18 +++ 18 files changed, 628 insertions(+), 337 deletions(-) create mode 100644 src/bind_group_resource.rs create mode 100644 src/color.rs create mode 100644 src/gui_attributes.rs create mode 100644 src/gui_node.rs delete mode 100644 src/gui_rect.rs delete mode 100644 src/gui_tree.rs create mode 100644 src/window_uniform.rs diff --git a/.gitignore b/.gitignore index ea8c4bf7..1ade5b68 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +*.spv \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 57dafdd8..15f66aec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,14 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "addr2line" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a49806b9dadc843c61e7c97e72490ad7f7220ae249012fbda9ad0609457c0543" +dependencies = [ + "gimli", +] + [[package]] name = "adler32" version = "1.0.4" @@ -76,26 +85,17 @@ checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" [[package]] name = "backtrace" -version = "0.3.46" +version = "0.3.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e692897359247cc6bb902933361652380af0f1b7651ae5c5013407f30e109e" +checksum = "0df2f85c8a2abbe3b7d7e748052fdd9b76a0458fdeb16ad4223f5eca78c7c130" dependencies = [ - "backtrace-sys", + "addr2line", "cfg-if", "libc", + "object", "rustc-demangle", ] -[[package]] -name = "backtrace-sys" -version = "0.1.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78848718ee1255a2485d1309ad9cdecfc2e7d0362dd11c6829364c6b35ae1bc7" -dependencies = [ - "cc", - "libc", -] - [[package]] name = "bitflags" version = "1.2.1" @@ -120,9 +120,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.2.1" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12ae9db68ad7fac5fe51304d20f016c911539251075a214f8e663babefa35187" +checksum = "5356f1d23ee24a1f785a56d1d1a5f0fd5b0f6a0c0fb2412ce11da71649ab78f6" [[package]] name = "byte-tools" @@ -155,9 +155,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.52" +version = "1.0.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d87b23d6a92cd03af510a5ade527033f6aa6fa92161e2d5863a907d4c5e31d" +checksum = "7bbb73db36c1246e9034e307d0fba23f9a2e251faa47ade70c1bd252220c8311" [[package]] name = "cfg-if" @@ -187,9 +187,9 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.42" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fb25b677f8bf1eb325017cb6bb8452f87969db0fedb4f757b297bee78a7c62" +checksum = "0e56268c17a6248366d66d4a47a3381369d068cce8409bb1716ed77ea32163bb" dependencies = [ "cc", ] @@ -211,9 +211,9 @@ dependencies = [ [[package]] name = "cocoa" -version = "0.20.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a4736c86d51bd878b474400d9ec888156f4037015f5d09794fab9f26eab1ad4" +checksum = "8f7b6f3f7f4f0b3ec5c5039aaa9e8c3cef97a7a480a400fd62944841314f293d" dependencies = [ "bitflags", "block", @@ -294,13 +294,13 @@ dependencies = [ [[package]] name = "core-video-sys" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dc065219542086f72d1e9f7aadbbab0989e980263695d129d502082d063a9d0" +checksum = "34ecad23610ad9757664d644e369246edde1803fcb43ed72876565098a5d3828" dependencies = [ "cfg-if", - "core-foundation-sys 0.6.2", - "core-graphics 0.17.3", + "core-foundation-sys 0.7.0", + "core-graphics 0.19.0", "libc", "objc", ] @@ -420,9 +420,9 @@ checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" [[package]] name = "failure" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8529c2421efa3066a5cbd8063d2244603824daccb6936b079010bb2aa89464b" +checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" dependencies = [ "backtrace", "failure_derive", @@ -430,13 +430,13 @@ dependencies = [ [[package]] name = "failure_derive" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "030a733c8287d6213886dd487564ff5c8f6aae10278b3588ed177f9d18f8d231" +checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" dependencies = [ - "proc-macro2 1.0.10", - "quote 1.0.3", - "syn 1.0.18", + "proc-macro2 1.0.15", + "quote 1.0.6", + "syn 1.0.23", "synstructure", ] @@ -485,9 +485,9 @@ checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" [[package]] name = "futures" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c329ae8753502fb44ae4fc2b622fa2a94652c41e795143765ba0927f92ab780" +checksum = "1e05b85ec287aac0dc34db7d4a569323df697f9c55b99b15d6b4ef8cde49f613" dependencies = [ "futures-channel", "futures-core", @@ -500,9 +500,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c77d04ce8edd9cb903932b608268b3fffec4163dc053b3b402bf47eac1f1a8" +checksum = "f366ad74c28cca6ba456d95e6422883cfb4b252a83bed929c83abfdbbf2967d5" dependencies = [ "futures-core", "futures-sink", @@ -510,15 +510,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f25592f769825e89b92358db00d26f965761e094951ac44d3663ef25b7ac464a" +checksum = "59f5fff90fd5d971f936ad674802482ba441b6f09ba5e15fd8b39145582ca399" [[package]] name = "futures-executor" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f674f3e1bcb15b37284a90cedf55afdba482ab061c407a9c0ebbd0f3109741ba" +checksum = "10d6bb888be1153d3abeb9006b11b02cf5e9b209fda28693c31ae1e4e012e314" dependencies = [ "futures-core", "futures-task", @@ -527,39 +527,42 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a638959aa96152c7a4cddf50fcb1e3fede0583b27157c26e67d6f99904090dc6" +checksum = "de27142b013a8e869c14957e6d2edeef89e97c289e69d042ee3a49acd8b51789" [[package]] name = "futures-macro" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a5081aa3de1f7542a794a397cde100ed903b0630152d0973479018fd85423a7" +checksum = "d0b5a30a4328ab5473878237c447333c093297bded83a4983d10f4deea240d39" dependencies = [ "proc-macro-hack", - "proc-macro2 1.0.10", - "quote 1.0.3", - "syn 1.0.18", + "proc-macro2 1.0.15", + "quote 1.0.6", + "syn 1.0.23", ] [[package]] name = "futures-sink" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3466821b4bc114d95b087b850a724c6f83115e929bc88f1fa98a3304a944c8a6" +checksum = "3f2032893cb734c7a05d85ce0cc8b8c4075278e93b24b66f9de99d6eb0fa8acc" [[package]] name = "futures-task" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0a34e53cf6cdcd0178aa573aed466b646eb3db769570841fda0c7ede375a27" +checksum = "bdb66b5f09e22019b1ab0830f7785bcea8e7a42148683f99214f73f8ec21a626" +dependencies = [ + "once_cell", +] [[package]] name = "futures-util" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22766cf25d64306bedf0384da004d05c9974ab104fcc4528f1236181c18004c5" +checksum = "8764574ff08b701a084482c3c7031349104b07ac897393010494beaa18ce32c6" dependencies = [ "futures-channel", "futures-core", @@ -568,6 +571,7 @@ dependencies = [ "futures-sink", "futures-task", "memchr", + "pin-project", "pin-utils", "proc-macro-hack", "proc-macro-nested", @@ -605,9 +609,9 @@ dependencies = [ [[package]] name = "gfx-auxil" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b46e6f0031330a0be08d17820f2dcaaa91cb36710a97a9500cb4f1c36e785c8" +checksum = "67bdbf8e8d6883c70e5a0d7379ad8ab3ac95127a3761306b36122d8f1c177a8e" dependencies = [ "fxhash", "gfx-hal", @@ -616,9 +620,9 @@ dependencies = [ [[package]] name = "gfx-backend-dx11" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b148219292624126f78245e50a9720d95ea149a415ce8ce73ab7014205301b88" +checksum = "92de0ddc0fde1a89b2a0e92dcc6bbb554bd34af0135e53a28d5ef064611094a4" dependencies = [ "bitflags", "gfx-auxil", @@ -636,9 +640,9 @@ dependencies = [ [[package]] name = "gfx-backend-dx12" -version = "0.5.0" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0e526746379e974501551b08958947e67a81b5ea8cdc717a000cdd72577da05" +checksum = "37365e2927d55cefac0d3f78dfd1d3119fbb13a8bd7afe2409d729961fee22fc" dependencies = [ "bitflags", "d3d12", @@ -664,14 +668,14 @@ dependencies = [ [[package]] name = "gfx-backend-metal" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfe128c29675b5afc8acdda1dfe096d6abd5e3528059ab0b98bda8215d8beed9" +checksum = "205f3ca8e74ed814ea2c0206d47d8925077673cab2e21f9b12d48ff781cf87ee" dependencies = [ "arrayvec", "bitflags", "block", - "cocoa 0.20.0", + "cocoa 0.20.1", "copyless", "core-graphics 0.19.0", "foreign-types", @@ -753,6 +757,12 @@ dependencies = [ "lzw", ] +[[package]] +name = "gimli" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc8e0c9bce37868955864dbecd2b1ab2bdf967e6f28066d65aaac620444b65c" + [[package]] name = "glsl-to-spirv" version = "0.1.7" @@ -775,15 +785,16 @@ dependencies = [ "glsl-to-spirv", "image", "palette", + "rctree", "wgpu", "winit", ] [[package]] name = "hermit-abi" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61565ff7aaace3525556587bd2dc31d4a07071957be715e63ce7b1eccf51a8f4" +checksum = "91780f809e750b0a89f5544be56617ff6b1227ee485bcb06ebe10cdf89bd3b71" dependencies = [ "libc", ] @@ -825,9 +836,9 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7152d2aed88aa566e7a342250f21ba2222c1ae230ad577499dbfa3c18475b80" +checksum = "7777a24a1ce5de49fcdde84ec46efa487c3af49d5b6e6e0a50367cc5c1096182" [[package]] name = "iovec" @@ -850,9 +861,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.37" +version = "0.3.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a27d435371a2fa5b6d2b028a74bbdb1234f308da363226a2854ca3ff8ba7055" +checksum = "fa5a448de267e7358beaf4a5d849518fe9a0c13fce7afd44b06e68550e5562a7" dependencies = [ "wasm-bindgen", ] @@ -881,9 +892,9 @@ checksum = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" [[package]] name = "libc" -version = "0.2.69" +version = "0.2.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99e85c08494b21a9054e7fe1374a732aeadaff3980b6990b94bfd3a70f690005" +checksum = "3baa92041a6fec78c687fa0cc2b3fae8884f743d672cf551bed1d6dac6988d0f" [[package]] name = "libloading" @@ -976,7 +987,7 @@ checksum = "e198a0ee42bdbe9ef2c09d0b9426f3b2b47d90d93a4a9b0395c4cea605e92dc0" dependencies = [ "bitflags", "block", - "cocoa 0.20.0", + "cocoa 0.20.1", "core-graphics 0.19.0", "foreign-types", "log", @@ -985,9 +996,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.6.21" +version = "0.6.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302dec22bcf6bae6dfb69c647187f4b4d0fb6f535521f7bc022430ce8e12008f" +checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430" dependencies = [ "cfg-if", "fuchsia-zircon", @@ -1028,9 +1039,9 @@ dependencies = [ [[package]] name = "net2" -version = "0.2.33" +version = "0.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" +checksum = "2ba7c918ac76704fb42afcbbb43891e72731f3dcca3bef2a19786297baf14af7" dependencies = [ "cfg-if", "libc", @@ -1131,6 +1142,18 @@ dependencies = [ "cc", ] +[[package]] +name = "object" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cbca9424c482ee628fa549d9c812e2cd22f1180b9222c9200fdfa6eb31aecb2" + +[[package]] +name = "once_cell" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d" + [[package]] name = "ordered-float" version = "1.0.2" @@ -1159,9 +1182,9 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b4b5f600e60dd3a147fb57b4547033d382d1979eb087af310e91cb45a63b1f4" dependencies = [ - "proc-macro2 1.0.10", - "quote 1.0.3", - "syn 1.0.18", + "proc-macro2 1.0.15", + "quote 1.0.6", + "syn 1.0.23", ] [[package]] @@ -1203,9 +1226,9 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fb44a25c5bba983be0fc8592dfaf3e6d0935ce8be0c6b15b2a39507af34a926" dependencies = [ - "proc-macro2 1.0.10", - "quote 1.0.3", - "syn 1.0.18", + "proc-macro2 1.0.15", + "quote 1.0.6", + "syn 1.0.23", "synstructure", "unicode-xid 0.2.0", ] @@ -1254,6 +1277,26 @@ dependencies = [ "siphasher", ] +[[package]] +name = "pin-project" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edc93aeee735e60ecb40cf740eb319ff23eab1c5748abfdb5c180e4ce49f7791" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e58db2081ba5b4c93bd6be09c40fd36cb9193a8336c384f3b40012e531aa7e40" +dependencies = [ + "proc-macro2 1.0.15", + "quote 1.0.6", + "syn 1.0.23", +] + [[package]] name = "pin-utils" version = "0.1.0" @@ -1280,9 +1323,9 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" +checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" [[package]] name = "proc-macro-hack" @@ -1307,9 +1350,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.10" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3" +checksum = "70a50b9351bfa8d65a7d93ce712dc63d2fd15ddbf2c36990fc7cac344859c04f" dependencies = [ "unicode-xid 0.2.0", ] @@ -1325,11 +1368,11 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.3" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" +checksum = "54a21852a652ad6f610c9510194f398ff6f8692e334fd1145fed931f7fbe44ea" dependencies = [ - "proc-macro2 1.0.10", + "proc-macro2 1.0.15", ] [[package]] @@ -1528,6 +1571,12 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "rctree" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be9e29cb19c8fe84169fcb07f8f11e66bc9e6e0280efd4715c54818296f8a4a8" + [[package]] name = "rdrand" version = "0.4.0" @@ -1647,9 +1696,9 @@ dependencies = [ [[package]] name = "spirv_cross" -version = "0.18.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "946216f8793f7199e3ea5b995ee8dc20a0ace1fcf46293a0ef4c17e1d046dbde" +checksum = "a33a9478e9c78782dd694d05dee074703a9c4c74b511de742b88a7e8149f1b37" dependencies = [ "cc", "js-sys", @@ -1687,12 +1736,12 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.18" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "410a7488c0a728c7ceb4ad59b9567eb4053d02e8cc7f5c0e0eeeb39518369213" +checksum = "95b5f192649e48a5302a13f2feb224df883b98933222369e4b3b0fe2a5447269" dependencies = [ - "proc-macro2 1.0.10", - "quote 1.0.3", + "proc-macro2 1.0.15", + "quote 1.0.6", "unicode-xid 0.2.0", ] @@ -1702,9 +1751,9 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" dependencies = [ - "proc-macro2 1.0.10", - "quote 1.0.3", - "syn 1.0.18", + "proc-macro2 1.0.15", + "quote 1.0.6", + "syn 1.0.23", "unicode-xid 0.2.0", ] @@ -1754,9 +1803,9 @@ checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" [[package]] name = "vec_map" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "void" @@ -1783,9 +1832,9 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "wasm-bindgen" -version = "0.2.60" +version = "0.2.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc57ce05287f8376e998cbddfb4c8cb43b84a7ec55cf4551d7c00eef317a47f" +checksum = "e3c7d40d09cdbf0f4895ae58cf57d92e1e57a9dd8ed2e8390514b54a47cc5551" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -1793,47 +1842,47 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.60" +version = "0.2.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d967d37bf6c16cca2973ca3af071d0a2523392e4a594548155d89a678f4237cd" +checksum = "c3972e137ebf830900db522d6c8fd74d1900dcfc733462e9a12e942b00b4ac94" dependencies = [ "bumpalo", "lazy_static", "log", - "proc-macro2 1.0.10", - "quote 1.0.3", - "syn 1.0.18", + "proc-macro2 1.0.15", + "quote 1.0.6", + "syn 1.0.23", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.60" +version = "0.2.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bd151b63e1ea881bb742cd20e1d6127cef28399558f3b5d415289bc41eee3a4" +checksum = "2cd85aa2c579e8892442954685f0d801f9129de24fa2136b2c6a539c76b65776" dependencies = [ - "quote 1.0.3", + "quote 1.0.6", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.60" +version = "0.2.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d68a5b36eef1be7868f668632863292e37739656a80fc4b9acec7b0bd35a4931" +checksum = "8eb197bd3a47553334907ffd2f16507b4f4f01bbec3ac921a7719e0decdfe72a" dependencies = [ - "proc-macro2 1.0.10", - "quote 1.0.3", - "syn 1.0.18", + "proc-macro2 1.0.15", + "quote 1.0.6", + "syn 1.0.23", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.60" +version = "0.2.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf76fe7d25ac79748a37538b7daeed1c7a6867c92d3245c12c6222e4a20d639" +checksum = "a91c2916119c17a8e316507afaaa2dd94b47646048014bbdf6bef098c1bb58ad" [[package]] name = "wayland-client" @@ -1912,9 +1961,9 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50212a35d2c20de1c421d9a0d831f494a85f9afab240e19aae499cff9d0526f2" +checksum = "b093098e0782b0f46f154fac5c670ba27b7a5bff98dc943422c13852c696a2b0" dependencies = [ "arrayvec", "bitflags", @@ -1954,9 +2003,9 @@ dependencies = [ [[package]] name = "wgpu-types" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b69dfe001a8a6b78810c7e479717cd1898b9177dbf646611fa1f258f5a2512" +checksum = "f3474b5ce2ed628e158c2fe4387a469b2ee119604556aa2debd10d830cedc3bc" dependencies = [ "bitflags", "peek-poke", diff --git a/Cargo.toml b/Cargo.toml index 80994677..e4ee7130 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,4 +15,5 @@ failure = "0.1.7" cgmath = "0.17" palette = "0.5" futures = "0.3.4" -bytemuck = "1.2.0" \ No newline at end of file +bytemuck = "1.2.0" +rctree = "0.3.3" diff --git a/shaders/shader.frag b/shaders/shader.frag index 2327b894..0b49372a 100644 --- a/shaders/shader.frag +++ b/shaders/shader.frag @@ -4,8 +4,24 @@ layout(location=0) in vec2 v_uv; layout(location=0) out vec4 f_color; -layout(set = 0, binding = 0) uniform sampler2D t_texture; +struct Dimensions_u32 { uint width; uint height; }; +struct Corners_f32 { float top_left; float top_right; float bottom_right; float bottom_left; }; +struct Sides_f32 { float top; float right; float bottom; float left; }; + +layout(set=0, binding=0) uniform GuiNodeUniform { + Dimensions_u32 dimensions; + Corners_f32 corners_radius; + Sides_f32 sides_inset; + float border_thickness; + vec4 border_color; + vec4 fill_color; +}; +layout(set=0, binding=1) uniform sampler2D t_texture; + +// layout(set=1, binding=0) uniform WindowUniform { +// Dimensions_u32 window_dimensions; +// }; void main() { - f_color = texture(t_texture, v_uv / textureSize(t_texture, 0) * 100); -} \ No newline at end of file + f_color = fill_color * texture(t_texture, v_uv / textureSize(t_texture, 0) * 100); +} diff --git a/src/application.rs b/src/application.rs index 1668d1fa..ef1fce3f 100644 --- a/src/application.rs +++ b/src/application.rs @@ -1,12 +1,10 @@ -use super::color_palette::ColorPalette; -use super::window_events; -use super::pipeline::Pipeline; -use super::texture::Texture; -use super::shader_stage::compile_from_glsl; -use super::resource_cache::ResourceCache; -use super::draw_command::DrawCommand; -use super::gui_tree::GuiTree; -use std::collections::VecDeque; +use crate::color_palette::ColorPalette; +use crate::window_events; +use crate::pipeline::Pipeline; +use crate::texture::Texture; +use crate::resource_cache::ResourceCache; +use crate::draw_command::DrawCommand; +use crate::gui_node::GuiNode; use winit::event::*; use winit::event_loop::*; use winit::window::Window; @@ -20,12 +18,9 @@ pub struct Application { pub swap_chain_descriptor: wgpu::SwapChainDescriptor, pub swap_chain: wgpu::SwapChain, pub shader_cache: ResourceCache, - pub bind_group_cache: ResourceCache, pub pipeline_cache: ResourceCache, pub texture_cache: ResourceCache, - pub draw_command_queue: VecDeque, - pub gui_tree: GuiTree, - pub temp_color_toggle: bool, + pub gui_root: rctree::Node, } impl Application { @@ -67,17 +62,24 @@ impl Application { let swap_chain = device.create_swap_chain(&surface, &swap_chain_descriptor); // Resource caches that own the application's shaders, pipelines, and textures - let shader_cache = ResourceCache::::new(); - let bind_group_cache = ResourceCache::::new(); - let pipeline_cache = ResourceCache::::new(); + let mut shader_cache = ResourceCache::::new(); + let mut pipeline_cache = ResourceCache::::new(); let texture_cache = ResourceCache::::new(); - // Ordered list of draw commands to send to the GPU on the next frame render - let draw_command_queue = VecDeque::new(); + // Temporary setup below, TODO: move to appropriate place in architecture - // Data structure maintaining the user interface - let gui_tree = GuiTree::new(); + // Window uniform bind group layout + let window_binding_types = vec![wgpu::BindingType::UniformBuffer { dynamic: false }]; + let window_bind_group_layout = Pipeline::build_bind_group_layout(&device, &window_binding_types); + // Data structure maintaining the user interface + // let extra_layouts = vec![&window_bind_group_layout]; + let gui_rect_pipeline = Pipeline::new(&device, swap_chain_descriptor.format, vec![], &mut shader_cache, ("shaders/shader.vert", "shaders/shader.frag")); + pipeline_cache.set("gui_rect", gui_rect_pipeline); + + let gui_root_data = GuiNode::new(swap_chain_descriptor.width, swap_chain_descriptor.height, ColorPalette::get_color_srgb(ColorPalette::Accent)); + let gui_root = rctree::Node::new(gui_root_data); + Self { surface, adapter, @@ -86,85 +88,12 @@ impl Application { swap_chain_descriptor, swap_chain, shader_cache, - bind_group_cache, pipeline_cache, texture_cache, - draw_command_queue, - gui_tree, - temp_color_toggle: true, + gui_root, } } - pub fn example(&mut self) { - // Example vertex data - const VERTICES: &[[f32; 2]] = &[ - [-0.5, 0.5], - [0.5, 0.5], - [0.5, 1.0], - [-0.5, 1.0], - ]; - const INDICES: &[u16] = &[ - 0, 1, 2, - 0, 2, 3, - ]; - - // If uncached, construct a vertex shader loaded from its source code file - let vertex_shader_path = "shaders/shader.vert"; - if self.shader_cache.get(vertex_shader_path).is_none() { - let vertex_shader_module = compile_from_glsl(&self.device, vertex_shader_path, glsl_to_spirv::ShaderType::Vertex).unwrap(); - self.shader_cache.set(vertex_shader_path, vertex_shader_module); - } - - // If uncached, construct a fragment shader loaded from its source code file - let fragment_shader_path = "shaders/shader.frag"; - if self.shader_cache.get(fragment_shader_path).is_none() { - let fragment_shader_module = compile_from_glsl(&self.device, fragment_shader_path, glsl_to_spirv::ShaderType::Fragment).unwrap(); - self.shader_cache.set(fragment_shader_path, fragment_shader_module); - } - - // Get the shader pair - let vertex_shader = self.shader_cache.get(vertex_shader_path).unwrap(); - let fragment_shader = self.shader_cache.get(fragment_shader_path).unwrap(); - - // If uncached, construct a pipeline from the shader pair - let pipeline_name = "example-pipeline"; - if self.pipeline_cache.get(pipeline_name).is_none() { - let bind_group_layout_binding_types = vec![ - wgpu::BindingType::SampledTexture { - dimension: wgpu::TextureViewDimension::D2, - component_type: wgpu::TextureComponentType::Float, - multisampled: false, - }, - // ty: wgpu::BindingType::Sampler, - ]; - let pipeline = Pipeline::new(&self.device, vertex_shader, fragment_shader, bind_group_layout_binding_types); - self.pipeline_cache.set(pipeline_name, pipeline); - } - let example_pipeline = self.pipeline_cache.get(pipeline_name).unwrap(); - - // If uncached, construct a texture loaded from the image file - let texture_path = "textures/grid.png"; - if self.texture_cache.get(texture_path).is_none() { - let texture = Texture::from_filepath(&self.device, &mut self.queue, texture_path).unwrap(); - self.texture_cache.set(texture_path, texture); - } - let grid_texture = self.texture_cache.get(texture_path).unwrap(); - - // If uncached, construct a bind group with resources matching the pipeline's bind group layout - let bind_group_name = "example-bindgroup"; - if self.bind_group_cache.get(bind_group_name).is_none() { - let binding_resources = vec![ - wgpu::BindingResource::TextureView(&grid_texture.texture_view), - ]; - let bind_group = example_pipeline.build_bind_group(&self.device, binding_resources); - self.bind_group_cache.set(bind_group_name, bind_group); - } - - // Create a draw command with the vertex data and bind group and push it to the GPU command queue - let draw_command = DrawCommand::new(&self.device, pipeline_name, bind_group_name, VERTICES, INDICES); - self.draw_command_queue.push_back(draw_command); - } - // Initializes the event loop for rendering and event handling pub fn begin_lifecycle(mut self, event_loop: EventLoop<()>, window: Window) { event_loop.run(move |event, _, control_flow| self.main_event_loop(event, control_flow, &window)); @@ -182,8 +111,8 @@ impl Application { Event::DeviceEvent { .. } => (), // Handle custom-dispatched events Event::UserEvent(_) => (), - // Once every event is handled and the GUI structure is updated, this requests a new sequence of draw commands - Event::MainEventsCleared => self.redraw_gui(window), + // Called once every event is handled and the GUI structure is updated + Event::MainEventsCleared => self.update_gui(window), // Resizing or calling `window.request_redraw()` renders the GUI with the queued draw commands Event::RedrawRequested(_) => self.render(), // Once all windows have been redrawn @@ -196,14 +125,8 @@ impl Application { } } - // Traverse dirty GUI elements and turn GUI changes into draw commands added to the render pipeline queue - pub fn redraw_gui(&mut self, window: &Window) { - self.example(); - - // If any draw commands were actually added, ask the window to dispatch a redraw event - if !self.draw_command_queue.is_empty() { - window.request_redraw(); - } + pub fn update_gui(&mut self, window: &Window) { + } // Render the queue of pipeline draw commands over the current window @@ -214,12 +137,21 @@ impl Application { // Generates a render pass that commands are applied to, then generates a command buffer when finished let mut command_encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: Some("Render Encoder") }); - // Temporary way to swap clear color every render - let color = match self.temp_color_toggle { - true => ColorPalette::get_color_linear(ColorPalette::MildBlack), - false => ColorPalette::get_color_linear(ColorPalette::NearBlack), - }; - self.temp_color_toggle = !self.temp_color_toggle; + // Build an array of draw commands + let gui_node = self.gui_root.borrow_mut(); + let mut nodes = vec![gui_node]; // TODO: Generate the DrawCommands as a list by recursively traversing the gui node tree + + let device = &mut self.device; + + // let commands: Vec = nodes.map(|mut node| node.build_draw_command(dev)).collect(); + let mut commands = Vec::::with_capacity(nodes.len()); + let mut bind_groups = Vec::>::with_capacity(nodes.len()); + for i in 0..nodes.len() { + let new_pipeline = self.pipeline_cache.get("gui_rect").unwrap(); + + commands.push(nodes[i].build_draw_command(device)); + bind_groups.push(nodes[i].build_bind_groups(device, &mut self.queue, new_pipeline, &mut self.texture_cache)); + } // Recording of commands while in "rendering mode" that go into a command buffer let mut render_pass = command_encoder.begin_render_pass(&wgpu::RenderPassDescriptor { @@ -229,34 +161,40 @@ impl Application { resolve_target: None, load_op: wgpu::LoadOp::Clear, store_op: wgpu::StoreOp::Store, - clear_color: color, + clear_color: wgpu::Color::BLACK, } ], depth_stencil_attachment: None, }); - - let mut current_pipeline = String::new(); - + + // Prepare a variable to cache the pipeline name + let mut bound_pipeline = self.pipeline_cache.get("gui_rect").unwrap(); //nodes[0].get_pipeline(&self.pipeline_cache); + render_pass.set_pipeline(&bound_pipeline.render_pipeline); + // Turn the queue of pipelines each into a command buffer and submit it to the render queue - self.draw_command_queue.iter().for_each(|command| { - // Tell the GPU which pipeline to draw in this render pass - if current_pipeline != command.pipeline_name { - let pipeline = self.pipeline_cache.get(&command.pipeline_name).unwrap(); - render_pass.set_pipeline(&pipeline.render_pipeline); - current_pipeline = command.pipeline_name.clone(); + for i in 0..nodes.len() { + // let command = commands[i]; + // If the previously set pipeline can't be reused, send the GPU the new pipeline to draw with + let new_pipeline = self.pipeline_cache.get("gui_rect").unwrap(); //node.get_pipeline(&self.pipeline_cache); + if bound_pipeline.render_pipeline != new_pipeline.render_pipeline { + render_pass.set_pipeline(&new_pipeline.render_pipeline); + bound_pipeline = new_pipeline; } // Send the GPU the vertices and triangle indices - render_pass.set_vertex_buffer(0, &command.vertex_buffer, 0, 0); - render_pass.set_index_buffer(&command.index_buffer, 0, 0); + render_pass.set_vertex_buffer(0, &commands[i].vertex_buffer, 0, 0); + render_pass.set_index_buffer(&commands[i].index_buffer, 0, 0); + + // let bind_groups = nodes[i].build_bind_groups(&self.device, &mut self.queue, new_pipeline, &mut self.texture_cache); // Send the GPU the bind group resources - let bind_group = self.bind_group_cache.get(&command.bind_group_name).unwrap(); - render_pass.set_bind_group(0, bind_group, &[]); + for (index, bind_group) in bind_groups[i].iter().enumerate() { + render_pass.set_bind_group(index as u32, bind_group, &[]); + } // Draw call - render_pass.draw_indexed(0..command.index_count, 0, 0..1); - }); + render_pass.draw_indexed(0..commands[i].index_count, 0, 0..1); + }; // Done sending render pass commands so we can give up mutation rights to command_encoder drop(render_pass); @@ -264,9 +202,6 @@ impl Application { // Turn the recording of commands into a complete command buffer let command_buffer = command_encoder.finish(); - // After the draw command queue has been iterated through and used, empty it for use next frame - self.draw_command_queue.clear(); - // Submit the command buffer to the GPU command queue self.queue.submit(&[command_buffer]); } diff --git a/src/bind_group_resource.rs b/src/bind_group_resource.rs new file mode 100644 index 00000000..d134611e --- /dev/null +++ b/src/bind_group_resource.rs @@ -0,0 +1,13 @@ +pub enum BindGroupResource<'a> { + Owned(wgpu::BindGroup), + Borrowed(&'a wgpu::BindGroup), +} + +impl<'a> BindGroupResource<'a> { + pub fn borrow(&self) -> BindGroupResource { + match self { + BindGroupResource::Owned(ref bind_group) => BindGroupResource::Borrowed(bind_group), + BindGroupResource::Borrowed(ref bind_group) => BindGroupResource::Borrowed(bind_group), + } + } +} \ No newline at end of file diff --git a/src/color.rs b/src/color.rs new file mode 100644 index 00000000..55bef396 --- /dev/null +++ b/src/color.rs @@ -0,0 +1,77 @@ +#[repr(C, align(16))] +#[derive(Debug, Copy, Clone)] +pub struct Color { + pub r: f32, + pub g: f32, + pub b: f32, + pub a: f32, +} + +impl Color { + pub fn new(r: f32, g: f32, b: f32, a: f32) -> Self { + Self { r, g, b, a } + } + + pub const TRANSPARENT: Self = Color { + r: 0.0, + g: 0.0, + b: 0.0, + a: 0.0, + }; + + pub const BLACK: Self = Color { + r: 0.0, + g: 0.0, + b: 0.0, + a: 1.0, + }; + + pub const WHITE: Self = Color { + r: 1.0, + g: 1.0, + b: 1.0, + a: 1.0, + }; + + pub const RED: Self = Color { + r: 1.0, + g: 0.0, + b: 0.0, + a: 1.0, + }; + + pub const YELLOW: Self = Color { + r: 1.0, + g: 1.0, + b: 0.0, + a: 1.0, + }; + + pub const GREEN: Self = Color { + r: 0.0, + g: 1.0, + b: 0.0, + a: 1.0, + }; + + pub const CYAN: Self = Color { + r: 0.0, + g: 1.0, + b: 1.0, + a: 1.0, + }; + + pub const BLUE: Self = Color { + r: 0.0, + g: 0.0, + b: 1.0, + a: 1.0, + }; + + pub const MAGENTA: Self = Color { + r: 1.0, + g: 0.0, + b: 1.0, + a: 1.0, + }; +} \ No newline at end of file diff --git a/src/color_palette.rs b/src/color_palette.rs index bf4f8e63..1462bdd8 100644 --- a/src/color_palette.rs +++ b/src/color_palette.rs @@ -1,3 +1,5 @@ +use crate::color::Color; + #[allow(dead_code)] pub enum ColorPalette { Black, @@ -20,7 +22,7 @@ pub enum ColorPalette { } impl ColorPalette { - pub fn get_color(self) -> wgpu::Color { + pub fn get_color_srgb(self) -> Color { let grayscale = match self { ColorPalette::Black => 0 * 17, // #000000 ColorPalette::NearBlack => 1 * 17, // #111111 @@ -42,8 +44,8 @@ impl ColorPalette { }; if grayscale > -1 { - let value = grayscale as f64 / 255.0; - return wgpu::Color { r: value, g: value, b: value, a: 1.0 }; + let value = grayscale as f32 / 255.0; + return Color::new(value, value, value, 1.0); } let rgba = match self { @@ -51,19 +53,14 @@ impl ColorPalette { _ => (0, 0, 0, 255), // Unimplemented returns black }; - wgpu::Color { - r: rgba.0 as f64 / 255.0, - g: rgba.1 as f64 / 255.0, - b: rgba.2 as f64 / 255.0, - a: rgba.3 as f64 / 255.0 - } + Color::new(rgba.0 as f32 / 255.0, rgba.1 as f32 / 255.0, rgba.2 as f32 / 255.0, rgba.3 as f32 / 255.0) } - pub fn get_color_linear(self) -> wgpu::Color { - let standard_rgb = ColorPalette::get_color(self); + pub fn get_color_linear(self) -> Color { + let standard_rgb = ColorPalette::get_color_srgb(self); let linear = palette::Srgb::new(standard_rgb.r, standard_rgb.g, standard_rgb.b).into_linear(); - wgpu::Color { r: linear.red, g: linear.green, b: linear.blue, a: standard_rgb.a } + Color::new(linear.red, linear.green, linear.blue, standard_rgb.a) } } \ No newline at end of file diff --git a/src/draw_command.rs b/src/draw_command.rs index c55cfda6..320fef13 100644 --- a/src/draw_command.rs +++ b/src/draw_command.rs @@ -1,20 +1,18 @@ +// use crate::bind_group_resource::BindGroupResource; + pub struct DrawCommand { - pub pipeline_name: String, - pub bind_group_name: String, pub vertex_buffer: wgpu::Buffer, pub index_buffer: wgpu::Buffer, pub index_count: u32, } impl DrawCommand { - pub fn new(device: &wgpu::Device, pipeline_name: &str, bind_group_name: &str, vertices: &[[f32; 2]], indices: &[u16]) -> Self { + pub fn new(device: &wgpu::Device, vertices: &[[f32; 2]], indices: &[u16]) -> Self { let vertex_buffer = device.create_buffer_with_data(bytemuck::cast_slice(vertices), wgpu::BufferUsage::VERTEX); let index_buffer = device.create_buffer_with_data(bytemuck::cast_slice(indices), wgpu::BufferUsage::INDEX); let index_count = indices.len() as u32; Self { - pipeline_name: String::from(pipeline_name), - bind_group_name: String::from(bind_group_name), vertex_buffer, index_buffer, index_count, diff --git a/src/gui_attributes.rs b/src/gui_attributes.rs new file mode 100644 index 00000000..f211a31e --- /dev/null +++ b/src/gui_attributes.rs @@ -0,0 +1,42 @@ +#[repr(C, align(16))] +#[derive(Debug, Copy, Clone)] +pub struct Corners { + pub top_left: T, + pub top_right: T, + pub bottom_right: T, + pub bottom_left: T, +} + +impl Corners { + pub fn new(top_left: T, top_right: T, bottom_right: T, bottom_left: T) -> Self { + Self { top_left, top_right, bottom_right, bottom_left } + } +} + +#[repr(C, align(16))] +#[derive(Debug, Copy, Clone)] +pub struct Sides { + pub top: T, + pub right: T, + pub bottom: T, + pub left: T, +} + +impl Sides { + pub fn new(top: T, right: T, bottom: T, left: T) -> Self { + Self { top, right, bottom, left } + } +} + +#[repr(C, align(16))] +#[derive(Debug, Copy, Clone)] +pub struct Dimensions { + pub width: T, + pub height: T, +} + +impl Dimensions { + pub fn new(width: T, height: T) -> Self { + Self { width, height } + } +} diff --git a/src/gui_node.rs b/src/gui_node.rs new file mode 100644 index 00000000..df61ca46 --- /dev/null +++ b/src/gui_node.rs @@ -0,0 +1,83 @@ +use crate::resource_cache::ResourceCache; +use crate::draw_command::DrawCommand; +use crate::color::Color; +use crate::texture::Texture; +use crate::pipeline::Pipeline; +use crate::gui_attributes::*; + +pub struct GuiNode { + pub form_factor: GuiNodeUniform, +} + +impl GuiNode { + pub fn new(width: u32, height: u32, color: Color) -> Self { + Self { + form_factor: GuiNodeUniform::new(width, height, color), + } + } + + // pub fn get_pipeline(&self, pipeline_cache: &ResourceCache) -> &Pipeline { + // pipeline_cache.get("gui_rect").unwrap() + // } + + pub fn build_draw_command(&mut self, device: &wgpu::Device) -> DrawCommand { + const VERTICES: &[[f32; 2]] = &[ + [-0.5, 0.5], + [0.5, 0.5], + [0.5, 1.0], + [-0.5, 1.0], + ]; + const INDICES: &[u16] = &[ + 0, 1, 2, + 0, 2, 3, + ]; + + // Create a draw command with the vertex data then push it to the GPU command queue + DrawCommand::new(device, VERTICES, INDICES) + } + + pub fn build_bind_groups(&mut self, device: &wgpu::Device, queue: &mut wgpu::Queue, pipeline: &Pipeline, texture_cache: &mut ResourceCache) -> Vec { + // Load the cached texture + let texture = Texture::cached_load(device, queue, "textures/grid.png", texture_cache); + + // Build a staging buffer from the uniform resource data + let binding_staging_buffer = Pipeline::build_binding_staging_buffer(device, self.form_factor); + + // Construct the bind group for this GUI node + let bind_group = Pipeline::build_bind_group(device, &pipeline.bind_group_layout, vec![ + Pipeline::build_binding_resource(&binding_staging_buffer), + wgpu::BindingResource::TextureView(&texture.texture_view), + ]); + + vec![ + bind_group, + ] + } +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct GuiNodeUniform { + pub dimensions: Dimensions, + pub corners_radius: Corners, + pub sides_inset: Sides, + pub border_thickness: f32, + pub border_color: Color, + pub fill_color: Color, +} + +impl GuiNodeUniform { + pub fn new(width: u32, height: u32, color: Color) -> Self { + GuiNodeUniform { + dimensions: Dimensions::::new(width, height), + corners_radius: Corners::::new(0.0, 0.0, 0.0, 0.0), + sides_inset: Sides::::new(0.0, 0.0, 0.0, 0.0), + border_thickness: 0.0, + border_color: Color::TRANSPARENT, + fill_color: color, + } + } +} + +unsafe impl bytemuck::Zeroable for GuiNodeUniform {} +unsafe impl bytemuck::Pod for GuiNodeUniform {} diff --git a/src/gui_rect.rs b/src/gui_rect.rs deleted file mode 100644 index 750dbd60..00000000 --- a/src/gui_rect.rs +++ /dev/null @@ -1,23 +0,0 @@ -pub struct GuiRect { - pub corners: Corners<(f32, f32)>, - pub corners_radius: Corners, - pub sides_inset: Sides, - pub border: f32, - pub border_color: wgpu::Color, - pub fill_color: wgpu::Color, - pub fill_texture: Option, -} - -pub struct Corners { - pub top_left: T, - pub top_right: T, - pub bottom_right: T, - pub bottom_left: T, -} - -pub struct Sides { - pub top: T, - pub right: T, - pub bottom: T, - pub left: T, -} diff --git a/src/gui_tree.rs b/src/gui_tree.rs deleted file mode 100644 index 1da05313..00000000 --- a/src/gui_tree.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub struct GuiTree { - -} - -impl GuiTree { - pub fn new() -> Self { - Self {} - } -} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 417df370..e9f80d4c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,16 @@ mod application; -mod gui_rect; mod pipeline; mod texture; +mod color; mod color_palette; mod resource_cache; mod shader_stage; mod draw_command; -mod gui_tree; +mod gui_node; +mod gui_attributes; mod window_events; +mod window_uniform; +mod bind_group_resource; use application::Application; use winit::event_loop::EventLoop; diff --git a/src/pipeline.rs b/src/pipeline.rs index 5c7c844e..57686979 100644 --- a/src/pipeline.rs +++ b/src/pipeline.rs @@ -1,4 +1,6 @@ use std::mem; +use crate::resource_cache::ResourceCache; +use crate::shader_stage; pub struct Pipeline { pub bind_group_layout: wgpu::BindGroupLayout, @@ -6,23 +8,107 @@ pub struct Pipeline { } impl Pipeline { - pub fn new(device: &wgpu::Device, vertex_shader: &wgpu::ShaderModule, fragment_shader: &wgpu::ShaderModule, bind_group_layout_binding_types: Vec) -> Self { - let bind_group_layout_entries = bind_group_layout_binding_types.into_iter().enumerate().map(|(index, binding_type)| - wgpu::BindGroupLayoutEntry { + pub fn new(device: &wgpu::Device, swap_chain_color_format: wgpu::TextureFormat, extra_layouts: Vec<&wgpu::BindGroupLayout>, shader_cache: &mut ResourceCache, shader_pair_path: (&str, &str)) -> Self { + // Load the vertex and fragment shaders + let shader_pair = Pipeline::get_shader_pair(device, shader_cache, shader_pair_path); + + // Prepare a bind group layout for the GUI element's texture and form factor data + let bind_group_layout = Pipeline::build_bind_group_layout(device, &vec![ + wgpu::BindingType::UniformBuffer { dynamic: false }, + wgpu::BindingType::SampledTexture { + dimension: wgpu::TextureViewDimension::D2, + component_type: wgpu::TextureComponentType::Float, + multisampled: false, + }, + ]); + + // Combine all bind group layouts + let mut bind_group_layouts = vec![&bind_group_layout]; + bind_group_layouts.append(&mut extra_layouts.clone()); + + // Construct the pipeline + let render_pipeline = Pipeline::build_pipeline(device, swap_chain_color_format, bind_group_layouts, shader_pair); + Self { + bind_group_layout, + render_pipeline, + } + } + + pub fn get_shader_pair<'a>(device: &wgpu::Device, shader_cache: &'a mut ResourceCache, shader_pair_path: (&str, &str)) -> (&'a wgpu::ShaderModule, &'a wgpu::ShaderModule) { + // If uncached, construct a vertex shader loaded from its source code file + if shader_cache.get(shader_pair_path.0).is_none() { + let vertex_shader_module = shader_stage::compile_from_glsl(device, shader_pair_path.0, glsl_to_spirv::ShaderType::Vertex).unwrap(); + shader_cache.set(shader_pair_path.0, vertex_shader_module); + } + + // If uncached, construct a fragment shader loaded from its source code file + if shader_cache.get(shader_pair_path.1).is_none() { + let fragment_shader_module = shader_stage::compile_from_glsl(&device, shader_pair_path.1, glsl_to_spirv::ShaderType::Fragment).unwrap(); + shader_cache.set(shader_pair_path.1, fragment_shader_module); + } + + // Get the shader pair + let vertex_shader = shader_cache.get(shader_pair_path.0).unwrap(); + let fragment_shader = shader_cache.get(shader_pair_path.1).unwrap(); + + (vertex_shader, fragment_shader) + } + + pub fn build_bind_group_layouts(device: &wgpu::Device, bind_group_layouts: &Vec>) -> Vec { + bind_group_layouts.into_iter().map(|layout_entry| Self::build_bind_group_layout(device, layout_entry)).collect::>() + } + + pub fn build_bind_group_layout(device: &wgpu::Device, bind_group_layout: &Vec) -> wgpu::BindGroupLayout { + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: None, + bindings: bind_group_layout.into_iter().enumerate().map(|(index, binding_type)| + wgpu::BindGroupLayoutEntry { + binding: index as u32, + visibility: wgpu::ShaderStage::all(), + ty: binding_type.clone(), + } + ).collect::>().as_slice(), + }) + } + + pub fn build_binding_staging_buffer(device: &wgpu::Device, resource: T) -> wgpu::Buffer { // TODO: Turn this into a borrow + // Construct a staging buffer with the binary uniform struct data + device.create_buffer_with_data( + bytemuck::cast_slice(&[resource]), + wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, + ) + } + + pub fn build_binding_resource(resource_buffer: &wgpu::Buffer) -> wgpu::BindingResource { + // Return the buffer as a binding resource + wgpu::BindingResource::Buffer { + buffer: resource_buffer, + range: 0..std::mem::size_of_val(resource_buffer) as wgpu::BufferAddress, + } + } + + pub fn build_bind_group(device: &wgpu::Device, bind_group_layout: &wgpu::BindGroupLayout, binding_resources: Vec) -> wgpu::BindGroup { + let bindings = binding_resources.into_iter().enumerate().map(|(index, binding_resource)| + wgpu::Binding { binding: index as u32, - visibility: wgpu::ShaderStage::all(), - ty: binding_type, + resource: binding_resource, } ).collect::>(); - let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - bindings: bind_group_layout_entries.as_slice(), - label: None, - }); + device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: bind_group_layout, + bindings: bindings.as_slice(), + label: None, + }) + } + + pub fn build_pipeline(device: &wgpu::Device, swap_chain_color_format: wgpu::TextureFormat, bind_group_layouts: Vec<&wgpu::BindGroupLayout>, shader_pair: (&wgpu::ShaderModule, &wgpu::ShaderModule)) -> wgpu::RenderPipeline { let render_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - bind_group_layouts: &[&bind_group_layout], + bind_group_layouts: bind_group_layouts.as_slice(), }); - let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + + let (vertex_shader, fragment_shader) = shader_pair; + device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { layout: &render_pipeline_layout, vertex_stage: wgpu::ProgrammableStageDescriptor { module: vertex_shader, @@ -41,7 +127,7 @@ impl Pipeline { }), primitive_topology: wgpu::PrimitiveTopology::TriangleList, color_states: &[wgpu::ColorStateDescriptor { - format: wgpu::TextureFormat::Bgra8UnormSrgb, // TODO: Make this match Application.swap_chain_descriptor + format: swap_chain_color_format, color_blend: wgpu::BlendDescriptor::REPLACE, alpha_blend: wgpu::BlendDescriptor::REPLACE, write_mask: wgpu::ColorWrite::ALL, @@ -62,25 +148,6 @@ impl Pipeline { sample_count: 1, sample_mask: !0, alpha_to_coverage_enabled: false, - }); - - Self { - bind_group_layout, - render_pipeline, - } - } - - pub fn build_bind_group(&self, device: &wgpu::Device, binding_resources: Vec) -> wgpu::BindGroup { - let bindings = binding_resources.into_iter().enumerate().map(|(index, binding_resource)| - wgpu::Binding { - binding: index as u32, - resource: binding_resource, - } - ).collect::>(); - device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: &self.bind_group_layout, - bindings: bindings.as_slice(), - label: None, }) } } diff --git a/src/texture.rs b/src/texture.rs index f574b7bb..49213f59 100644 --- a/src/texture.rs +++ b/src/texture.rs @@ -1,5 +1,6 @@ use std::fs; use image::GenericImageView; +use crate::resource_cache::ResourceCache; pub struct Texture { pub texture: wgpu::Texture, @@ -8,6 +9,15 @@ pub struct Texture { } impl Texture { + pub fn cached_load<'a>(device: &wgpu::Device, queue: &mut wgpu::Queue, path: &str, texture_cache: &'a mut ResourceCache) -> &'a Texture { + // If uncached, construct a texture loaded from the image file + if texture_cache.get(path).is_none() { + let texture = Texture::from_filepath(device, queue, path).unwrap(); + texture_cache.set(path, texture); + } + texture_cache.get(path).unwrap() + } + pub fn from_filepath(device: &wgpu::Device, queue: &mut wgpu::Queue, path: &str) -> Result { // Read the raw bytes from the specified file let bytes = fs::read(path)?; diff --git a/src/window_events.rs b/src/window_events.rs index 800ebb79..90d67a18 100644 --- a/src/window_events.rs +++ b/src/window_events.rs @@ -1,4 +1,4 @@ -use super::application::Application; +use crate::application::Application; use winit::event::*; use winit::event_loop::ControlFlow; @@ -30,7 +30,20 @@ pub fn window_event(application: &mut Application, control_flow: &mut ControlFlo fn keyboard_event(application: &mut Application, control_flow: &mut ControlFlow, input: &KeyboardInput) { match input { KeyboardInput { state: ElementState::Pressed, virtual_keycode: Some(VirtualKeyCode::Escape), .. } => quit(control_flow), - KeyboardInput { state: ElementState::Pressed, virtual_keycode: Some(VirtualKeyCode::Space), .. } => application.example(), + KeyboardInput { state: ElementState::Pressed, virtual_keycode: Some(VirtualKeyCode::Space), .. } => { + // const VERTICES: &[[f32; 2]] = &[ + // [-0.2, 0.0], + // [0.2, 0.0], + // [0.2, -0.5], + // [-0.2, -0.5], + // ]; + // const INDICES: &[u16] = &[ + // 0, 1, 2, + // 0, 2, 3, + // ]; + + // application.example(VERTICES, INDICES); + }, _ => *control_flow = ControlFlow::Wait, } } diff --git a/src/window_uniform.rs b/src/window_uniform.rs new file mode 100644 index 00000000..69c3cc11 --- /dev/null +++ b/src/window_uniform.rs @@ -0,0 +1,18 @@ +use crate::gui_attributes::*; + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct WindowUniform { + pub dimensions: Dimensions, +} + +impl WindowUniform { + pub fn new(width: u32, height: u32) -> Self { + Self { + dimensions: Dimensions::new(width, height), + } + } +} + +unsafe impl bytemuck::Zeroable for WindowUniform {} +unsafe impl bytemuck::Pod for WindowUniform {}