diff --git a/Cargo.lock b/Cargo.lock index 6f6953e..0d3e397 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -77,6 +77,15 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anstream" version = "0.6.21" @@ -209,6 +218,21 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + [[package]] name = "bitflags" version = "1.3.2" @@ -552,6 +576,17 @@ dependencies = [ "objc", ] +[[package]] +name = "codespan-reporting" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81" +dependencies = [ + "serde", + "termcolor", + "unicode-width", +] + [[package]] name = "colorchoice" version = "1.0.4" @@ -971,6 +1006,24 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "foreign-types" version = "0.5.0" @@ -1359,6 +1412,57 @@ dependencies = [ "regex-syntax", ] +[[package]] +name = "gpu-alloc" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" +dependencies = [ + "bitflags 2.10.0", + "gpu-alloc-types", +] + +[[package]] +name = "gpu-alloc-types" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" +dependencies = [ + "bitflags 2.10.0", +] + +[[package]] +name = "gpu-descriptor" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" +dependencies = [ + "bitflags 2.10.0", + "gpu-descriptor-types", + "hashbrown 0.15.5", +] + +[[package]] +name = "gpu-descriptor-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" +dependencies = [ + "bitflags 2.10.0", +] + +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "num-traits", + "zerocopy", +] + [[package]] name = "hash32" version = "0.3.1" @@ -1373,12 +1477,18 @@ name = "hashbrown" version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash 0.1.5", +] [[package]] name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "foldhash 0.2.0", +] [[package]] name = "heapless" @@ -1402,6 +1512,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" +[[package]] +name = "hexf-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" + [[package]] name = "home" version = "0.5.12" @@ -1928,8 +2044,11 @@ dependencies = [ "ash-window", "bytemuck", "cargo-gpu", + "env_logger", "mygraphics-shaders", + "pollster", "raw-window-handle", + "wgpu", "winit", ] @@ -1942,6 +2061,33 @@ dependencies = [ "spirv-std", ] +[[package]] +name = "naga" +version = "27.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "066cf25f0e8b11ee0df221219010f213ad429855f57c494f995590c861a9a7d8" +dependencies = [ + "arrayvec", + "bit-set", + "bitflags 2.10.0", + "cfg-if", + "cfg_aliases", + "codespan-reporting", + "half", + "hashbrown 0.16.1", + "hexf-parse", + "indexmap", + "libm", + "log", + "num-traits", + "once_cell", + "petgraph", + "rustc-hash", + "spirv", + "thiserror 2.0.17", + "unicode-ident", +] + [[package]] name = "names" version = "0.14.0" @@ -2333,6 +2479,15 @@ dependencies = [ "num-traits", ] +[[package]] +name = "ordered-float" +version = "5.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4779c6901a562440c3786d08192c6fbda7c1c2060edd10006b05ee35d10f2d" +dependencies = [ + "num-traits", +] + [[package]] name = "owned_ttf_parser" version = "0.25.1" @@ -2420,6 +2575,17 @@ dependencies = [ "sha2", ] +[[package]] +name = "petgraph" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" +dependencies = [ + "fixedbitset", + "hashbrown 0.15.5", + "indexmap", +] + [[package]] name = "pin-project" version = "1.1.10" @@ -2466,6 +2632,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "pollster" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3" + [[package]] name = "portable-atomic" version = "1.11.1" @@ -2532,6 +2704,12 @@ dependencies = [ "parking_lot", ] +[[package]] +name = "profiling" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" + [[package]] name = "quick-xml" version = "0.37.5" @@ -2691,6 +2869,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "renderdoc-sys" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" + [[package]] name = "rhai" version = "1.23.6" @@ -2880,7 +3064,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" dependencies = [ - "ordered-float", + "ordered-float 2.10.1", "serde", ] @@ -3182,6 +3366,15 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + [[package]] name = "terminal-prompt" version = "0.2.3" @@ -3763,6 +3956,127 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "wgpu" +version = "27.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfe68bac7cde125de7a731c3400723cadaaf1703795ad3f4805f187459cd7a77" +dependencies = [ + "arrayvec", + "bitflags 2.10.0", + "cfg-if", + "cfg_aliases", + "document-features", + "hashbrown 0.16.1", + "log", + "naga", + "parking_lot", + "portable-atomic", + "profiling", + "raw-window-handle", + "smallvec", + "static_assertions", + "wgpu-core", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-core" +version = "27.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27a75de515543b1897b26119f93731b385a19aea165a1ec5f0e3acecc229cae7" +dependencies = [ + "arrayvec", + "bit-set", + "bit-vec", + "bitflags 2.10.0", + "bytemuck", + "cfg_aliases", + "document-features", + "hashbrown 0.16.1", + "indexmap", + "log", + "naga", + "once_cell", + "parking_lot", + "portable-atomic", + "profiling", + "raw-window-handle", + "rustc-hash", + "smallvec", + "thiserror 2.0.17", + "wgpu-core-deps-apple", + "wgpu-core-deps-windows-linux-android", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-core-deps-apple" +version = "27.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0772ae958e9be0c729561d5e3fd9a19679bcdfb945b8b1a1969d9bfe8056d233" +dependencies = [ + "wgpu-hal", +] + +[[package]] +name = "wgpu-core-deps-windows-linux-android" +version = "27.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71197027d61a71748e4120f05a9242b2ad142e3c01f8c1b47707945a879a03c3" +dependencies = [ + "wgpu-hal", +] + +[[package]] +name = "wgpu-hal" +version = "27.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b21cb61c57ee198bc4aff71aeadff4cbb80b927beb912506af9c780d64313ce" +dependencies = [ + "android_system_properties", + "arrayvec", + "ash", + "bitflags 2.10.0", + "bytemuck", + "cfg-if", + "cfg_aliases", + "gpu-alloc", + "gpu-descriptor", + "hashbrown 0.16.1", + "libc", + "libloading", + "log", + "naga", + "ordered-float 5.1.0", + "parking_lot", + "portable-atomic", + "portable-atomic-util", + "profiling", + "raw-window-handle", + "renderdoc-sys", + "smallvec", + "thiserror 2.0.17", + "wgpu-types", + "windows", +] + +[[package]] +name = "wgpu-types" +version = "27.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afdcf84c395990db737f2dd91628706cb31e86d72e53482320d368e52b5da5eb" +dependencies = [ + "bitflags 2.10.0", + "bytemuck", + "js-sys", + "log", + "thiserror 2.0.17", + "web-sys", +] + [[package]] name = "winapi" version = "0.3.9" @@ -3794,12 +4108,76 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +dependencies = [ + "windows-core", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-implement" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.45.0" diff --git a/Cargo.toml b/Cargo.toml index 4866335..bb3189d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ unexpected_cfgs = { level = "allow", check-cfg = ['cfg(target_arch, values("spir ash = "0.38" ash-window = "0.13" wgpu = { version = "27.0.1", default-features = false, features = ["std", "parking_lot", "vulkan", "vulkan-portability", "spirv", "wgsl"] } +pollster = "0.4.0" # rust-gpu cargo-gpu = { git = "https://github.com/Rust-GPU/cargo-gpu", rev = "bf24eb6060e0c7b0013eceddd23b5d7cee68f4cc" } @@ -31,5 +32,5 @@ glam = { version = "0.30.9", default-features = false } bytemuck = { version = "1.24.0", features = ["derive"] } raw-window-handle = "0.6.2" winit = "0.30.0" -cfg-if = "1.0.0" +env_logger = "0.11.8" anyhow = "1.0.98" diff --git a/generated/graphics/cargo-gpu/Cargo.toml b/generated/graphics/ash/cargo-gpu/Cargo.toml similarity index 94% rename from generated/graphics/cargo-gpu/Cargo.toml rename to generated/graphics/ash/cargo-gpu/Cargo.toml index f28b950..338ec1f 100644 --- a/generated/graphics/cargo-gpu/Cargo.toml +++ b/generated/graphics/ash/cargo-gpu/Cargo.toml @@ -16,15 +16,19 @@ repository = "" unexpected_cfgs = { level = "allow", check-cfg = ['cfg(target_arch, values("spirv"))'] } [workspace.dependencies] +# API +ash = "0.38" +ash-window = "0.13" + +# rust-gpu cargo-gpu = { git = "https://github.com/Rust-GPU/cargo-gpu", rev = "bf24eb6060e0c7b0013eceddd23b5d7cee68f4cc" } spirv-std = { git = "https://github.com/Rust-GPU/rust-gpu", rev = "6fb875068d0d35b1a81ae89b73cf7a464f8c60f7" } +# other glam = { version = "0.30.9", default-features = false } bytemuck = { version = "1.24.0", features = ["derive"] } -ash = "0.38" -ash-window = "0.13" raw-window-handle = "0.6.2" winit = "0.30.0" -cfg-if = "1.0.0" +env_logger = "0.11.8" anyhow = "1.0.98" diff --git a/generated/graphics/cargo-gpu/mygraphics-shaders/Cargo.toml b/generated/graphics/ash/cargo-gpu/mygraphics-shaders/Cargo.toml similarity index 100% rename from generated/graphics/cargo-gpu/mygraphics-shaders/Cargo.toml rename to generated/graphics/ash/cargo-gpu/mygraphics-shaders/Cargo.toml diff --git a/generated/graphics/cargo-gpu/mygraphics-shaders/src/lib.rs b/generated/graphics/ash/cargo-gpu/mygraphics-shaders/src/lib.rs similarity index 100% rename from generated/graphics/cargo-gpu/mygraphics-shaders/src/lib.rs rename to generated/graphics/ash/cargo-gpu/mygraphics-shaders/src/lib.rs diff --git a/generated/graphics/cargo-gpu/mygraphics/Cargo.toml b/generated/graphics/ash/cargo-gpu/mygraphics/Cargo.toml similarity index 90% rename from generated/graphics/cargo-gpu/mygraphics/Cargo.toml rename to generated/graphics/ash/cargo-gpu/mygraphics/Cargo.toml index 35b36ee..38d9e61 100644 --- a/generated/graphics/cargo-gpu/mygraphics/Cargo.toml +++ b/generated/graphics/ash/cargo-gpu/mygraphics/Cargo.toml @@ -11,15 +11,22 @@ repository.workspace = true workspace = true [dependencies] +# shader crate mygraphics-shaders = { path = "../mygraphics-shaders" } +# API ash.workspace = true ash-window.workspace = true + +# other raw-window-handle.workspace = true winit.workspace = true anyhow.workspace = true bytemuck.workspace = true [build-dependencies] +# rust-gpu cargo-gpu.workspace = true + +# other anyhow.workspace = true diff --git a/generated/graphics/cargo-gpu/mygraphics/build.rs b/generated/graphics/ash/cargo-gpu/mygraphics/build.rs similarity index 100% rename from generated/graphics/cargo-gpu/mygraphics/build.rs rename to generated/graphics/ash/cargo-gpu/mygraphics/build.rs diff --git a/generated/graphics/cargo-gpu/mygraphics/src/ash_renderer/device.rs b/generated/graphics/ash/cargo-gpu/mygraphics/src/ash_renderer/device.rs similarity index 100% rename from generated/graphics/cargo-gpu/mygraphics/src/ash_renderer/device.rs rename to generated/graphics/ash/cargo-gpu/mygraphics/src/ash_renderer/device.rs diff --git a/generated/graphics/cargo-gpu/mygraphics/src/ash_renderer/graphics.rs b/generated/graphics/ash/cargo-gpu/mygraphics/src/ash_renderer/graphics.rs similarity index 100% rename from generated/graphics/cargo-gpu/mygraphics/src/ash_renderer/graphics.rs rename to generated/graphics/ash/cargo-gpu/mygraphics/src/ash_renderer/graphics.rs diff --git a/generated/graphics/cargo-gpu/mygraphics/src/ash_renderer/mod.rs b/generated/graphics/ash/cargo-gpu/mygraphics/src/ash_renderer/mod.rs similarity index 100% rename from generated/graphics/cargo-gpu/mygraphics/src/ash_renderer/mod.rs rename to generated/graphics/ash/cargo-gpu/mygraphics/src/ash_renderer/mod.rs diff --git a/generated/graphics/cargo-gpu/mygraphics/src/ash_renderer/single_command_buffer.rs b/generated/graphics/ash/cargo-gpu/mygraphics/src/ash_renderer/single_command_buffer.rs similarity index 100% rename from generated/graphics/cargo-gpu/mygraphics/src/ash_renderer/single_command_buffer.rs rename to generated/graphics/ash/cargo-gpu/mygraphics/src/ash_renderer/single_command_buffer.rs diff --git a/generated/graphics/cargo-gpu/mygraphics/src/ash_renderer/swapchain.rs b/generated/graphics/ash/cargo-gpu/mygraphics/src/ash_renderer/swapchain.rs similarity index 100% rename from generated/graphics/cargo-gpu/mygraphics/src/ash_renderer/swapchain.rs rename to generated/graphics/ash/cargo-gpu/mygraphics/src/ash_renderer/swapchain.rs diff --git a/generated/graphics/cargo-gpu/mygraphics/src/lib.rs b/generated/graphics/ash/cargo-gpu/mygraphics/src/lib.rs similarity index 100% rename from generated/graphics/cargo-gpu/mygraphics/src/lib.rs rename to generated/graphics/ash/cargo-gpu/mygraphics/src/lib.rs diff --git a/generated/graphics/cargo-gpu/mygraphics/src/main.rs b/generated/graphics/ash/cargo-gpu/mygraphics/src/main.rs similarity index 100% rename from generated/graphics/cargo-gpu/mygraphics/src/main.rs rename to generated/graphics/ash/cargo-gpu/mygraphics/src/main.rs diff --git a/generated/graphics/cargo-gpu/mygraphics/src/util.rs b/generated/graphics/ash/cargo-gpu/mygraphics/src/util.rs similarity index 100% rename from generated/graphics/cargo-gpu/mygraphics/src/util.rs rename to generated/graphics/ash/cargo-gpu/mygraphics/src/util.rs diff --git a/generated/graphics/spirv-builder/Cargo.toml b/generated/graphics/ash/spirv-builder/Cargo.toml similarity index 97% rename from generated/graphics/spirv-builder/Cargo.toml rename to generated/graphics/ash/spirv-builder/Cargo.toml index 8cda13c..1944c29 100644 --- a/generated/graphics/spirv-builder/Cargo.toml +++ b/generated/graphics/ash/spirv-builder/Cargo.toml @@ -16,17 +16,21 @@ repository = "" unexpected_cfgs = { level = "allow", check-cfg = ['cfg(target_arch, values("spirv"))'] } [workspace.dependencies] +# API +ash = "0.38" +ash-window = "0.13" + +# rust-gpu # The version of the dependencies `spirv-builder` and `spirv-std` must match exactly! spirv-builder = { git = "https://github.com/Rust-GPU/rust-gpu", rev = "6fb875068d0d35b1a81ae89b73cf7a464f8c60f7" } spirv-std = { git = "https://github.com/Rust-GPU/rust-gpu", rev = "6fb875068d0d35b1a81ae89b73cf7a464f8c60f7" } +# other glam = { version = "0.30.9", default-features = false } bytemuck = { version = "1.24.0", features = ["derive"] } -ash = "0.38" -ash-window = "0.13" raw-window-handle = "0.6.2" winit = "0.30.0" -cfg-if = "1.0.0" +env_logger = "0.11.8" anyhow = "1.0.98" # Optimize build scripts, copied from rust-gpu's repo diff --git a/generated/graphics/spirv-builder/mygraphics-shaders/Cargo.toml b/generated/graphics/ash/spirv-builder/mygraphics-shaders/Cargo.toml similarity index 100% rename from generated/graphics/spirv-builder/mygraphics-shaders/Cargo.toml rename to generated/graphics/ash/spirv-builder/mygraphics-shaders/Cargo.toml diff --git a/generated/graphics/spirv-builder/mygraphics-shaders/src/lib.rs b/generated/graphics/ash/spirv-builder/mygraphics-shaders/src/lib.rs similarity index 100% rename from generated/graphics/spirv-builder/mygraphics-shaders/src/lib.rs rename to generated/graphics/ash/spirv-builder/mygraphics-shaders/src/lib.rs diff --git a/generated/graphics/spirv-builder/mygraphics/Cargo.toml b/generated/graphics/ash/spirv-builder/mygraphics/Cargo.toml similarity index 93% rename from generated/graphics/spirv-builder/mygraphics/Cargo.toml rename to generated/graphics/ash/spirv-builder/mygraphics/Cargo.toml index 972e8a8..55ed561 100644 --- a/generated/graphics/spirv-builder/mygraphics/Cargo.toml +++ b/generated/graphics/ash/spirv-builder/mygraphics/Cargo.toml @@ -15,15 +15,22 @@ default = ["use-compiled-tools"] use-installed-tools = ["spirv-builder/use-installed-tools"] use-compiled-tools = ["spirv-builder/use-compiled-tools"] [dependencies] +# shader crate mygraphics-shaders = { path = "../mygraphics-shaders" } +# API ash.workspace = true ash-window.workspace = true + +# other raw-window-handle.workspace = true winit.workspace = true anyhow.workspace = true bytemuck.workspace = true [build-dependencies] +# rust-gpu spirv-builder.workspace = true + +# other anyhow.workspace = true diff --git a/generated/graphics/spirv-builder/mygraphics/build.rs b/generated/graphics/ash/spirv-builder/mygraphics/build.rs similarity index 100% rename from generated/graphics/spirv-builder/mygraphics/build.rs rename to generated/graphics/ash/spirv-builder/mygraphics/build.rs diff --git a/generated/graphics/spirv-builder/mygraphics/src/ash_renderer/device.rs b/generated/graphics/ash/spirv-builder/mygraphics/src/ash_renderer/device.rs similarity index 100% rename from generated/graphics/spirv-builder/mygraphics/src/ash_renderer/device.rs rename to generated/graphics/ash/spirv-builder/mygraphics/src/ash_renderer/device.rs diff --git a/generated/graphics/spirv-builder/mygraphics/src/ash_renderer/graphics.rs b/generated/graphics/ash/spirv-builder/mygraphics/src/ash_renderer/graphics.rs similarity index 100% rename from generated/graphics/spirv-builder/mygraphics/src/ash_renderer/graphics.rs rename to generated/graphics/ash/spirv-builder/mygraphics/src/ash_renderer/graphics.rs diff --git a/generated/graphics/spirv-builder/mygraphics/src/ash_renderer/mod.rs b/generated/graphics/ash/spirv-builder/mygraphics/src/ash_renderer/mod.rs similarity index 100% rename from generated/graphics/spirv-builder/mygraphics/src/ash_renderer/mod.rs rename to generated/graphics/ash/spirv-builder/mygraphics/src/ash_renderer/mod.rs diff --git a/generated/graphics/spirv-builder/mygraphics/src/ash_renderer/single_command_buffer.rs b/generated/graphics/ash/spirv-builder/mygraphics/src/ash_renderer/single_command_buffer.rs similarity index 100% rename from generated/graphics/spirv-builder/mygraphics/src/ash_renderer/single_command_buffer.rs rename to generated/graphics/ash/spirv-builder/mygraphics/src/ash_renderer/single_command_buffer.rs diff --git a/generated/graphics/spirv-builder/mygraphics/src/ash_renderer/swapchain.rs b/generated/graphics/ash/spirv-builder/mygraphics/src/ash_renderer/swapchain.rs similarity index 100% rename from generated/graphics/spirv-builder/mygraphics/src/ash_renderer/swapchain.rs rename to generated/graphics/ash/spirv-builder/mygraphics/src/ash_renderer/swapchain.rs diff --git a/generated/graphics/spirv-builder/mygraphics/src/lib.rs b/generated/graphics/ash/spirv-builder/mygraphics/src/lib.rs similarity index 100% rename from generated/graphics/spirv-builder/mygraphics/src/lib.rs rename to generated/graphics/ash/spirv-builder/mygraphics/src/lib.rs diff --git a/generated/graphics/spirv-builder/mygraphics/src/main.rs b/generated/graphics/ash/spirv-builder/mygraphics/src/main.rs similarity index 100% rename from generated/graphics/spirv-builder/mygraphics/src/main.rs rename to generated/graphics/ash/spirv-builder/mygraphics/src/main.rs diff --git a/generated/graphics/spirv-builder/mygraphics/src/util.rs b/generated/graphics/ash/spirv-builder/mygraphics/src/util.rs similarity index 100% rename from generated/graphics/spirv-builder/mygraphics/src/util.rs rename to generated/graphics/ash/spirv-builder/mygraphics/src/util.rs diff --git a/generated/graphics/spirv-builder/rust-toolchain.toml b/generated/graphics/ash/spirv-builder/rust-toolchain.toml similarity index 100% rename from generated/graphics/spirv-builder/rust-toolchain.toml rename to generated/graphics/ash/spirv-builder/rust-toolchain.toml diff --git a/generated/graphics/wgpu/cargo-gpu/Cargo.toml b/generated/graphics/wgpu/cargo-gpu/Cargo.toml new file mode 100644 index 0000000..49f0b10 --- /dev/null +++ b/generated/graphics/wgpu/cargo-gpu/Cargo.toml @@ -0,0 +1,34 @@ +[workspace] +members = [ + "mygraphics", + "mygraphics-shaders" +] +resolver = "3" + +[workspace.package] +version = "0.1.0" +authors = ["generated "] +edition = "2024" +license = "MIT" +repository = "" + +[workspace.lints.rust] +unexpected_cfgs = { level = "allow", check-cfg = ['cfg(target_arch, values("spirv"))'] } + +[workspace.dependencies] +# API +wgpu = { version = "27.0.1", default-features = false, features = ["std", "parking_lot", "vulkan", "vulkan-portability", "spirv", "wgsl"] } +pollster = "0.4.0" + +# rust-gpu +cargo-gpu = { git = "https://github.com/Rust-GPU/cargo-gpu", rev = "bf24eb6060e0c7b0013eceddd23b5d7cee68f4cc" } +spirv-std = { git = "https://github.com/Rust-GPU/rust-gpu", rev = "6fb875068d0d35b1a81ae89b73cf7a464f8c60f7" } + +# other +glam = { version = "0.30.9", default-features = false } +bytemuck = { version = "1.24.0", features = ["derive"] } +raw-window-handle = "0.6.2" +winit = "0.30.0" +env_logger = "0.11.8" +anyhow = "1.0.98" + diff --git a/generated/graphics/wgpu/cargo-gpu/mygraphics-shaders/Cargo.toml b/generated/graphics/wgpu/cargo-gpu/mygraphics-shaders/Cargo.toml new file mode 100644 index 0000000..0860c8b --- /dev/null +++ b/generated/graphics/wgpu/cargo-gpu/mygraphics-shaders/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "mygraphics-shaders" +version = "0.1.0" +edition = "2024" + +[lints] +workspace = true + +[lib] +crate-type = ["lib", "dylib"] + +[dependencies] +spirv-std.workspace = true +glam.workspace = true +bytemuck.workspace = true diff --git a/generated/graphics/wgpu/cargo-gpu/mygraphics-shaders/src/lib.rs b/generated/graphics/wgpu/cargo-gpu/mygraphics-shaders/src/lib.rs new file mode 100644 index 0000000..acf55ee --- /dev/null +++ b/generated/graphics/wgpu/cargo-gpu/mygraphics-shaders/src/lib.rs @@ -0,0 +1,36 @@ +#![no_std] + +use bytemuck::{Pod, Zeroable}; +use core::f32::consts::PI; +use glam::{Vec3, Vec4, vec2, vec3}; +#[cfg(target_arch = "spirv")] +use spirv_std::num_traits::Float; +use spirv_std::spirv; + +#[derive(Copy, Clone, Pod, Zeroable)] +#[repr(C)] +pub struct ShaderConstants { + pub width: u32, + pub height: u32, + pub time: f32, +} + +#[spirv(fragment)] +pub fn main_fs(vtx_color: Vec3, output: &mut Vec4) { + *output = Vec4::from((vtx_color, 1.)); +} + +#[spirv(vertex)] +pub fn main_vs( + #[spirv(vertex_index)] vert_id: i32, + #[spirv(push_constant)] constants: &ShaderConstants, + #[spirv(position)] vtx_pos: &mut Vec4, + vtx_color: &mut Vec3, +) { + let speed = 0.4; + let time = constants.time * speed + vert_id as f32 * (2. * PI * 120. / 360.); + let position = vec2(f32::sin(time), f32::cos(time)); + *vtx_pos = Vec4::from((position, 0.0, 1.0)); + + *vtx_color = [vec3(1., 0., 0.), vec3(0., 1., 0.), vec3(0., 0., 1.)][vert_id as usize % 3]; +} diff --git a/generated/graphics/wgpu/cargo-gpu/mygraphics/Cargo.toml b/generated/graphics/wgpu/cargo-gpu/mygraphics/Cargo.toml new file mode 100644 index 0000000..1349391 --- /dev/null +++ b/generated/graphics/wgpu/cargo-gpu/mygraphics/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "mygraphics" +publish = false +version.workspace = true +authors.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true + +[lints] +workspace = true + +[dependencies] +# shader crate +mygraphics-shaders = { path = "../mygraphics-shaders" } + +# API +wgpu.workspace = true +pollster.workspace = true +env_logger.workspace = true + +# other +raw-window-handle.workspace = true +winit.workspace = true +anyhow.workspace = true +bytemuck.workspace = true + +[build-dependencies] +# rust-gpu +cargo-gpu.workspace = true + +# other +anyhow.workspace = true diff --git a/generated/graphics/wgpu/cargo-gpu/mygraphics/build.rs b/generated/graphics/wgpu/cargo-gpu/mygraphics/build.rs new file mode 100644 index 0000000..0219afa --- /dev/null +++ b/generated/graphics/wgpu/cargo-gpu/mygraphics/build.rs @@ -0,0 +1,24 @@ +use cargo_gpu::Install; +use cargo_gpu::spirv_builder::{MetadataPrintout, ShaderPanicStrategy}; +use std::path::PathBuf; + +pub fn main() -> anyhow::Result<()> { + let manifest_dir = env!("CARGO_MANIFEST_DIR"); + let crate_path = [manifest_dir, "..", "mygraphics-shaders"] + .iter() + .copied() + .collect::(); + + let install = Install::from_shader_crate(crate_path.clone()).run()?; + let mut builder = install.to_spirv_builder(crate_path, "spirv-unknown-vulkan1.3"); + builder.print_metadata = MetadataPrintout::DependencyOnly; + builder.shader_panic_strategy = ShaderPanicStrategy::DebugPrintfThenExit { + print_inputs: true, + print_backtrace: true, + }; + + let compile_result = builder.build()?; + let spv_path = compile_result.module.unwrap_single(); + println!("cargo::rustc-env=SHADER_SPV_PATH={}", spv_path.display()); + Ok(()) +} diff --git a/generated/graphics/wgpu/cargo-gpu/mygraphics/src/lib.rs b/generated/graphics/wgpu/cargo-gpu/mygraphics/src/lib.rs new file mode 100644 index 0000000..48b8478 --- /dev/null +++ b/generated/graphics/wgpu/cargo-gpu/mygraphics/src/lib.rs @@ -0,0 +1,74 @@ +// FIXME(eddyb) update/review these lints. +// +// BEGIN - Embark standard lints v0.4 +// do not change or add/remove here, but one can add exceptions after this section +// for more info see: +//#![deny(unsafe_code)] // impractical in this crate dealing with unsafe `ash` +#![warn( + clippy::all, + clippy::await_holding_lock, + clippy::char_lit_as_u8, + clippy::checked_conversions, + clippy::dbg_macro, + clippy::debug_assert_with_mut_call, + clippy::doc_markdown, + clippy::empty_enum, + clippy::enum_glob_use, + clippy::exit, + clippy::expl_impl_clone_on_copy, + clippy::explicit_deref_methods, + clippy::explicit_into_iter_loop, + clippy::fallible_impl_from, + clippy::filter_map_next, + clippy::float_cmp_const, + clippy::fn_params_excessive_bools, + clippy::if_let_mutex, + clippy::implicit_clone, + clippy::imprecise_flops, + clippy::inefficient_to_string, + clippy::invalid_upcast_comparisons, + clippy::large_types_passed_by_value, + clippy::let_unit_value, + clippy::linkedlist, + clippy::lossy_float_literal, + clippy::macro_use_imports, + clippy::manual_ok_or, + clippy::map_err_ignore, + clippy::map_flatten, + clippy::map_unwrap_or, + clippy::match_same_arms, + clippy::match_wildcard_for_single_variants, + clippy::mem_forget, + clippy::mut_mut, + clippy::mutex_integer, + clippy::needless_borrow, + clippy::needless_continue, + clippy::option_option, + clippy::path_buf_push_overwrite, + clippy::ptr_as_ptr, + clippy::ref_option_ref, + clippy::rest_pat_in_fully_bound_structs, + clippy::same_functions_in_if_condition, + clippy::semicolon_if_nothing_returned, + clippy::string_add_assign, + clippy::string_add, + clippy::string_lit_as_bytes, + clippy::string_to_string, + clippy::todo, + clippy::trait_duplication_in_bounds, + clippy::unimplemented, + clippy::unnested_or_patterns, + clippy::unused_self, + clippy::useless_transmute, + clippy::verbose_file_reads, + clippy::zero_sized_map_values, + future_incompatible, + nonstandard_style, + rust_2018_idioms +)] +// END - Embark standard lints v0.4 +// crate-specific exceptions: +// #![allow()] + +pub mod util; +pub mod wgpu_renderer; diff --git a/graphics/mygraphics/src/main.rs b/generated/graphics/wgpu/cargo-gpu/mygraphics/src/main.rs similarity index 51% rename from graphics/mygraphics/src/main.rs rename to generated/graphics/wgpu/cargo-gpu/mygraphics/src/main.rs index f0e4195..7e06281 100644 --- a/graphics/mygraphics/src/main.rs +++ b/generated/graphics/wgpu/cargo-gpu/mygraphics/src/main.rs @@ -1,3 +1,3 @@ pub fn main() -> anyhow::Result<()> { - mygraphics::ash_renderer::main() + mygraphics::wgpu_renderer::main() } diff --git a/generated/graphics/wgpu/cargo-gpu/mygraphics/src/util.rs b/generated/graphics/wgpu/cargo-gpu/mygraphics/src/util.rs new file mode 100644 index 0000000..5541594 --- /dev/null +++ b/generated/graphics/wgpu/cargo-gpu/mygraphics/src/util.rs @@ -0,0 +1,5 @@ +pub fn enable_debug_layer() -> bool { + std::env::var("DEBUG_LAYER") + .map(|e| !(e == "0" || e == "false")) + .unwrap_or(false) +} diff --git a/generated/graphics/wgpu/cargo-gpu/mygraphics/src/wgpu_renderer/mod.rs b/generated/graphics/wgpu/cargo-gpu/mygraphics/src/wgpu_renderer/mod.rs new file mode 100644 index 0000000..f9a670f --- /dev/null +++ b/generated/graphics/wgpu/cargo-gpu/mygraphics/src/wgpu_renderer/mod.rs @@ -0,0 +1,104 @@ +use crate::wgpu_renderer::swapchain::MySwapchainManager; +use anyhow::Context; +use mygraphics_shaders::ShaderConstants; +use std::sync::Arc; +use winit::event::{Event, WindowEvent}; +use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop}; + +mod render_pipeline; +mod renderer; +mod swapchain; + +pub fn main() -> anyhow::Result<()> { + env_logger::init(); + pollster::block_on(main_inner()) +} + +pub async fn main_inner() -> anyhow::Result<()> { + // env_logger::init(); + let event_loop = EventLoop::new()?; + // FIXME(eddyb) incomplete `winit` upgrade, follow the guides in: + // https://github.com/rust-windowing/winit/releases/tag/v0.30.0 + #[allow(deprecated)] + let window = Arc::new( + event_loop.create_window( + winit::window::Window::default_attributes() + .with_title("Rust GPU - wgpu") + .with_inner_size(winit::dpi::LogicalSize::new( + f64::from(1280), + f64::from(720), + )), + )?, + ); + + let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor::from_env_or_default()); + let surface = instance.create_surface(window.clone())?; + let adapter = + wgpu::util::initialize_adapter_from_env_or_default(&instance, Some(&surface)).await?; + + let required_features = + wgpu::Features::PUSH_CONSTANTS | wgpu::Features::EXPERIMENTAL_PASSTHROUGH_SHADERS; + let required_limits = wgpu::Limits { + max_push_constant_size: 128, + ..Default::default() + }; + let (device, queue) = adapter + .request_device(&wgpu::DeviceDescriptor { + label: None, + required_features, + required_limits, + experimental_features: unsafe { wgpu::ExperimentalFeatures::enabled() }, + memory_hints: wgpu::MemoryHints::Performance, + trace: Default::default(), + }) + .await + .context("Failed to create device")?; + + let mut swapchain = MySwapchainManager::new(adapter.clone(), device.clone(), window, surface); + let renderer = renderer::MyRenderer::new(device, queue, swapchain.format())?; + + let start = std::time::Instant::now(); + let mut event_handler = + move |event: Event<_>, event_loop_window_target: &ActiveEventLoop| match event { + Event::AboutToWait => swapchain.render(|render_target| { + renderer.render( + &ShaderConstants { + time: start.elapsed().as_secs_f32(), + width: render_target.texture().width(), + height: render_target.texture().height(), + }, + render_target, + ); + }), + Event::WindowEvent { event, .. } => { + match event { + WindowEvent::KeyboardInput { + event: + winit::event::KeyEvent { + logical_key: + winit::keyboard::Key::Named(winit::keyboard::NamedKey::Escape), + state: winit::event::ElementState::Pressed, + .. + }, + .. + } + | WindowEvent::CloseRequested => event_loop_window_target.exit(), + WindowEvent::Resized(_) => swapchain.should_recreate(), + _ => {} + } + Ok(()) + } + _ => { + event_loop_window_target.set_control_flow(ControlFlow::Poll); + Ok(()) + } + }; + + // FIXME(eddyb) incomplete `winit` upgrade, follow the guides in: + // https://github.com/rust-windowing/winit/releases/tag/v0.30.0 + #[allow(deprecated)] + event_loop.run(move |event, event_loop_window_target| { + event_handler(event, event_loop_window_target).unwrap(); + })?; + Ok(()) +} diff --git a/generated/graphics/wgpu/cargo-gpu/mygraphics/src/wgpu_renderer/render_pipeline.rs b/generated/graphics/wgpu/cargo-gpu/mygraphics/src/wgpu_renderer/render_pipeline.rs new file mode 100644 index 0000000..f100339 --- /dev/null +++ b/generated/graphics/wgpu/cargo-gpu/mygraphics/src/wgpu_renderer/render_pipeline.rs @@ -0,0 +1,92 @@ +use mygraphics_shaders::ShaderConstants; +use wgpu::{ + ColorTargetState, ColorWrites, Device, FragmentState, FrontFace, MultisampleState, + PipelineLayoutDescriptor, PolygonMode, PrimitiveState, PrimitiveTopology, PushConstantRange, + RenderPass, RenderPipeline, RenderPipelineDescriptor, ShaderModuleDescriptorPassthrough, + ShaderRuntimeChecks, ShaderStages, TextureFormat, VertexState, +}; + +pub struct MyRenderPipeline { + pipeline: RenderPipeline, +} + +impl MyRenderPipeline { + pub fn new(device: &Device, out_format: TextureFormat) -> anyhow::Result { + // Workaround in wgpu 27.0.1 where the macro expansion of `include_spirv_raw!` doesn't compile + // see https://github.com/gfx-rs/wgpu/pull/8250 + // let module = unsafe { + // device.create_shader_module_passthrough(include_spirv_raw!(env!("SHADER_SPV_PATH"))) + // }; + let module = unsafe { + device.create_shader_module_passthrough(ShaderModuleDescriptorPassthrough { + label: Some(env!("SHADER_SPV_PATH")), + entry_point: "".to_owned(), + num_workgroups: (0, 0, 0), + runtime_checks: ShaderRuntimeChecks::unchecked(), + spirv: Some(wgpu::util::make_spirv_raw(include_bytes!(env!( + "SHADER_SPV_PATH" + )))), + dxil: None, + msl: None, + hlsl: None, + glsl: None, + wgsl: None, + }) + }; + + let layout = device.create_pipeline_layout(&PipelineLayoutDescriptor { + label: Some("MyRenderPipeline layout"), + bind_group_layouts: &[], + push_constant_ranges: &[PushConstantRange { + stages: ShaderStages::VERTEX_FRAGMENT, + range: 0..size_of::() as u32, + }], + }); + + Ok(Self { + pipeline: device.create_render_pipeline(&RenderPipelineDescriptor { + label: Some("MyRenderPipeline"), + layout: Some(&layout), + vertex: VertexState { + module: &module, + entry_point: Some("main_vs"), + compilation_options: Default::default(), + buffers: &[], + }, + primitive: PrimitiveState { + topology: PrimitiveTopology::TriangleList, + strip_index_format: None, + front_face: FrontFace::Ccw, + cull_mode: None, + unclipped_depth: false, + polygon_mode: PolygonMode::Fill, + conservative: false, + }, + depth_stencil: None, + multisample: MultisampleState::default(), + fragment: Some(FragmentState { + module: &module, + entry_point: Some("main_fs"), + compilation_options: Default::default(), + targets: &[Some(ColorTargetState { + format: out_format, + blend: None, + write_mask: ColorWrites::ALL, + })], + }), + multiview: None, + cache: None, + }), + }) + } + + pub fn draw(&self, rpass: &mut RenderPass<'_>, shader_constants: &ShaderConstants) { + rpass.set_pipeline(&self.pipeline); + rpass.set_push_constants( + ShaderStages::VERTEX_FRAGMENT, + 0, + bytemuck::bytes_of(shader_constants), + ); + rpass.draw(0..3, 0..1); + } +} diff --git a/generated/graphics/wgpu/cargo-gpu/mygraphics/src/wgpu_renderer/renderer.rs b/generated/graphics/wgpu/cargo-gpu/mygraphics/src/wgpu_renderer/renderer.rs new file mode 100644 index 0000000..c5213df --- /dev/null +++ b/generated/graphics/wgpu/cargo-gpu/mygraphics/src/wgpu_renderer/renderer.rs @@ -0,0 +1,51 @@ +use crate::wgpu_renderer::render_pipeline::MyRenderPipeline; +use mygraphics_shaders::ShaderConstants; +use wgpu::wgt::CommandEncoderDescriptor; +use wgpu::{ + Color, Device, LoadOp, Operations, Queue, RenderPassColorAttachment, RenderPassDescriptor, + StoreOp, TextureFormat, TextureView, +}; + +pub struct MyRenderer { + pub device: Device, + pub queue: Queue, + pipeline: MyRenderPipeline, +} + +impl MyRenderer { + pub fn new(device: Device, queue: Queue, out_format: TextureFormat) -> anyhow::Result { + Ok(Self { + pipeline: MyRenderPipeline::new(&device, out_format)?, + device, + queue, + }) + } + + pub fn render(&self, shader_constants: &ShaderConstants, output: TextureView) { + let mut cmd = self + .device + .create_command_encoder(&CommandEncoderDescriptor { + label: Some("main draw"), + }); + + let mut rpass = cmd.begin_render_pass(&RenderPassDescriptor { + label: Some("main renderpass"), + color_attachments: &[Some(RenderPassColorAttachment { + view: &output, + depth_slice: None, + resolve_target: None, + ops: Operations { + load: LoadOp::Clear(Color::BLACK), + store: StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, + }); + self.pipeline.draw(&mut rpass, shader_constants); + drop(rpass); + + self.queue.submit(std::iter::once(cmd.finish())); + } +} diff --git a/generated/graphics/wgpu/cargo-gpu/mygraphics/src/wgpu_renderer/swapchain.rs b/generated/graphics/wgpu/cargo-gpu/mygraphics/src/wgpu_renderer/swapchain.rs new file mode 100644 index 0000000..ed1b8d1 --- /dev/null +++ b/generated/graphics/wgpu/cargo-gpu/mygraphics/src/wgpu_renderer/swapchain.rs @@ -0,0 +1,117 @@ +use anyhow::Context; +use std::sync::Arc; +use wgpu::{Adapter, Device, Surface, SurfaceError, TextureFormat, TextureView}; +use winit::dpi::PhysicalSize; +use winit::window::Window; + +pub struct MySwapchainManager<'a> { + adapter: Adapter, + device: Device, + window: Arc, + surface: Surface<'a>, + format: TextureFormat, + + // state below + active: Option, + should_recreate: bool, +} + +pub struct ActiveConfiguration { + size: PhysicalSize, +} + +impl<'a> MySwapchainManager<'a> { + pub fn new( + adapter: Adapter, + device: Device, + window: Arc, + surface: Surface<'a>, + ) -> Self { + let caps = surface.get_capabilities(&adapter); + Self { + adapter, + device, + window, + surface, + format: caps.formats[0], + active: None, + should_recreate: true, + } + } + + #[inline] + pub fn should_recreate(&mut self) { + self.should_recreate = true; + } + + pub fn format(&self) -> TextureFormat { + self.format + } + + pub fn render(&mut self, f: impl FnOnce(TextureView) -> R) -> anyhow::Result { + let size = self.window.inner_size(); + if let Some(active) = &self.active { + if active.size != size { + self.should_recreate(); + } + } else { + self.should_recreate(); + } + + const RECREATE_ATTEMPTS: u32 = 10; + for _ in 0..RECREATE_ATTEMPTS { + if self.should_recreate { + self.should_recreate = false; + self.configure_surface(size)?; + } + + match self.surface.get_current_texture() { + Ok(surface_texture) => { + if surface_texture.suboptimal { + self.should_recreate = true; + } + let output_view = + surface_texture + .texture + .create_view(&wgpu::TextureViewDescriptor { + format: Some(self.format), + ..wgpu::TextureViewDescriptor::default() + }); + let r = f(output_view); + surface_texture.present(); + return Ok(r); + } + Err(SurfaceError::Outdated | SurfaceError::Lost) => { + self.should_recreate = true; + } + Err(e) => { + anyhow::bail!("get_current_texture() failed: {e}") + } + }; + } + anyhow::bail!( + "looped {RECREATE_ATTEMPTS} times trying to acquire swapchain image and failed repeatedly!" + ); + } + + fn configure_surface(&mut self, size: PhysicalSize) -> anyhow::Result<()> { + let mut surface_config = self + .surface + .get_default_config(&self.adapter, size.width, size.height) + .with_context(|| { + format!( + "Incompatible adapter for surface, returned capabilities: {:?}", + self.surface.get_capabilities(&self.adapter) + ) + })?; + + // force srgb surface format + surface_config.view_formats.push(self.format); + // limit framerate to vsync + surface_config.present_mode = wgpu::PresentMode::AutoVsync; + self.surface.configure(&self.device, &surface_config); + + self.active = Some(ActiveConfiguration { size }); + Ok(()) + } +} diff --git a/generated/graphics/wgpu/spirv-builder/Cargo.toml b/generated/graphics/wgpu/spirv-builder/Cargo.toml new file mode 100644 index 0000000..5d9e4b9 --- /dev/null +++ b/generated/graphics/wgpu/spirv-builder/Cargo.toml @@ -0,0 +1,61 @@ +[workspace] +members = [ + "mygraphics", + "mygraphics-shaders" +] +resolver = "3" + +[workspace.package] +version = "0.1.0" +authors = ["generated "] +edition = "2024" +license = "MIT" +repository = "" + +[workspace.lints.rust] +unexpected_cfgs = { level = "allow", check-cfg = ['cfg(target_arch, values("spirv"))'] } + +[workspace.dependencies] +# API +wgpu = { version = "27.0.1", default-features = false, features = ["std", "parking_lot", "vulkan", "vulkan-portability", "spirv", "wgsl"] } +pollster = "0.4.0" + +# rust-gpu +# The version of the dependencies `spirv-builder` and `spirv-std` must match exactly! +spirv-builder = { git = "https://github.com/Rust-GPU/rust-gpu", rev = "6fb875068d0d35b1a81ae89b73cf7a464f8c60f7" } +spirv-std = { git = "https://github.com/Rust-GPU/rust-gpu", rev = "6fb875068d0d35b1a81ae89b73cf7a464f8c60f7" } + +# other +glam = { version = "0.30.9", default-features = false } +bytemuck = { version = "1.24.0", features = ["derive"] } +raw-window-handle = "0.6.2" +winit = "0.30.0" +env_logger = "0.11.8" +anyhow = "1.0.98" + +# Optimize build scripts, copied from rust-gpu's repo +# Enable incremental by default in release mode. +[profile.release] +incremental = true +# HACK(eddyb) this is the default but without explicitly specifying it, Cargo +# will treat the identical settings in `[profile.release.build-override]` below +# as different sets of `rustc` flags and will not reuse artifacts between them. +codegen-units = 256 + +# Compile build-dependencies in release mode with the same settings +# as regular dependencies (including the incremental enabled above). +[profile.release.build-override] +opt-level = 3 +incremental = true +codegen-units = 256 + +# HACK(eddyb) reduce the number of linker exports and/or imports, by avoiding +# inter-CGU linkage, to stay under the 64Ki MSVC limit for `rustc_codegen_spirv` +# when building it in "debug mode" (only relevant to CI for now, realistically), +# i.e. working around this issue: https://github.com/rust-lang/rust/issues/53014. +[profile.dev] +# HACK(eddyb) fewer inter-crate exports/imports (not just inter-CGU), but sadly +# not configurable w/o breaking `Cargo.toml` parsing from non-nightly Cargo. +# +# rustflags = ["-Zshare-generics=off"] +codegen-units = 1 diff --git a/generated/graphics/wgpu/spirv-builder/mygraphics-shaders/Cargo.toml b/generated/graphics/wgpu/spirv-builder/mygraphics-shaders/Cargo.toml new file mode 100644 index 0000000..0860c8b --- /dev/null +++ b/generated/graphics/wgpu/spirv-builder/mygraphics-shaders/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "mygraphics-shaders" +version = "0.1.0" +edition = "2024" + +[lints] +workspace = true + +[lib] +crate-type = ["lib", "dylib"] + +[dependencies] +spirv-std.workspace = true +glam.workspace = true +bytemuck.workspace = true diff --git a/generated/graphics/wgpu/spirv-builder/mygraphics-shaders/src/lib.rs b/generated/graphics/wgpu/spirv-builder/mygraphics-shaders/src/lib.rs new file mode 100644 index 0000000..acf55ee --- /dev/null +++ b/generated/graphics/wgpu/spirv-builder/mygraphics-shaders/src/lib.rs @@ -0,0 +1,36 @@ +#![no_std] + +use bytemuck::{Pod, Zeroable}; +use core::f32::consts::PI; +use glam::{Vec3, Vec4, vec2, vec3}; +#[cfg(target_arch = "spirv")] +use spirv_std::num_traits::Float; +use spirv_std::spirv; + +#[derive(Copy, Clone, Pod, Zeroable)] +#[repr(C)] +pub struct ShaderConstants { + pub width: u32, + pub height: u32, + pub time: f32, +} + +#[spirv(fragment)] +pub fn main_fs(vtx_color: Vec3, output: &mut Vec4) { + *output = Vec4::from((vtx_color, 1.)); +} + +#[spirv(vertex)] +pub fn main_vs( + #[spirv(vertex_index)] vert_id: i32, + #[spirv(push_constant)] constants: &ShaderConstants, + #[spirv(position)] vtx_pos: &mut Vec4, + vtx_color: &mut Vec3, +) { + let speed = 0.4; + let time = constants.time * speed + vert_id as f32 * (2. * PI * 120. / 360.); + let position = vec2(f32::sin(time), f32::cos(time)); + *vtx_pos = Vec4::from((position, 0.0, 1.0)); + + *vtx_color = [vec3(1., 0., 0.), vec3(0., 1., 0.), vec3(0., 0., 1.)][vert_id as usize % 3]; +} diff --git a/generated/graphics/wgpu/spirv-builder/mygraphics/Cargo.toml b/generated/graphics/wgpu/spirv-builder/mygraphics/Cargo.toml new file mode 100644 index 0000000..744eaa1 --- /dev/null +++ b/generated/graphics/wgpu/spirv-builder/mygraphics/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "mygraphics" +publish = false +version.workspace = true +authors.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true + +[lints] +workspace = true + +[features] +default = ["use-compiled-tools"] +use-installed-tools = ["spirv-builder/use-installed-tools"] +use-compiled-tools = ["spirv-builder/use-compiled-tools"] +[dependencies] +# shader crate +mygraphics-shaders = { path = "../mygraphics-shaders" } + +# API +wgpu.workspace = true +pollster.workspace = true +env_logger.workspace = true + +# other +raw-window-handle.workspace = true +winit.workspace = true +anyhow.workspace = true +bytemuck.workspace = true + +[build-dependencies] +# rust-gpu +spirv-builder.workspace = true + +# other +anyhow.workspace = true diff --git a/generated/graphics/wgpu/spirv-builder/mygraphics/build.rs b/generated/graphics/wgpu/spirv-builder/mygraphics/build.rs new file mode 100644 index 0000000..5993ae2 --- /dev/null +++ b/generated/graphics/wgpu/spirv-builder/mygraphics/build.rs @@ -0,0 +1,22 @@ +use spirv_builder::{MetadataPrintout, ShaderPanicStrategy, SpirvBuilder}; +use std::path::PathBuf; + +pub fn main() -> anyhow::Result<()> { + let manifest_dir = env!("CARGO_MANIFEST_DIR"); + let crate_path = [manifest_dir, "..", "mygraphics-shaders"] + .iter() + .copied() + .collect::(); + + let mut builder = SpirvBuilder::new(crate_path, "spirv-unknown-vulkan1.3"); + builder.print_metadata = MetadataPrintout::DependencyOnly; + builder.shader_panic_strategy = ShaderPanicStrategy::DebugPrintfThenExit { + print_inputs: true, + print_backtrace: true, + }; + + let compile_result = builder.build()?; + let spv_path = compile_result.module.unwrap_single(); + println!("cargo::rustc-env=SHADER_SPV_PATH={}", spv_path.display()); + Ok(()) +} diff --git a/generated/graphics/wgpu/spirv-builder/mygraphics/src/lib.rs b/generated/graphics/wgpu/spirv-builder/mygraphics/src/lib.rs new file mode 100644 index 0000000..48b8478 --- /dev/null +++ b/generated/graphics/wgpu/spirv-builder/mygraphics/src/lib.rs @@ -0,0 +1,74 @@ +// FIXME(eddyb) update/review these lints. +// +// BEGIN - Embark standard lints v0.4 +// do not change or add/remove here, but one can add exceptions after this section +// for more info see: +//#![deny(unsafe_code)] // impractical in this crate dealing with unsafe `ash` +#![warn( + clippy::all, + clippy::await_holding_lock, + clippy::char_lit_as_u8, + clippy::checked_conversions, + clippy::dbg_macro, + clippy::debug_assert_with_mut_call, + clippy::doc_markdown, + clippy::empty_enum, + clippy::enum_glob_use, + clippy::exit, + clippy::expl_impl_clone_on_copy, + clippy::explicit_deref_methods, + clippy::explicit_into_iter_loop, + clippy::fallible_impl_from, + clippy::filter_map_next, + clippy::float_cmp_const, + clippy::fn_params_excessive_bools, + clippy::if_let_mutex, + clippy::implicit_clone, + clippy::imprecise_flops, + clippy::inefficient_to_string, + clippy::invalid_upcast_comparisons, + clippy::large_types_passed_by_value, + clippy::let_unit_value, + clippy::linkedlist, + clippy::lossy_float_literal, + clippy::macro_use_imports, + clippy::manual_ok_or, + clippy::map_err_ignore, + clippy::map_flatten, + clippy::map_unwrap_or, + clippy::match_same_arms, + clippy::match_wildcard_for_single_variants, + clippy::mem_forget, + clippy::mut_mut, + clippy::mutex_integer, + clippy::needless_borrow, + clippy::needless_continue, + clippy::option_option, + clippy::path_buf_push_overwrite, + clippy::ptr_as_ptr, + clippy::ref_option_ref, + clippy::rest_pat_in_fully_bound_structs, + clippy::same_functions_in_if_condition, + clippy::semicolon_if_nothing_returned, + clippy::string_add_assign, + clippy::string_add, + clippy::string_lit_as_bytes, + clippy::string_to_string, + clippy::todo, + clippy::trait_duplication_in_bounds, + clippy::unimplemented, + clippy::unnested_or_patterns, + clippy::unused_self, + clippy::useless_transmute, + clippy::verbose_file_reads, + clippy::zero_sized_map_values, + future_incompatible, + nonstandard_style, + rust_2018_idioms +)] +// END - Embark standard lints v0.4 +// crate-specific exceptions: +// #![allow()] + +pub mod util; +pub mod wgpu_renderer; diff --git a/generated/graphics/wgpu/spirv-builder/mygraphics/src/main.rs b/generated/graphics/wgpu/spirv-builder/mygraphics/src/main.rs new file mode 100644 index 0000000..7e06281 --- /dev/null +++ b/generated/graphics/wgpu/spirv-builder/mygraphics/src/main.rs @@ -0,0 +1,3 @@ +pub fn main() -> anyhow::Result<()> { + mygraphics::wgpu_renderer::main() +} diff --git a/generated/graphics/wgpu/spirv-builder/mygraphics/src/util.rs b/generated/graphics/wgpu/spirv-builder/mygraphics/src/util.rs new file mode 100644 index 0000000..5541594 --- /dev/null +++ b/generated/graphics/wgpu/spirv-builder/mygraphics/src/util.rs @@ -0,0 +1,5 @@ +pub fn enable_debug_layer() -> bool { + std::env::var("DEBUG_LAYER") + .map(|e| !(e == "0" || e == "false")) + .unwrap_or(false) +} diff --git a/generated/graphics/wgpu/spirv-builder/mygraphics/src/wgpu_renderer/mod.rs b/generated/graphics/wgpu/spirv-builder/mygraphics/src/wgpu_renderer/mod.rs new file mode 100644 index 0000000..f9a670f --- /dev/null +++ b/generated/graphics/wgpu/spirv-builder/mygraphics/src/wgpu_renderer/mod.rs @@ -0,0 +1,104 @@ +use crate::wgpu_renderer::swapchain::MySwapchainManager; +use anyhow::Context; +use mygraphics_shaders::ShaderConstants; +use std::sync::Arc; +use winit::event::{Event, WindowEvent}; +use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop}; + +mod render_pipeline; +mod renderer; +mod swapchain; + +pub fn main() -> anyhow::Result<()> { + env_logger::init(); + pollster::block_on(main_inner()) +} + +pub async fn main_inner() -> anyhow::Result<()> { + // env_logger::init(); + let event_loop = EventLoop::new()?; + // FIXME(eddyb) incomplete `winit` upgrade, follow the guides in: + // https://github.com/rust-windowing/winit/releases/tag/v0.30.0 + #[allow(deprecated)] + let window = Arc::new( + event_loop.create_window( + winit::window::Window::default_attributes() + .with_title("Rust GPU - wgpu") + .with_inner_size(winit::dpi::LogicalSize::new( + f64::from(1280), + f64::from(720), + )), + )?, + ); + + let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor::from_env_or_default()); + let surface = instance.create_surface(window.clone())?; + let adapter = + wgpu::util::initialize_adapter_from_env_or_default(&instance, Some(&surface)).await?; + + let required_features = + wgpu::Features::PUSH_CONSTANTS | wgpu::Features::EXPERIMENTAL_PASSTHROUGH_SHADERS; + let required_limits = wgpu::Limits { + max_push_constant_size: 128, + ..Default::default() + }; + let (device, queue) = adapter + .request_device(&wgpu::DeviceDescriptor { + label: None, + required_features, + required_limits, + experimental_features: unsafe { wgpu::ExperimentalFeatures::enabled() }, + memory_hints: wgpu::MemoryHints::Performance, + trace: Default::default(), + }) + .await + .context("Failed to create device")?; + + let mut swapchain = MySwapchainManager::new(adapter.clone(), device.clone(), window, surface); + let renderer = renderer::MyRenderer::new(device, queue, swapchain.format())?; + + let start = std::time::Instant::now(); + let mut event_handler = + move |event: Event<_>, event_loop_window_target: &ActiveEventLoop| match event { + Event::AboutToWait => swapchain.render(|render_target| { + renderer.render( + &ShaderConstants { + time: start.elapsed().as_secs_f32(), + width: render_target.texture().width(), + height: render_target.texture().height(), + }, + render_target, + ); + }), + Event::WindowEvent { event, .. } => { + match event { + WindowEvent::KeyboardInput { + event: + winit::event::KeyEvent { + logical_key: + winit::keyboard::Key::Named(winit::keyboard::NamedKey::Escape), + state: winit::event::ElementState::Pressed, + .. + }, + .. + } + | WindowEvent::CloseRequested => event_loop_window_target.exit(), + WindowEvent::Resized(_) => swapchain.should_recreate(), + _ => {} + } + Ok(()) + } + _ => { + event_loop_window_target.set_control_flow(ControlFlow::Poll); + Ok(()) + } + }; + + // FIXME(eddyb) incomplete `winit` upgrade, follow the guides in: + // https://github.com/rust-windowing/winit/releases/tag/v0.30.0 + #[allow(deprecated)] + event_loop.run(move |event, event_loop_window_target| { + event_handler(event, event_loop_window_target).unwrap(); + })?; + Ok(()) +} diff --git a/generated/graphics/wgpu/spirv-builder/mygraphics/src/wgpu_renderer/render_pipeline.rs b/generated/graphics/wgpu/spirv-builder/mygraphics/src/wgpu_renderer/render_pipeline.rs new file mode 100644 index 0000000..f100339 --- /dev/null +++ b/generated/graphics/wgpu/spirv-builder/mygraphics/src/wgpu_renderer/render_pipeline.rs @@ -0,0 +1,92 @@ +use mygraphics_shaders::ShaderConstants; +use wgpu::{ + ColorTargetState, ColorWrites, Device, FragmentState, FrontFace, MultisampleState, + PipelineLayoutDescriptor, PolygonMode, PrimitiveState, PrimitiveTopology, PushConstantRange, + RenderPass, RenderPipeline, RenderPipelineDescriptor, ShaderModuleDescriptorPassthrough, + ShaderRuntimeChecks, ShaderStages, TextureFormat, VertexState, +}; + +pub struct MyRenderPipeline { + pipeline: RenderPipeline, +} + +impl MyRenderPipeline { + pub fn new(device: &Device, out_format: TextureFormat) -> anyhow::Result { + // Workaround in wgpu 27.0.1 where the macro expansion of `include_spirv_raw!` doesn't compile + // see https://github.com/gfx-rs/wgpu/pull/8250 + // let module = unsafe { + // device.create_shader_module_passthrough(include_spirv_raw!(env!("SHADER_SPV_PATH"))) + // }; + let module = unsafe { + device.create_shader_module_passthrough(ShaderModuleDescriptorPassthrough { + label: Some(env!("SHADER_SPV_PATH")), + entry_point: "".to_owned(), + num_workgroups: (0, 0, 0), + runtime_checks: ShaderRuntimeChecks::unchecked(), + spirv: Some(wgpu::util::make_spirv_raw(include_bytes!(env!( + "SHADER_SPV_PATH" + )))), + dxil: None, + msl: None, + hlsl: None, + glsl: None, + wgsl: None, + }) + }; + + let layout = device.create_pipeline_layout(&PipelineLayoutDescriptor { + label: Some("MyRenderPipeline layout"), + bind_group_layouts: &[], + push_constant_ranges: &[PushConstantRange { + stages: ShaderStages::VERTEX_FRAGMENT, + range: 0..size_of::() as u32, + }], + }); + + Ok(Self { + pipeline: device.create_render_pipeline(&RenderPipelineDescriptor { + label: Some("MyRenderPipeline"), + layout: Some(&layout), + vertex: VertexState { + module: &module, + entry_point: Some("main_vs"), + compilation_options: Default::default(), + buffers: &[], + }, + primitive: PrimitiveState { + topology: PrimitiveTopology::TriangleList, + strip_index_format: None, + front_face: FrontFace::Ccw, + cull_mode: None, + unclipped_depth: false, + polygon_mode: PolygonMode::Fill, + conservative: false, + }, + depth_stencil: None, + multisample: MultisampleState::default(), + fragment: Some(FragmentState { + module: &module, + entry_point: Some("main_fs"), + compilation_options: Default::default(), + targets: &[Some(ColorTargetState { + format: out_format, + blend: None, + write_mask: ColorWrites::ALL, + })], + }), + multiview: None, + cache: None, + }), + }) + } + + pub fn draw(&self, rpass: &mut RenderPass<'_>, shader_constants: &ShaderConstants) { + rpass.set_pipeline(&self.pipeline); + rpass.set_push_constants( + ShaderStages::VERTEX_FRAGMENT, + 0, + bytemuck::bytes_of(shader_constants), + ); + rpass.draw(0..3, 0..1); + } +} diff --git a/generated/graphics/wgpu/spirv-builder/mygraphics/src/wgpu_renderer/renderer.rs b/generated/graphics/wgpu/spirv-builder/mygraphics/src/wgpu_renderer/renderer.rs new file mode 100644 index 0000000..c5213df --- /dev/null +++ b/generated/graphics/wgpu/spirv-builder/mygraphics/src/wgpu_renderer/renderer.rs @@ -0,0 +1,51 @@ +use crate::wgpu_renderer::render_pipeline::MyRenderPipeline; +use mygraphics_shaders::ShaderConstants; +use wgpu::wgt::CommandEncoderDescriptor; +use wgpu::{ + Color, Device, LoadOp, Operations, Queue, RenderPassColorAttachment, RenderPassDescriptor, + StoreOp, TextureFormat, TextureView, +}; + +pub struct MyRenderer { + pub device: Device, + pub queue: Queue, + pipeline: MyRenderPipeline, +} + +impl MyRenderer { + pub fn new(device: Device, queue: Queue, out_format: TextureFormat) -> anyhow::Result { + Ok(Self { + pipeline: MyRenderPipeline::new(&device, out_format)?, + device, + queue, + }) + } + + pub fn render(&self, shader_constants: &ShaderConstants, output: TextureView) { + let mut cmd = self + .device + .create_command_encoder(&CommandEncoderDescriptor { + label: Some("main draw"), + }); + + let mut rpass = cmd.begin_render_pass(&RenderPassDescriptor { + label: Some("main renderpass"), + color_attachments: &[Some(RenderPassColorAttachment { + view: &output, + depth_slice: None, + resolve_target: None, + ops: Operations { + load: LoadOp::Clear(Color::BLACK), + store: StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, + }); + self.pipeline.draw(&mut rpass, shader_constants); + drop(rpass); + + self.queue.submit(std::iter::once(cmd.finish())); + } +} diff --git a/generated/graphics/wgpu/spirv-builder/mygraphics/src/wgpu_renderer/swapchain.rs b/generated/graphics/wgpu/spirv-builder/mygraphics/src/wgpu_renderer/swapchain.rs new file mode 100644 index 0000000..ed1b8d1 --- /dev/null +++ b/generated/graphics/wgpu/spirv-builder/mygraphics/src/wgpu_renderer/swapchain.rs @@ -0,0 +1,117 @@ +use anyhow::Context; +use std::sync::Arc; +use wgpu::{Adapter, Device, Surface, SurfaceError, TextureFormat, TextureView}; +use winit::dpi::PhysicalSize; +use winit::window::Window; + +pub struct MySwapchainManager<'a> { + adapter: Adapter, + device: Device, + window: Arc, + surface: Surface<'a>, + format: TextureFormat, + + // state below + active: Option, + should_recreate: bool, +} + +pub struct ActiveConfiguration { + size: PhysicalSize, +} + +impl<'a> MySwapchainManager<'a> { + pub fn new( + adapter: Adapter, + device: Device, + window: Arc, + surface: Surface<'a>, + ) -> Self { + let caps = surface.get_capabilities(&adapter); + Self { + adapter, + device, + window, + surface, + format: caps.formats[0], + active: None, + should_recreate: true, + } + } + + #[inline] + pub fn should_recreate(&mut self) { + self.should_recreate = true; + } + + pub fn format(&self) -> TextureFormat { + self.format + } + + pub fn render(&mut self, f: impl FnOnce(TextureView) -> R) -> anyhow::Result { + let size = self.window.inner_size(); + if let Some(active) = &self.active { + if active.size != size { + self.should_recreate(); + } + } else { + self.should_recreate(); + } + + const RECREATE_ATTEMPTS: u32 = 10; + for _ in 0..RECREATE_ATTEMPTS { + if self.should_recreate { + self.should_recreate = false; + self.configure_surface(size)?; + } + + match self.surface.get_current_texture() { + Ok(surface_texture) => { + if surface_texture.suboptimal { + self.should_recreate = true; + } + let output_view = + surface_texture + .texture + .create_view(&wgpu::TextureViewDescriptor { + format: Some(self.format), + ..wgpu::TextureViewDescriptor::default() + }); + let r = f(output_view); + surface_texture.present(); + return Ok(r); + } + Err(SurfaceError::Outdated | SurfaceError::Lost) => { + self.should_recreate = true; + } + Err(e) => { + anyhow::bail!("get_current_texture() failed: {e}") + } + }; + } + anyhow::bail!( + "looped {RECREATE_ATTEMPTS} times trying to acquire swapchain image and failed repeatedly!" + ); + } + + fn configure_surface(&mut self, size: PhysicalSize) -> anyhow::Result<()> { + let mut surface_config = self + .surface + .get_default_config(&self.adapter, size.width, size.height) + .with_context(|| { + format!( + "Incompatible adapter for surface, returned capabilities: {:?}", + self.surface.get_capabilities(&self.adapter) + ) + })?; + + // force srgb surface format + surface_config.view_formats.push(self.format); + // limit framerate to vsync + surface_config.present_mode = wgpu::PresentMode::AutoVsync; + self.surface.configure(&self.device, &surface_config); + + self.active = Some(ActiveConfiguration { size }); + Ok(()) + } +} diff --git a/generated/graphics/wgpu/spirv-builder/rust-toolchain.toml b/generated/graphics/wgpu/spirv-builder/rust-toolchain.toml new file mode 100644 index 0000000..c817176 --- /dev/null +++ b/generated/graphics/wgpu/spirv-builder/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = "nightly-2025-06-30" +components = ["rust-src", "rustc-dev", "llvm-tools"] diff --git a/graphics/Cargo.toml.liquid b/graphics/Cargo.toml.liquid index 7794d07..5257139 100644 --- a/graphics/Cargo.toml.liquid +++ b/graphics/Cargo.toml.liquid @@ -16,6 +16,17 @@ repository = "" unexpected_cfgs = { level = "allow", check-cfg = ['cfg(target_arch, values("spirv"))'] } [workspace.dependencies] +# API +{% if api == "ash" -%} +ash = "0.38" +ash-window = "0.13" +{%- endif -%} +{%- if api == "wgpu" -%} +wgpu = { version = "27.0.1", default-features = false, features = ["std", "parking_lot", "vulkan", "vulkan-portability", "spirv", "wgsl"] } +pollster = "0.4.0" +{%- endif %} + +# rust-gpu {% if integration == "spirv-builder" -%} # The version of the dependencies `spirv-builder` and `spirv-std` must match exactly! spirv-builder = { git = "https://github.com/Rust-GPU/rust-gpu", rev = "6fb875068d0d35b1a81ae89b73cf7a464f8c60f7" } @@ -25,13 +36,12 @@ cargo-gpu = { git = "https://github.com/Rust-GPU/cargo-gpu", rev = "bf24eb6060e0 {% endif -%} spirv-std = { git = "https://github.com/Rust-GPU/rust-gpu", rev = "6fb875068d0d35b1a81ae89b73cf7a464f8c60f7" } +# other glam = { version = "0.30.9", default-features = false } bytemuck = { version = "1.24.0", features = ["derive"] } -ash = "0.38" -ash-window = "0.13" raw-window-handle = "0.6.2" winit = "0.30.0" -cfg-if = "1.0.0" +env_logger = "0.11.8" anyhow = "1.0.98" {% if integration == "spirv-builder" -%} diff --git a/graphics/cargo-generate.toml b/graphics/cargo-generate.toml index 12ed189..5003d4c 100644 --- a/graphics/cargo-generate.toml +++ b/graphics/cargo-generate.toml @@ -3,7 +3,14 @@ ignore = ["target", "mygraphics/src/bin"] exclude = ["target", "mygraphics/src/bin"] [placeholders] -integration = { prompt = "What integration type?", choices = ["cargo-gpu", "spirv-builder"], default = "cargo-gpu", type = "string" } +api = { prompt = "What API?", choices = ["wgpu", "ash"], default = "wgpu", type = "string" } +integration = { prompt = "How to integrate rust-gpu?", choices = ["cargo-gpu", "spirv-builder"], default = "cargo-gpu", type = "string" } [conditional.'integration != "spirv-builder"'] ignore = [ "rust-toolchain.toml" ] + +[conditional.'api == "ash"'] +ignore = [ "mygraphics/src/wgpu_renderer" ] + +[conditional.'api == "wgpu"'] +ignore = [ "mygraphics/src/ash_renderer" ] diff --git a/graphics/mygraphics/Cargo.toml b/graphics/mygraphics/Cargo.toml index 38d9e61..0ce4276 100644 --- a/graphics/mygraphics/Cargo.toml +++ b/graphics/mygraphics/Cargo.toml @@ -17,6 +17,9 @@ mygraphics-shaders = { path = "../mygraphics-shaders" } # API ash.workspace = true ash-window.workspace = true +wgpu.workspace = true +pollster.workspace = true +env_logger.workspace = true # other raw-window-handle.workspace = true diff --git a/graphics/mygraphics/Cargo.toml.liquid b/graphics/mygraphics/Cargo.toml.liquid index 4ecf8ff..209002e 100644 --- a/graphics/mygraphics/Cargo.toml.liquid +++ b/graphics/mygraphics/Cargo.toml.liquid @@ -18,20 +18,34 @@ use-compiled-tools = ["spirv-builder/use-compiled-tools"] {% endif -%} [dependencies] +# shader crate mygraphics-shaders = { path = "../mygraphics-shaders" } +# API +{% if api == "ash" -%} ash.workspace = true ash-window.workspace = true +{%- endif -%} +{%- if api == "wgpu" -%} +wgpu.workspace = true +pollster.workspace = true +env_logger.workspace = true +{%- endif %} + +# other raw-window-handle.workspace = true winit.workspace = true anyhow.workspace = true bytemuck.workspace = true [build-dependencies] +# rust-gpu {% if integration == "spirv-builder" -%} spirv-builder.workspace = true -{% endif -%} -{% if integration == "cargo-gpu" -%} +{%- endif -%} +{%- if integration == "cargo-gpu" -%} cargo-gpu.workspace = true -{% endif -%} +{%- endif %} + +# other anyhow.workspace = true diff --git a/graphics/mygraphics/src/bin/wgpu.rs b/graphics/mygraphics/src/bin/wgpu.rs new file mode 100644 index 0000000..7e06281 --- /dev/null +++ b/graphics/mygraphics/src/bin/wgpu.rs @@ -0,0 +1,3 @@ +pub fn main() -> anyhow::Result<()> { + mygraphics::wgpu_renderer::main() +} diff --git a/graphics/mygraphics/src/lib.rs b/graphics/mygraphics/src/lib.rs index 73ba8a6..bde0fc5 100644 --- a/graphics/mygraphics/src/lib.rs +++ b/graphics/mygraphics/src/lib.rs @@ -72,3 +72,4 @@ pub mod ash_renderer; pub mod util; +pub mod wgpu_renderer; diff --git a/graphics/mygraphics/src/lib.rs.liquid b/graphics/mygraphics/src/lib.rs.liquid new file mode 100644 index 0000000..22e2631 --- /dev/null +++ b/graphics/mygraphics/src/lib.rs.liquid @@ -0,0 +1,79 @@ +// FIXME(eddyb) update/review these lints. +// +// BEGIN - Embark standard lints v0.4 +// do not change or add/remove here, but one can add exceptions after this section +// for more info see: +//#![deny(unsafe_code)] // impractical in this crate dealing with unsafe `ash` +#![warn( + clippy::all, + clippy::await_holding_lock, + clippy::char_lit_as_u8, + clippy::checked_conversions, + clippy::dbg_macro, + clippy::debug_assert_with_mut_call, + clippy::doc_markdown, + clippy::empty_enum, + clippy::enum_glob_use, + clippy::exit, + clippy::expl_impl_clone_on_copy, + clippy::explicit_deref_methods, + clippy::explicit_into_iter_loop, + clippy::fallible_impl_from, + clippy::filter_map_next, + clippy::float_cmp_const, + clippy::fn_params_excessive_bools, + clippy::if_let_mutex, + clippy::implicit_clone, + clippy::imprecise_flops, + clippy::inefficient_to_string, + clippy::invalid_upcast_comparisons, + clippy::large_types_passed_by_value, + clippy::let_unit_value, + clippy::linkedlist, + clippy::lossy_float_literal, + clippy::macro_use_imports, + clippy::manual_ok_or, + clippy::map_err_ignore, + clippy::map_flatten, + clippy::map_unwrap_or, + clippy::match_same_arms, + clippy::match_wildcard_for_single_variants, + clippy::mem_forget, + clippy::mut_mut, + clippy::mutex_integer, + clippy::needless_borrow, + clippy::needless_continue, + clippy::option_option, + clippy::path_buf_push_overwrite, + clippy::ptr_as_ptr, + clippy::ref_option_ref, + clippy::rest_pat_in_fully_bound_structs, + clippy::same_functions_in_if_condition, + clippy::semicolon_if_nothing_returned, + clippy::string_add_assign, + clippy::string_add, + clippy::string_lit_as_bytes, + clippy::string_to_string, + clippy::todo, + clippy::trait_duplication_in_bounds, + clippy::unimplemented, + clippy::unnested_or_patterns, + clippy::unused_self, + clippy::useless_transmute, + clippy::verbose_file_reads, + clippy::zero_sized_map_values, + future_incompatible, + nonstandard_style, + rust_2018_idioms +)] +// END - Embark standard lints v0.4 +// crate-specific exceptions: +// #![allow()] + +{% if api == "ash" -%} +pub mod ash_renderer; +{% endif -%} +pub mod util; +{% if api == "wgpu" -%} +pub mod wgpu_renderer; +{% endif -%} diff --git a/graphics/mygraphics/src/main.rs.liquid b/graphics/mygraphics/src/main.rs.liquid new file mode 100644 index 0000000..8323899 --- /dev/null +++ b/graphics/mygraphics/src/main.rs.liquid @@ -0,0 +1,8 @@ +pub fn main() -> anyhow::Result<()> { + {%- if api == "ash" %} + mygraphics::ash_renderer::main() + {%- endif -%} + {%- if api == "wgpu" %} + mygraphics::wgpu_renderer::main() + {%- endif %} +} diff --git a/graphics/mygraphics/src/wgpu_renderer/mod.rs b/graphics/mygraphics/src/wgpu_renderer/mod.rs new file mode 100644 index 0000000..f9a670f --- /dev/null +++ b/graphics/mygraphics/src/wgpu_renderer/mod.rs @@ -0,0 +1,104 @@ +use crate::wgpu_renderer::swapchain::MySwapchainManager; +use anyhow::Context; +use mygraphics_shaders::ShaderConstants; +use std::sync::Arc; +use winit::event::{Event, WindowEvent}; +use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop}; + +mod render_pipeline; +mod renderer; +mod swapchain; + +pub fn main() -> anyhow::Result<()> { + env_logger::init(); + pollster::block_on(main_inner()) +} + +pub async fn main_inner() -> anyhow::Result<()> { + // env_logger::init(); + let event_loop = EventLoop::new()?; + // FIXME(eddyb) incomplete `winit` upgrade, follow the guides in: + // https://github.com/rust-windowing/winit/releases/tag/v0.30.0 + #[allow(deprecated)] + let window = Arc::new( + event_loop.create_window( + winit::window::Window::default_attributes() + .with_title("Rust GPU - wgpu") + .with_inner_size(winit::dpi::LogicalSize::new( + f64::from(1280), + f64::from(720), + )), + )?, + ); + + let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor::from_env_or_default()); + let surface = instance.create_surface(window.clone())?; + let adapter = + wgpu::util::initialize_adapter_from_env_or_default(&instance, Some(&surface)).await?; + + let required_features = + wgpu::Features::PUSH_CONSTANTS | wgpu::Features::EXPERIMENTAL_PASSTHROUGH_SHADERS; + let required_limits = wgpu::Limits { + max_push_constant_size: 128, + ..Default::default() + }; + let (device, queue) = adapter + .request_device(&wgpu::DeviceDescriptor { + label: None, + required_features, + required_limits, + experimental_features: unsafe { wgpu::ExperimentalFeatures::enabled() }, + memory_hints: wgpu::MemoryHints::Performance, + trace: Default::default(), + }) + .await + .context("Failed to create device")?; + + let mut swapchain = MySwapchainManager::new(adapter.clone(), device.clone(), window, surface); + let renderer = renderer::MyRenderer::new(device, queue, swapchain.format())?; + + let start = std::time::Instant::now(); + let mut event_handler = + move |event: Event<_>, event_loop_window_target: &ActiveEventLoop| match event { + Event::AboutToWait => swapchain.render(|render_target| { + renderer.render( + &ShaderConstants { + time: start.elapsed().as_secs_f32(), + width: render_target.texture().width(), + height: render_target.texture().height(), + }, + render_target, + ); + }), + Event::WindowEvent { event, .. } => { + match event { + WindowEvent::KeyboardInput { + event: + winit::event::KeyEvent { + logical_key: + winit::keyboard::Key::Named(winit::keyboard::NamedKey::Escape), + state: winit::event::ElementState::Pressed, + .. + }, + .. + } + | WindowEvent::CloseRequested => event_loop_window_target.exit(), + WindowEvent::Resized(_) => swapchain.should_recreate(), + _ => {} + } + Ok(()) + } + _ => { + event_loop_window_target.set_control_flow(ControlFlow::Poll); + Ok(()) + } + }; + + // FIXME(eddyb) incomplete `winit` upgrade, follow the guides in: + // https://github.com/rust-windowing/winit/releases/tag/v0.30.0 + #[allow(deprecated)] + event_loop.run(move |event, event_loop_window_target| { + event_handler(event, event_loop_window_target).unwrap(); + })?; + Ok(()) +} diff --git a/graphics/mygraphics/src/wgpu_renderer/render_pipeline.rs b/graphics/mygraphics/src/wgpu_renderer/render_pipeline.rs new file mode 100644 index 0000000..f100339 --- /dev/null +++ b/graphics/mygraphics/src/wgpu_renderer/render_pipeline.rs @@ -0,0 +1,92 @@ +use mygraphics_shaders::ShaderConstants; +use wgpu::{ + ColorTargetState, ColorWrites, Device, FragmentState, FrontFace, MultisampleState, + PipelineLayoutDescriptor, PolygonMode, PrimitiveState, PrimitiveTopology, PushConstantRange, + RenderPass, RenderPipeline, RenderPipelineDescriptor, ShaderModuleDescriptorPassthrough, + ShaderRuntimeChecks, ShaderStages, TextureFormat, VertexState, +}; + +pub struct MyRenderPipeline { + pipeline: RenderPipeline, +} + +impl MyRenderPipeline { + pub fn new(device: &Device, out_format: TextureFormat) -> anyhow::Result { + // Workaround in wgpu 27.0.1 where the macro expansion of `include_spirv_raw!` doesn't compile + // see https://github.com/gfx-rs/wgpu/pull/8250 + // let module = unsafe { + // device.create_shader_module_passthrough(include_spirv_raw!(env!("SHADER_SPV_PATH"))) + // }; + let module = unsafe { + device.create_shader_module_passthrough(ShaderModuleDescriptorPassthrough { + label: Some(env!("SHADER_SPV_PATH")), + entry_point: "".to_owned(), + num_workgroups: (0, 0, 0), + runtime_checks: ShaderRuntimeChecks::unchecked(), + spirv: Some(wgpu::util::make_spirv_raw(include_bytes!(env!( + "SHADER_SPV_PATH" + )))), + dxil: None, + msl: None, + hlsl: None, + glsl: None, + wgsl: None, + }) + }; + + let layout = device.create_pipeline_layout(&PipelineLayoutDescriptor { + label: Some("MyRenderPipeline layout"), + bind_group_layouts: &[], + push_constant_ranges: &[PushConstantRange { + stages: ShaderStages::VERTEX_FRAGMENT, + range: 0..size_of::() as u32, + }], + }); + + Ok(Self { + pipeline: device.create_render_pipeline(&RenderPipelineDescriptor { + label: Some("MyRenderPipeline"), + layout: Some(&layout), + vertex: VertexState { + module: &module, + entry_point: Some("main_vs"), + compilation_options: Default::default(), + buffers: &[], + }, + primitive: PrimitiveState { + topology: PrimitiveTopology::TriangleList, + strip_index_format: None, + front_face: FrontFace::Ccw, + cull_mode: None, + unclipped_depth: false, + polygon_mode: PolygonMode::Fill, + conservative: false, + }, + depth_stencil: None, + multisample: MultisampleState::default(), + fragment: Some(FragmentState { + module: &module, + entry_point: Some("main_fs"), + compilation_options: Default::default(), + targets: &[Some(ColorTargetState { + format: out_format, + blend: None, + write_mask: ColorWrites::ALL, + })], + }), + multiview: None, + cache: None, + }), + }) + } + + pub fn draw(&self, rpass: &mut RenderPass<'_>, shader_constants: &ShaderConstants) { + rpass.set_pipeline(&self.pipeline); + rpass.set_push_constants( + ShaderStages::VERTEX_FRAGMENT, + 0, + bytemuck::bytes_of(shader_constants), + ); + rpass.draw(0..3, 0..1); + } +} diff --git a/graphics/mygraphics/src/wgpu_renderer/renderer.rs b/graphics/mygraphics/src/wgpu_renderer/renderer.rs new file mode 100644 index 0000000..c5213df --- /dev/null +++ b/graphics/mygraphics/src/wgpu_renderer/renderer.rs @@ -0,0 +1,51 @@ +use crate::wgpu_renderer::render_pipeline::MyRenderPipeline; +use mygraphics_shaders::ShaderConstants; +use wgpu::wgt::CommandEncoderDescriptor; +use wgpu::{ + Color, Device, LoadOp, Operations, Queue, RenderPassColorAttachment, RenderPassDescriptor, + StoreOp, TextureFormat, TextureView, +}; + +pub struct MyRenderer { + pub device: Device, + pub queue: Queue, + pipeline: MyRenderPipeline, +} + +impl MyRenderer { + pub fn new(device: Device, queue: Queue, out_format: TextureFormat) -> anyhow::Result { + Ok(Self { + pipeline: MyRenderPipeline::new(&device, out_format)?, + device, + queue, + }) + } + + pub fn render(&self, shader_constants: &ShaderConstants, output: TextureView) { + let mut cmd = self + .device + .create_command_encoder(&CommandEncoderDescriptor { + label: Some("main draw"), + }); + + let mut rpass = cmd.begin_render_pass(&RenderPassDescriptor { + label: Some("main renderpass"), + color_attachments: &[Some(RenderPassColorAttachment { + view: &output, + depth_slice: None, + resolve_target: None, + ops: Operations { + load: LoadOp::Clear(Color::BLACK), + store: StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, + }); + self.pipeline.draw(&mut rpass, shader_constants); + drop(rpass); + + self.queue.submit(std::iter::once(cmd.finish())); + } +} diff --git a/graphics/mygraphics/src/wgpu_renderer/swapchain.rs b/graphics/mygraphics/src/wgpu_renderer/swapchain.rs new file mode 100644 index 0000000..ed1b8d1 --- /dev/null +++ b/graphics/mygraphics/src/wgpu_renderer/swapchain.rs @@ -0,0 +1,117 @@ +use anyhow::Context; +use std::sync::Arc; +use wgpu::{Adapter, Device, Surface, SurfaceError, TextureFormat, TextureView}; +use winit::dpi::PhysicalSize; +use winit::window::Window; + +pub struct MySwapchainManager<'a> { + adapter: Adapter, + device: Device, + window: Arc, + surface: Surface<'a>, + format: TextureFormat, + + // state below + active: Option, + should_recreate: bool, +} + +pub struct ActiveConfiguration { + size: PhysicalSize, +} + +impl<'a> MySwapchainManager<'a> { + pub fn new( + adapter: Adapter, + device: Device, + window: Arc, + surface: Surface<'a>, + ) -> Self { + let caps = surface.get_capabilities(&adapter); + Self { + adapter, + device, + window, + surface, + format: caps.formats[0], + active: None, + should_recreate: true, + } + } + + #[inline] + pub fn should_recreate(&mut self) { + self.should_recreate = true; + } + + pub fn format(&self) -> TextureFormat { + self.format + } + + pub fn render(&mut self, f: impl FnOnce(TextureView) -> R) -> anyhow::Result { + let size = self.window.inner_size(); + if let Some(active) = &self.active { + if active.size != size { + self.should_recreate(); + } + } else { + self.should_recreate(); + } + + const RECREATE_ATTEMPTS: u32 = 10; + for _ in 0..RECREATE_ATTEMPTS { + if self.should_recreate { + self.should_recreate = false; + self.configure_surface(size)?; + } + + match self.surface.get_current_texture() { + Ok(surface_texture) => { + if surface_texture.suboptimal { + self.should_recreate = true; + } + let output_view = + surface_texture + .texture + .create_view(&wgpu::TextureViewDescriptor { + format: Some(self.format), + ..wgpu::TextureViewDescriptor::default() + }); + let r = f(output_view); + surface_texture.present(); + return Ok(r); + } + Err(SurfaceError::Outdated | SurfaceError::Lost) => { + self.should_recreate = true; + } + Err(e) => { + anyhow::bail!("get_current_texture() failed: {e}") + } + }; + } + anyhow::bail!( + "looped {RECREATE_ATTEMPTS} times trying to acquire swapchain image and failed repeatedly!" + ); + } + + fn configure_surface(&mut self, size: PhysicalSize) -> anyhow::Result<()> { + let mut surface_config = self + .surface + .get_default_config(&self.adapter, size.width, size.height) + .with_context(|| { + format!( + "Incompatible adapter for surface, returned capabilities: {:?}", + self.surface.get_capabilities(&self.adapter) + ) + })?; + + // force srgb surface format + surface_config.view_formats.push(self.format); + // limit framerate to vsync + surface_config.present_mode = wgpu::PresentMode::AutoVsync; + self.surface.configure(&self.device, &surface_config); + + self.active = Some(ActiveConfiguration { size }); + Ok(()) + } +}