From 168ecfa5c0d29087fddd0fe7dfda2db3868f7a36 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Oct 2023 13:26:36 +0000 Subject: [PATCH] Bump wgpu from 0.17.1 to 0.18.0 (#123) * Bump wgpu from 0.17.1 to 0.18.0 Bumps [wgpu](https://github.com/gfx-rs/wgpu) from 0.17.1 to 0.18.0. - [Release notes](https://github.com/gfx-rs/wgpu/releases) - [Changelog](https://github.com/gfx-rs/wgpu/blob/trunk/CHANGELOG.md) - [Commits](https://github.com/gfx-rs/wgpu/compare/v0.17.1...v0.18.0) --- updated-dependencies: - dependency-name: wgpu dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Fix breaking changes --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Hugo Woodiwiss --- Cargo.lock | 202 +++-- wgpu-testbed-lib/Cargo.toml | 2 +- wgpu-testbed-lib/src/model.rs | 1 + wgpu-testbed-lib/src/state.rs | 1418 +++++++++++++++++---------------- 4 files changed, 863 insertions(+), 760 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b2b6fae..f377fb0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -410,6 +410,12 @@ dependencies = [ "termcolor", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "errno" version = "0.3.1" @@ -450,6 +456,18 @@ dependencies = [ "miniz_oxide 0.7.1", ] +[[package]] +name = "flume" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +dependencies = [ + "futures-core", + "futures-sink", + "nanorand", + "spin", +] + [[package]] name = "foreign-types" version = "0.3.2" @@ -606,6 +624,17 @@ version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" +[[package]] +name = "gl_generator" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" +dependencies = [ + "khronos_api", + "log", + "xml-rs", +] + [[package]] name = "glob" version = "0.3.1" @@ -614,9 +643,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "glow" -version = "0.12.3" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca0fe580e4b60a8ab24a868bc08e2f03cbcb20d3d676601fa909386713333728" +checksum = "886c2a30b160c4c6fec8f987430c26b526b7988ca71f664e6a699ddf6f9601e4" dependencies = [ "js-sys", "slotmap", @@ -624,6 +653,15 @@ dependencies = [ "web-sys", ] +[[package]] +name = "glutin_wgl_sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8098adac955faa2d31079b65dc48841251f69efd3ac25477903fc424362ead" +dependencies = [ + "gl_generator", +] + [[package]] name = "gpu-alloc" version = "0.6.0" @@ -645,12 +683,13 @@ dependencies = [ [[package]] name = "gpu-allocator" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce95f9e2e11c2c6fadfce42b5af60005db06576f231f5c92550fdded43c423e8" +checksum = "40fe17c8a05d60c38c0a4e5a3c802f2f1ceb66b76c67d96ffb34bef0475a7fad" dependencies = [ "backtrace", "log", + "presser", "thiserror", "winapi", "windows", @@ -664,7 +703,7 @@ checksum = "0b0c02e1ba0bdb14e965058ca34e09c020f8e507a760df1121728e0aef68d57a" dependencies = [ "bitflags 1.3.2", "gpu-descriptor-types", - "hashbrown", + "hashbrown 0.12.3", ] [[package]] @@ -685,6 +724,12 @@ dependencies = [ "ahash 0.7.6", ] +[[package]] +name = "hashbrown" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" + [[package]] name = "hassle-rs" version = "0.10.0" @@ -740,7 +785,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" +dependencies = [ + "equivalent", + "hashbrown 0.14.2", ] [[package]] @@ -810,15 +865,21 @@ dependencies = [ [[package]] name = "khronos-egl" -version = "4.1.0" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c2352bd1d0bceb871cb9d40f24360c8133c11d7486b68b5381c1dd1a32015e3" +checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" dependencies = [ "libc", - "libloading 0.7.4", + "libloading 0.8.0", "pkg-config", ] +[[package]] +name = "khronos_api" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" + [[package]] name = "lazy_static" version = "1.4.0" @@ -908,9 +969,9 @@ dependencies = [ [[package]] name = "metal" -version = "0.26.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "623b5e6cefd76e58f774bd3cc0c6f5c7615c58c03a97815245a25c3c9bdee318" +checksum = "c43f73953f8cbe511f021b58f18c3ce1c3d1ae13fe953293e13345bf83217f25" dependencies = [ "bitflags 2.2.1", "block", @@ -960,15 +1021,15 @@ dependencies = [ [[package]] name = "naga" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ceaaa4eedaece7e4ec08c55c640ba03dbb73fb812a6570a59bcf1930d0f70e" +checksum = "61d829abac9f5230a85d8cc83ec0879b4c09790208ae25b5ea031ef84562e071" dependencies = [ "bit-set", "bitflags 2.2.1", "codespan-reporting", "hexf-parse", - "indexmap", + "indexmap 2.0.2", "log", "num-traits", "rustc-hash", @@ -978,6 +1039,15 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "nanorand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" +dependencies = [ + "getrandom", +] + [[package]] name = "ndk" version = "0.7.0" @@ -1149,9 +1219,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.17.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "orbclient" @@ -1237,6 +1307,12 @@ dependencies = [ "miniz_oxide 0.7.1", ] +[[package]] +name = "presser" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" + [[package]] name = "proc-macro-crate" version = "1.3.1" @@ -1424,6 +1500,15 @@ dependencies = [ "wayland-protocols", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + [[package]] name = "spirv" version = "0.2.0+1.5.4" @@ -1543,7 +1628,7 @@ version = "0.19.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" dependencies = [ - "indexmap", + "indexmap 1.9.3", "toml_datetime", "winnow", ] @@ -1741,12 +1826,13 @@ dependencies = [ [[package]] name = "wgpu" -version = "0.17.1" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed547920565c56c7a29afb4538ac5ae5048865a5d2f05bff3ad4fbeb921a9a2c" +checksum = "30e7d227c9f961f2061c26f4cb0fbd4df0ef37e056edd0931783599d6c94ef24" dependencies = [ "arrayvec", "cfg-if", + "flume", "js-sys", "log", "naga", @@ -1765,9 +1851,9 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecf7454d9386f602f7399225c92dd2fbdcde52c519bc8fb0bd6fbeb388075dc2" +checksum = "837e02ddcdc6d4a9b56ba4598f7fd4202a7699ab03f6ef4dcdebfad2c966aea6" dependencies = [ "arrayvec", "bit-vec", @@ -1788,9 +1874,9 @@ dependencies = [ [[package]] name = "wgpu-hal" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6654a13885a17f475e8324efb46dc6986d7aaaa98353330f8de2077b153d0101" +checksum = "1e30b9a8155c83868e82a8c5d3ce899de6c3961d2ef595de8fc168a1677fc2d8" dependencies = [ "android_system_properties", "arrayvec", @@ -1801,6 +1887,7 @@ dependencies = [ "core-graphics-types", "d3d12", "glow", + "glutin_wgl_sys", "gpu-alloc", "gpu-allocator", "gpu-descriptor", @@ -1813,6 +1900,7 @@ dependencies = [ "metal", "naga", "objc", + "once_cell", "parking_lot", "profiling", "range-alloc", @@ -1861,9 +1949,9 @@ dependencies = [ [[package]] name = "wgpu-types" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee64d7398d0c2f9ca48922c902ef69c42d000c759f3db41e355f4a570b052b67" +checksum = "0d5ed5f0edf0de351fe311c53304986315ce866f394a2e6df0c4b3c70774bcdd" dependencies = [ "bitflags 2.2.1", "js-sys", @@ -1909,11 +1997,21 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.44.0" +version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e745dab35a0c4c77aa3ce42d595e13d2003d6902d6b08c9ef5fc326d08da12b" +checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" dependencies = [ - "windows-targets 0.42.2", + "windows-core", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-core" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +dependencies = [ + "windows-targets 0.48.5", ] [[package]] @@ -1931,7 +2029,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.0", + "windows-targets 0.48.5", ] [[package]] @@ -1951,17 +2049,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] @@ -1972,9 +2070,9 @@ checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_msvc" @@ -1984,9 +2082,9 @@ checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_i686_gnu" @@ -1996,9 +2094,9 @@ checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_msvc" @@ -2008,9 +2106,9 @@ checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_x86_64_gnu" @@ -2020,9 +2118,9 @@ checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnullvm" @@ -2032,9 +2130,9 @@ checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_msvc" @@ -2044,9 +2142,9 @@ checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winit" diff --git a/wgpu-testbed-lib/Cargo.toml b/wgpu-testbed-lib/Cargo.toml index b829d3d..c591ba5 100644 --- a/wgpu-testbed-lib/Cargo.toml +++ b/wgpu-testbed-lib/Cargo.toml @@ -13,7 +13,7 @@ cgmath = "0.18" env_logger = "0.10.0" log = "0.4" futures = "0.3" -wgpu = "0.17.1" +wgpu = "0.18.0" bytemuck = { version = "1.14.0", features = [ "derive" ] } anyhow = "1.0" tobj = { version = "4.0.0", features = ["async"]} diff --git a/wgpu-testbed-lib/src/model.rs b/wgpu-testbed-lib/src/model.rs index 7fd9839..4d11782 100644 --- a/wgpu-testbed-lib/src/model.rs +++ b/wgpu-testbed-lib/src/model.rs @@ -393,6 +393,7 @@ impl ModelLoader { { let mut pass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor { label: Some("Compute Pass"), + timestamp_writes: None, }); pass.set_pipeline(&self.pipeline); pass.set_bind_group(0, &calc_bind_group, &[]); diff --git a/wgpu-testbed-lib/src/state.rs b/wgpu-testbed-lib/src/state.rs index 92a1630..a57b381 100644 --- a/wgpu-testbed-lib/src/state.rs +++ b/wgpu-testbed-lib/src/state.rs @@ -1,707 +1,711 @@ -use std::collections::HashMap; -use std::iter::FromIterator; - -use crate::camera::CameraController; -use crate::file_reader::FileReader; -use crate::instance::InstanceRaw; -use crate::pipeline::{self, create_render_pipeline}; -use crate::uniform::Uniforms; -use crate::{instance::Instance, light::Light}; -use cgmath::*; - -use wgpu::util::DeviceExt; -use wgpu::{InstanceDescriptor, PowerPreference, SamplerBindingType}; -use winit::{event::WindowEvent, window::Window}; - -use crate::camera::Camera; -use crate::model::{self, DrawLight, Material, Mesh, ModelLoader, QuadVertex}; -use crate::model::{DrawModel, Model}; -use crate::texture::{self, Texture}; -use crate::vertex::Vertex; - -fn rgb_to_normalized(r: u8, g: u8, b: u8) -> wgpu::Color { - // Wish this could be const, but cant do fp arithmetic in const fn - wgpu::Color { - r: r as f64 / 255f64, - g: g as f64 / 255f64, - b: b as f64 / 255f64, - a: 1.0, - } -} - -const INSTANCES_PER_ROW: u32 = 100; -const INSTANCE_DISPLACEMENT: cgmath::Vector3 = cgmath::Vector3::new( - INSTANCES_PER_ROW as f32 * 0.5, - 0.0, - INSTANCES_PER_ROW as f32 * 0.5, -); - -const RENDER_SCALE: f32 = 2.0; -pub struct State { - surface: wgpu::Surface, - device: wgpu::Device, - queue: wgpu::Queue, - surface_config: wgpu::SurfaceConfiguration, - pub size: winit::dpi::PhysicalSize, - bg_color: wgpu::Color, - deferred_render_pipeline: wgpu::RenderPipeline, - camera: Camera, - uniforms: Uniforms, - uniform_buffer: wgpu::Buffer, - uniform_bind_group: wgpu::BindGroup, - camera_controller: CameraController, - instances: Vec, - instance_buffer: wgpu::Buffer, - depth_texture: Texture, - obj_model: Model, - screen_quad: Mesh, - render_material: Material, - light: Light, - light_buffer: wgpu::Buffer, - light_bind_group: wgpu::BindGroup, - light_render_pipeline: wgpu::RenderPipeline, - output_render_pipeline: wgpu::RenderPipeline, -} - -impl State { - pub async fn new(window: &Window) -> Self { - let size = window.inner_size(); - let instance_desc = InstanceDescriptor::default(); - let instance = wgpu::Instance::new(instance_desc); - let surface = unsafe { - instance - .create_surface(window) - .expect("Expected surface from window") - }; - let adapter = instance - .request_adapter(&wgpu::RequestAdapterOptions { - compatible_surface: Some(&surface), - power_preference: PowerPreference::HighPerformance, - force_fallback_adapter: false, - }) - .await - .expect("Could not create adapter instance!"); - - let (device, queue) = adapter - .request_device( - &wgpu::DeviceDescriptor { - features: wgpu::Features::empty(), - limits: wgpu::Limits::default(), - label: None, - }, - None, - ) - .await - .expect("Could not get device from adapter!"); - let capabilities = surface.get_capabilities(&adapter); - let surface_config = wgpu::SurfaceConfiguration { - usage: wgpu::TextureUsages::RENDER_ATTACHMENT, - format: capabilities.formats[0], - width: size.width, - height: size.height, - present_mode: wgpu::PresentMode::Fifo, - alpha_mode: wgpu::CompositeAlphaMode::Auto, - view_formats: vec![wgpu::TextureFormat::Bgra8UnormSrgb], - }; - - surface.configure(&device, &surface_config); - - let texture_bind_group_layout = - device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - label: Some("Texture bind group layout"), - entries: &[ - wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Texture { - sample_type: wgpu::TextureSampleType::Float { filterable: true }, - view_dimension: wgpu::TextureViewDimension::D2, - multisampled: false, - }, - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 1, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Sampler(SamplerBindingType::Filtering), - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 2, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Texture { - sample_type: wgpu::TextureSampleType::Float { filterable: true }, - view_dimension: wgpu::TextureViewDimension::D2, - multisampled: false, - }, - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 3, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Sampler(SamplerBindingType::Filtering), - count: None, - }, - ], - }); - - let camera = Camera { - eye: (0.0, 1.0, 2.0).into(), - target: (0.0, 0.0, 0.0).into(), - up: (0.0, 1.0, 0.0).into(), - aspect: surface_config.width as f32 / surface_config.height as f32, - fovy: 45.0, - znear: 0.1, - zfar: 1000.0, - }; - - let camera_controller = CameraController::new(0.2); - - let mut uniforms = Uniforms::new(); - uniforms.update_view_proj(&camera); - - let uniform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { - label: Some("Uniform Buffer"), - contents: bytemuck::bytes_of(&uniforms), - usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, - }); - - let uniform_bind_group_layout = - device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - label: Some("Uniform Bind Group Layout"), - entries: &[wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: None, - }, - count: None, - }], - }); - - let uniform_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - label: Some("Uniform Bind Group"), - layout: &uniform_bind_group_layout, - entries: &[wgpu::BindGroupEntry { - binding: 0, - resource: uniform_buffer.as_entire_binding(), - }], - }); - - // Cornflour blue, because I 'member XNA - let bg_color = rgb_to_normalized(0, 0, 0); - - let light = Light { - position: [2.0, 2.0, 2.0], - _padding: 0.0, - colour: [1.0, 1.0, 1.0], - _padding2: 0.0, - }; - - let light_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { - label: Some("Light buffer"), - contents: bytemuck::cast_slice(&[light]), - usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, - }); - - let light_bind_group_layout = - device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - entries: &[wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: None, - }, - count: None, - }], - label: None, - }); - - let light_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: &light_bind_group_layout, - entries: &[wgpu::BindGroupEntry { - binding: 0, - resource: light_buffer.as_entire_binding(), - }], - label: None, - }); - - let render_pipeline_layout = - device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - label: Some("Render Pipeline Layout"), - bind_group_layouts: &[ - &texture_bind_group_layout, - &uniform_bind_group_layout, - &light_bind_group_layout, - ], - push_constant_ranges: &[], - }); - - let model_loader = ModelLoader::new(&device).await; - - let obj_model = model_loader - .load( - &device, - &queue, - &texture_bind_group_layout, - "resources/cube/cube.obj", - ) - .await - .unwrap(); - - const SPACE_BETWEEN: f32 = 3.0; - let instances = (0..INSTANCES_PER_ROW) - .flat_map(|z| { - (0..INSTANCES_PER_ROW).map(move |x| { - let x = SPACE_BETWEEN * (x as f32 - INSTANCES_PER_ROW as f32 / 2.0); - let z = SPACE_BETWEEN * (z as f32 - INSTANCES_PER_ROW as f32 / 2.0); - - let position = cgmath::Vector3 { - x: x as f32, - y: 0.0, - z: z as f32, - } - INSTANCE_DISPLACEMENT; - - let rotation = if position.is_zero() { - cgmath::Quaternion::from_axis_angle( - cgmath::Vector3::unit_z(), - cgmath::Deg(0.0), - ) - } else { - cgmath::Quaternion::from_axis_angle( - position.clone().normalize(), - cgmath::Deg(45.0), - ) - }; - - Instance { position, rotation } - }) - }) - .collect::>(); - - let instance_data = instances.iter().map(Instance::to_raw).collect::>(); - - let instance_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { - label: Some("Instance Buffer"), - contents: bytemuck::cast_slice(instance_data.as_slice()), - usage: wgpu::BufferUsages::VERTEX, - }); - - let depth_texture = - Texture::create_depth_texture(&device, &surface_config, RENDER_SCALE, "Depth Texture"); - let shader_buffer = FileReader::read_file("shaders/shader.wgsl").await; - let shader_str = - std::str::from_utf8(shader_buffer.as_slice()).expect("Failed to load shader"); - - let deferred_render_pipeline = { - let shader = wgpu::ShaderModuleDescriptor { - label: Some("Normal Shader"), - source: wgpu::ShaderSource::Wgsl(shader_str.into()), - }; - - pipeline::create_render_pipeline( - &device, - &render_pipeline_layout, - Some(texture::Texture::DEPTH_FORMAT), - &[model::ModelVertex::desc(), InstanceRaw::desc()], - shader, - &[ - Some(wgpu::ColorTargetState { - format: surface_config.format, - blend: Some(wgpu::BlendState { - color: wgpu::BlendComponent::REPLACE, - alpha: wgpu::BlendComponent::REPLACE, - }), - write_mask: wgpu::ColorWrites::ALL, - }), - Some(wgpu::ColorTargetState { - format: surface_config.format, - blend: Some(wgpu::BlendState { - color: wgpu::BlendComponent::REPLACE, - alpha: wgpu::BlendComponent::REPLACE, - }), - write_mask: wgpu::ColorWrites::ALL, - }), - ], - Some("Render Pipeline"), - ) - }; - - let light_render_pipeline = { - let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - label: Some("Light pipeline layout desc"), - bind_group_layouts: &[&uniform_bind_group_layout, &light_bind_group_layout], - push_constant_ranges: &[], - }); - let shader_buffer = FileReader::read_file("shaders/light.wgsl").await; - let shader_str = - std::str::from_utf8(shader_buffer.as_slice()).expect("Failed to load shader"); - - let shader = wgpu::ShaderModuleDescriptor { - label: Some("Light Shader"), - source: wgpu::ShaderSource::Wgsl(shader_str.into()), - }; - - pipeline::create_render_pipeline( - &device, - &layout, - Some(texture::Texture::DEPTH_FORMAT), - &[model::ModelVertex::desc()], - shader, - &[ - Some(wgpu::ColorTargetState { - format: surface_config.format, - blend: Some(wgpu::BlendState { - color: wgpu::BlendComponent::REPLACE, - alpha: wgpu::BlendComponent::REPLACE, - }), - write_mask: wgpu::ColorWrites::ALL, - }), - Some(wgpu::ColorTargetState { - format: surface_config.format, - blend: Some(wgpu::BlendState { - color: wgpu::BlendComponent::REPLACE, - alpha: wgpu::BlendComponent::REPLACE, - }), - write_mask: wgpu::ColorWrites::ALL, - }), - ], - Some("Light render pipeline"), - ) - }; - - let output_bindgroup_layout = - device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - entries: &[ - wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Texture { - sample_type: wgpu::TextureSampleType::Float { filterable: true }, - view_dimension: wgpu::TextureViewDimension::D2, - multisampled: false, - }, - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 1, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Sampler(SamplerBindingType::Filtering), - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 2, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Texture { - sample_type: wgpu::TextureSampleType::Float { filterable: true }, - view_dimension: wgpu::TextureViewDimension::D2, - multisampled: false, - }, - count: None, - }, - wgpu::BindGroupLayoutEntry { - binding: 3, - visibility: wgpu::ShaderStages::FRAGMENT, - ty: wgpu::BindingType::Sampler(SamplerBindingType::Filtering), - count: None, - }, - ], - label: None, - }); - - let shader_buffer = FileReader::read_file("shaders/draw_deferred.wgsl").await; - let shader_str = - std::str::from_utf8(shader_buffer.as_slice()).expect("Failed to load shader"); - - let output_render_pipeline = { - let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - label: Some("Deferred pipeline layout desc"), - bind_group_layouts: &[&output_bindgroup_layout], - push_constant_ranges: &[], - }); - - let shader = wgpu::ShaderModuleDescriptor { - label: Some("Output Shader"), - source: wgpu::ShaderSource::Wgsl(shader_str.into()), - }; - - create_render_pipeline( - &device, - &layout, - None, - &[QuadVertex::desc()], - shader, - &[Some(wgpu::ColorTargetState { - format: surface_config.format, - blend: Some(wgpu::BlendState { - color: wgpu::BlendComponent::REPLACE, - alpha: wgpu::BlendComponent::REPLACE, - }), - write_mask: wgpu::ColorWrites::ALL, - })], - Some("Output Pipeline"), - ) - }; - - let diffuse_texture = Texture::create_render_texture( - &device, - &surface_config, - RENDER_SCALE, - "Deferred Diffuse Surface", - ); - - let specular_texture = Texture::create_render_texture( - &device, - &surface_config, - RENDER_SCALE, - "Deferred Normal Surface", - ); - - let screen_quad = ModelLoader::create_screen_quad_mesh(&device); - - let render_material = { - let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - label: None, - layout: &output_bindgroup_layout, - entries: &[ - wgpu::BindGroupEntry { - binding: 0, - resource: wgpu::BindingResource::TextureView(&diffuse_texture.view), - }, - wgpu::BindGroupEntry { - binding: 1, - resource: wgpu::BindingResource::Sampler(&diffuse_texture.sampler), - }, - wgpu::BindGroupEntry { - binding: 2, - resource: wgpu::BindingResource::TextureView(&specular_texture.view), - }, - wgpu::BindGroupEntry { - binding: 3, - resource: wgpu::BindingResource::Sampler(&specular_texture.sampler), - }, - ], - }); - - Material { - name: String::from("Output Quad Textures"), - textures: HashMap::from_iter([ - ("ss_diffuse".to_owned(), diffuse_texture), - ("ss_specular".to_owned(), specular_texture), - ]), - bind_group, - } - }; - - Self { - surface, - device, - queue, - surface_config, - size, - bg_color, - deferred_render_pipeline, - camera, - uniforms, - uniform_buffer, - uniform_bind_group, - camera_controller, - instances, - instance_buffer, - depth_texture, - obj_model, - light, - light_buffer, - light_bind_group, - light_render_pipeline, - output_render_pipeline, - screen_quad, - render_material, - } - } - - pub fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { - self.size = new_size; - self.surface_config.width = self.size.width; - self.surface_config.height = self.size.height; - self.surface.configure(&self.device, &self.surface_config); - self.depth_texture = Texture::create_depth_texture( - &self.device, - &self.surface_config, - RENDER_SCALE, - "Depth Texture", - ); - self.camera.aspect = self.surface_config.width as f32 / self.surface_config.height as f32; - - let diffuse_texture = Texture::create_render_texture( - &self.device, - &self.surface_config, - RENDER_SCALE, - "Deferred Surface", - ); - - let screen_normal_texture = Texture::create_render_texture( - &self.device, - &self.surface_config, - RENDER_SCALE, - "Deferred Normal Surface", - ); - - self.render_material = { - let bind_group = self.device.create_bind_group(&wgpu::BindGroupDescriptor { - label: None, - layout: &self.output_render_pipeline.get_bind_group_layout(0), - entries: &[ - wgpu::BindGroupEntry { - binding: 0, - resource: wgpu::BindingResource::TextureView(&diffuse_texture.view), - }, - wgpu::BindGroupEntry { - binding: 1, - resource: wgpu::BindingResource::Sampler(&diffuse_texture.sampler), - }, - wgpu::BindGroupEntry { - binding: 2, - resource: wgpu::BindingResource::TextureView(&screen_normal_texture.view), - }, - wgpu::BindGroupEntry { - binding: 3, - resource: wgpu::BindingResource::Sampler(&screen_normal_texture.sampler), - }, - ], - }); - - Material { - name: String::from("Output Quad Textures"), - textures: HashMap::from_iter([ - ("ss_diffuse".to_owned(), diffuse_texture), - ("ss_specular".to_owned(), screen_normal_texture), - ]), - bind_group, - } - }; - } - - pub fn input(&mut self, event: &WindowEvent) -> bool { - self.camera_controller.process_inputs(event) - } - - pub fn update(&mut self) { - let old_position: cgmath::Vector3<_> = self.light.position.into(); - self.light.position = - (cgmath::Quaternion::from_axis_angle((0.0, 1.0, 0.0).into(), cgmath::Deg(1.0)) - * old_position) - .into(); - self.queue - .write_buffer(&self.light_buffer, 0, bytemuck::cast_slice(&[self.light])); - - self.camera_controller.update_camera(&mut self.camera); - self.uniforms.update_view_proj(&self.camera); - self.queue.write_buffer( - &self.uniform_buffer, - 0, - bytemuck::cast_slice(&[self.uniforms]), - ); - } - - pub fn render(&mut self) -> Result<(), wgpu::SurfaceError> { - let frame = self.surface.get_current_texture()?; - - let mut encoder = self - .device - .create_command_encoder(&wgpu::CommandEncoderDescriptor { - label: Some("Render Encoder"), - }); - - let frame_view = frame.texture.create_view(&wgpu::TextureViewDescriptor { - label: Some("Render Texture View"), - format: Some(self.surface_config.format), - ..Default::default() - }); - - { - let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - label: Some("Frame render pass"), - color_attachments: &[ - Some(wgpu::RenderPassColorAttachment { - view: &self.render_material.textures["ss_diffuse"].view, - resolve_target: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Clear(self.bg_color), - store: true, - }, - }), - Some(wgpu::RenderPassColorAttachment { - view: &self.render_material.textures["ss_specular"].view, - resolve_target: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Clear(self.bg_color), - store: true, - }, - }), - ], - depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { - view: &self.depth_texture.view, - depth_ops: Some(wgpu::Operations { - load: wgpu::LoadOp::Clear(1.0), - store: true, - }), - stencil_ops: Some(wgpu::Operations { - load: wgpu::LoadOp::Clear(0xFF), - store: true, - }), - }), - }); - render_pass.set_stencil_reference(32); - render_pass.set_pipeline(&self.light_render_pipeline); - render_pass.draw_light_model( - &self.obj_model, - &self.uniform_bind_group, - &self.light_bind_group, - ); - - render_pass.set_vertex_buffer(1, self.instance_buffer.slice(..)); - render_pass.set_stencil_reference(64); - render_pass.set_pipeline(&self.deferred_render_pipeline); - render_pass.draw_model_instanced( - &self.obj_model, - 0..self.instances.len() as u32, - &self.uniform_bind_group, - &self.light_bind_group, - ); - } - - { - let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - label: Some("Frame render pass"), - color_attachments: &[Some(wgpu::RenderPassColorAttachment { - view: &frame_view, - resolve_target: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Clear(self.bg_color), - store: true, - }, - })], - depth_stencil_attachment: None, - }); - - render_pass.set_pipeline(&self.output_render_pipeline); - render_pass.set_bind_group(0, &self.render_material.bind_group, &[]); - - render_pass.set_vertex_buffer(0, self.screen_quad.vertex_buffer.slice(..)); - render_pass.set_index_buffer( - self.screen_quad.index_buffer.slice(..), - wgpu::IndexFormat::Uint32, - ); - render_pass.draw_indexed(0..self.screen_quad.num_elements, 0, 0..1); - } - - self.queue.submit(std::iter::once(encoder.finish())); - frame.present(); - Ok(()) - } -} +use std::collections::HashMap; +use std::iter::FromIterator; + +use crate::camera::CameraController; +use crate::file_reader::FileReader; +use crate::instance::InstanceRaw; +use crate::pipeline::{self, create_render_pipeline}; +use crate::uniform::Uniforms; +use crate::{instance::Instance, light::Light}; +use cgmath::*; + +use wgpu::util::DeviceExt; +use wgpu::{InstanceDescriptor, PowerPreference, SamplerBindingType}; +use winit::{event::WindowEvent, window::Window}; + +use crate::camera::Camera; +use crate::model::{self, DrawLight, Material, Mesh, ModelLoader, QuadVertex}; +use crate::model::{DrawModel, Model}; +use crate::texture::{self, Texture}; +use crate::vertex::Vertex; + +fn rgb_to_normalized(r: u8, g: u8, b: u8) -> wgpu::Color { + // Wish this could be const, but cant do fp arithmetic in const fn + wgpu::Color { + r: r as f64 / 255f64, + g: g as f64 / 255f64, + b: b as f64 / 255f64, + a: 1.0, + } +} + +const INSTANCES_PER_ROW: u32 = 100; +const INSTANCE_DISPLACEMENT: cgmath::Vector3 = cgmath::Vector3::new( + INSTANCES_PER_ROW as f32 * 0.5, + 0.0, + INSTANCES_PER_ROW as f32 * 0.5, +); + +const RENDER_SCALE: f32 = 2.0; +pub struct State { + surface: wgpu::Surface, + device: wgpu::Device, + queue: wgpu::Queue, + surface_config: wgpu::SurfaceConfiguration, + pub size: winit::dpi::PhysicalSize, + bg_color: wgpu::Color, + deferred_render_pipeline: wgpu::RenderPipeline, + camera: Camera, + uniforms: Uniforms, + uniform_buffer: wgpu::Buffer, + uniform_bind_group: wgpu::BindGroup, + camera_controller: CameraController, + instances: Vec, + instance_buffer: wgpu::Buffer, + depth_texture: Texture, + obj_model: Model, + screen_quad: Mesh, + render_material: Material, + light: Light, + light_buffer: wgpu::Buffer, + light_bind_group: wgpu::BindGroup, + light_render_pipeline: wgpu::RenderPipeline, + output_render_pipeline: wgpu::RenderPipeline, +} + +impl State { + pub async fn new(window: &Window) -> Self { + let size = window.inner_size(); + let instance_desc = InstanceDescriptor::default(); + let instance = wgpu::Instance::new(instance_desc); + let surface = unsafe { + instance + .create_surface(window) + .expect("Expected surface from window") + }; + let adapter = instance + .request_adapter(&wgpu::RequestAdapterOptions { + compatible_surface: Some(&surface), + power_preference: PowerPreference::HighPerformance, + force_fallback_adapter: false, + }) + .await + .expect("Could not create adapter instance!"); + + let (device, queue) = adapter + .request_device( + &wgpu::DeviceDescriptor { + features: wgpu::Features::empty(), + limits: wgpu::Limits::default(), + label: None, + }, + None, + ) + .await + .expect("Could not get device from adapter!"); + let capabilities = surface.get_capabilities(&adapter); + let surface_config = wgpu::SurfaceConfiguration { + usage: wgpu::TextureUsages::RENDER_ATTACHMENT, + format: capabilities.formats[0], + width: size.width, + height: size.height, + present_mode: wgpu::PresentMode::Fifo, + alpha_mode: wgpu::CompositeAlphaMode::Auto, + view_formats: vec![wgpu::TextureFormat::Bgra8UnormSrgb], + }; + + surface.configure(&device, &surface_config); + + let texture_bind_group_layout = + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("Texture bind group layout"), + entries: &[ + wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Texture { + sample_type: wgpu::TextureSampleType::Float { filterable: true }, + view_dimension: wgpu::TextureViewDimension::D2, + multisampled: false, + }, + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 1, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Sampler(SamplerBindingType::Filtering), + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 2, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Texture { + sample_type: wgpu::TextureSampleType::Float { filterable: true }, + view_dimension: wgpu::TextureViewDimension::D2, + multisampled: false, + }, + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 3, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Sampler(SamplerBindingType::Filtering), + count: None, + }, + ], + }); + + let camera = Camera { + eye: (0.0, 1.0, 2.0).into(), + target: (0.0, 0.0, 0.0).into(), + up: (0.0, 1.0, 0.0).into(), + aspect: surface_config.width as f32 / surface_config.height as f32, + fovy: 45.0, + znear: 0.1, + zfar: 1000.0, + }; + + let camera_controller = CameraController::new(0.2); + + let mut uniforms = Uniforms::new(); + uniforms.update_view_proj(&camera); + + let uniform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("Uniform Buffer"), + contents: bytemuck::bytes_of(&uniforms), + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + }); + + let uniform_bind_group_layout = + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("Uniform Bind Group Layout"), + entries: &[wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }], + }); + + let uniform_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("Uniform Bind Group"), + layout: &uniform_bind_group_layout, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: uniform_buffer.as_entire_binding(), + }], + }); + + // Cornflour blue, because I 'member XNA + let bg_color = rgb_to_normalized(0, 0, 0); + + let light = Light { + position: [2.0, 2.0, 2.0], + _padding: 0.0, + colour: [1.0, 1.0, 1.0], + _padding2: 0.0, + }; + + let light_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("Light buffer"), + contents: bytemuck::cast_slice(&[light]), + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + }); + + let light_bind_group_layout = + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + entries: &[wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }], + label: None, + }); + + let light_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &light_bind_group_layout, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: light_buffer.as_entire_binding(), + }], + label: None, + }); + + let render_pipeline_layout = + device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("Render Pipeline Layout"), + bind_group_layouts: &[ + &texture_bind_group_layout, + &uniform_bind_group_layout, + &light_bind_group_layout, + ], + push_constant_ranges: &[], + }); + + let model_loader = ModelLoader::new(&device).await; + + let obj_model = model_loader + .load( + &device, + &queue, + &texture_bind_group_layout, + "resources/cube/cube.obj", + ) + .await + .unwrap(); + + const SPACE_BETWEEN: f32 = 3.0; + let instances = (0..INSTANCES_PER_ROW) + .flat_map(|z| { + (0..INSTANCES_PER_ROW).map(move |x| { + let x = SPACE_BETWEEN * (x as f32 - INSTANCES_PER_ROW as f32 / 2.0); + let z = SPACE_BETWEEN * (z as f32 - INSTANCES_PER_ROW as f32 / 2.0); + + let position = cgmath::Vector3 { + x: x as f32, + y: 0.0, + z: z as f32, + } - INSTANCE_DISPLACEMENT; + + let rotation = if position.is_zero() { + cgmath::Quaternion::from_axis_angle( + cgmath::Vector3::unit_z(), + cgmath::Deg(0.0), + ) + } else { + cgmath::Quaternion::from_axis_angle( + position.clone().normalize(), + cgmath::Deg(45.0), + ) + }; + + Instance { position, rotation } + }) + }) + .collect::>(); + + let instance_data = instances.iter().map(Instance::to_raw).collect::>(); + + let instance_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("Instance Buffer"), + contents: bytemuck::cast_slice(instance_data.as_slice()), + usage: wgpu::BufferUsages::VERTEX, + }); + + let depth_texture = + Texture::create_depth_texture(&device, &surface_config, RENDER_SCALE, "Depth Texture"); + let shader_buffer = FileReader::read_file("shaders/shader.wgsl").await; + let shader_str = + std::str::from_utf8(shader_buffer.as_slice()).expect("Failed to load shader"); + + let deferred_render_pipeline = { + let shader = wgpu::ShaderModuleDescriptor { + label: Some("Normal Shader"), + source: wgpu::ShaderSource::Wgsl(shader_str.into()), + }; + + pipeline::create_render_pipeline( + &device, + &render_pipeline_layout, + Some(texture::Texture::DEPTH_FORMAT), + &[model::ModelVertex::desc(), InstanceRaw::desc()], + shader, + &[ + Some(wgpu::ColorTargetState { + format: surface_config.format, + blend: Some(wgpu::BlendState { + color: wgpu::BlendComponent::REPLACE, + alpha: wgpu::BlendComponent::REPLACE, + }), + write_mask: wgpu::ColorWrites::ALL, + }), + Some(wgpu::ColorTargetState { + format: surface_config.format, + blend: Some(wgpu::BlendState { + color: wgpu::BlendComponent::REPLACE, + alpha: wgpu::BlendComponent::REPLACE, + }), + write_mask: wgpu::ColorWrites::ALL, + }), + ], + Some("Render Pipeline"), + ) + }; + + let light_render_pipeline = { + let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("Light pipeline layout desc"), + bind_group_layouts: &[&uniform_bind_group_layout, &light_bind_group_layout], + push_constant_ranges: &[], + }); + let shader_buffer = FileReader::read_file("shaders/light.wgsl").await; + let shader_str = + std::str::from_utf8(shader_buffer.as_slice()).expect("Failed to load shader"); + + let shader = wgpu::ShaderModuleDescriptor { + label: Some("Light Shader"), + source: wgpu::ShaderSource::Wgsl(shader_str.into()), + }; + + pipeline::create_render_pipeline( + &device, + &layout, + Some(texture::Texture::DEPTH_FORMAT), + &[model::ModelVertex::desc()], + shader, + &[ + Some(wgpu::ColorTargetState { + format: surface_config.format, + blend: Some(wgpu::BlendState { + color: wgpu::BlendComponent::REPLACE, + alpha: wgpu::BlendComponent::REPLACE, + }), + write_mask: wgpu::ColorWrites::ALL, + }), + Some(wgpu::ColorTargetState { + format: surface_config.format, + blend: Some(wgpu::BlendState { + color: wgpu::BlendComponent::REPLACE, + alpha: wgpu::BlendComponent::REPLACE, + }), + write_mask: wgpu::ColorWrites::ALL, + }), + ], + Some("Light render pipeline"), + ) + }; + + let output_bindgroup_layout = + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + entries: &[ + wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Texture { + sample_type: wgpu::TextureSampleType::Float { filterable: true }, + view_dimension: wgpu::TextureViewDimension::D2, + multisampled: false, + }, + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 1, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Sampler(SamplerBindingType::Filtering), + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 2, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Texture { + sample_type: wgpu::TextureSampleType::Float { filterable: true }, + view_dimension: wgpu::TextureViewDimension::D2, + multisampled: false, + }, + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 3, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Sampler(SamplerBindingType::Filtering), + count: None, + }, + ], + label: None, + }); + + let shader_buffer = FileReader::read_file("shaders/draw_deferred.wgsl").await; + let shader_str = + std::str::from_utf8(shader_buffer.as_slice()).expect("Failed to load shader"); + + let output_render_pipeline = { + let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("Deferred pipeline layout desc"), + bind_group_layouts: &[&output_bindgroup_layout], + push_constant_ranges: &[], + }); + + let shader = wgpu::ShaderModuleDescriptor { + label: Some("Output Shader"), + source: wgpu::ShaderSource::Wgsl(shader_str.into()), + }; + + create_render_pipeline( + &device, + &layout, + None, + &[QuadVertex::desc()], + shader, + &[Some(wgpu::ColorTargetState { + format: surface_config.format, + blend: Some(wgpu::BlendState { + color: wgpu::BlendComponent::REPLACE, + alpha: wgpu::BlendComponent::REPLACE, + }), + write_mask: wgpu::ColorWrites::ALL, + })], + Some("Output Pipeline"), + ) + }; + + let diffuse_texture = Texture::create_render_texture( + &device, + &surface_config, + RENDER_SCALE, + "Deferred Diffuse Surface", + ); + + let specular_texture = Texture::create_render_texture( + &device, + &surface_config, + RENDER_SCALE, + "Deferred Normal Surface", + ); + + let screen_quad = ModelLoader::create_screen_quad_mesh(&device); + + let render_material = { + let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: None, + layout: &output_bindgroup_layout, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::TextureView(&diffuse_texture.view), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::Sampler(&diffuse_texture.sampler), + }, + wgpu::BindGroupEntry { + binding: 2, + resource: wgpu::BindingResource::TextureView(&specular_texture.view), + }, + wgpu::BindGroupEntry { + binding: 3, + resource: wgpu::BindingResource::Sampler(&specular_texture.sampler), + }, + ], + }); + + Material { + name: String::from("Output Quad Textures"), + textures: HashMap::from_iter([ + ("ss_diffuse".to_owned(), diffuse_texture), + ("ss_specular".to_owned(), specular_texture), + ]), + bind_group, + } + }; + + Self { + surface, + device, + queue, + surface_config, + size, + bg_color, + deferred_render_pipeline, + camera, + uniforms, + uniform_buffer, + uniform_bind_group, + camera_controller, + instances, + instance_buffer, + depth_texture, + obj_model, + light, + light_buffer, + light_bind_group, + light_render_pipeline, + output_render_pipeline, + screen_quad, + render_material, + } + } + + pub fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { + self.size = new_size; + self.surface_config.width = self.size.width; + self.surface_config.height = self.size.height; + self.surface.configure(&self.device, &self.surface_config); + self.depth_texture = Texture::create_depth_texture( + &self.device, + &self.surface_config, + RENDER_SCALE, + "Depth Texture", + ); + self.camera.aspect = self.surface_config.width as f32 / self.surface_config.height as f32; + + let diffuse_texture = Texture::create_render_texture( + &self.device, + &self.surface_config, + RENDER_SCALE, + "Deferred Surface", + ); + + let screen_normal_texture = Texture::create_render_texture( + &self.device, + &self.surface_config, + RENDER_SCALE, + "Deferred Normal Surface", + ); + + self.render_material = { + let bind_group = self.device.create_bind_group(&wgpu::BindGroupDescriptor { + label: None, + layout: &self.output_render_pipeline.get_bind_group_layout(0), + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::TextureView(&diffuse_texture.view), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::Sampler(&diffuse_texture.sampler), + }, + wgpu::BindGroupEntry { + binding: 2, + resource: wgpu::BindingResource::TextureView(&screen_normal_texture.view), + }, + wgpu::BindGroupEntry { + binding: 3, + resource: wgpu::BindingResource::Sampler(&screen_normal_texture.sampler), + }, + ], + }); + + Material { + name: String::from("Output Quad Textures"), + textures: HashMap::from_iter([ + ("ss_diffuse".to_owned(), diffuse_texture), + ("ss_specular".to_owned(), screen_normal_texture), + ]), + bind_group, + } + }; + } + + pub fn input(&mut self, event: &WindowEvent) -> bool { + self.camera_controller.process_inputs(event) + } + + pub fn update(&mut self) { + let old_position: cgmath::Vector3<_> = self.light.position.into(); + self.light.position = + (cgmath::Quaternion::from_axis_angle((0.0, 1.0, 0.0).into(), cgmath::Deg(1.0)) + * old_position) + .into(); + self.queue + .write_buffer(&self.light_buffer, 0, bytemuck::cast_slice(&[self.light])); + + self.camera_controller.update_camera(&mut self.camera); + self.uniforms.update_view_proj(&self.camera); + self.queue.write_buffer( + &self.uniform_buffer, + 0, + bytemuck::cast_slice(&[self.uniforms]), + ); + } + + pub fn render(&mut self) -> Result<(), wgpu::SurfaceError> { + let frame = self.surface.get_current_texture()?; + + let mut encoder = self + .device + .create_command_encoder(&wgpu::CommandEncoderDescriptor { + label: Some("Render Encoder"), + }); + + let frame_view = frame.texture.create_view(&wgpu::TextureViewDescriptor { + label: Some("Render Texture View"), + format: Some(self.surface_config.format), + ..Default::default() + }); + + { + let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("Frame render pass"), + color_attachments: &[ + Some(wgpu::RenderPassColorAttachment { + view: &self.render_material.textures["ss_diffuse"].view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(self.bg_color), + store: wgpu::StoreOp::Store, + }, + }), + Some(wgpu::RenderPassColorAttachment { + view: &self.render_material.textures["ss_specular"].view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(self.bg_color), + store: wgpu::StoreOp::Store, + }, + }), + ], + depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { + view: &self.depth_texture.view, + depth_ops: Some(wgpu::Operations { + load: wgpu::LoadOp::Clear(1.0), + store: wgpu::StoreOp::Store, + }), + stencil_ops: Some(wgpu::Operations { + load: wgpu::LoadOp::Clear(0xFF), + store: wgpu::StoreOp::Store, + }), + }), + timestamp_writes: None, + occlusion_query_set: None, + }); + render_pass.set_stencil_reference(32); + render_pass.set_pipeline(&self.light_render_pipeline); + render_pass.draw_light_model( + &self.obj_model, + &self.uniform_bind_group, + &self.light_bind_group, + ); + + render_pass.set_vertex_buffer(1, self.instance_buffer.slice(..)); + render_pass.set_stencil_reference(64); + render_pass.set_pipeline(&self.deferred_render_pipeline); + render_pass.draw_model_instanced( + &self.obj_model, + 0..self.instances.len() as u32, + &self.uniform_bind_group, + &self.light_bind_group, + ); + } + + { + let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("Frame render pass"), + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: &frame_view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(self.bg_color), + store: wgpu::StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, + }); + + render_pass.set_pipeline(&self.output_render_pipeline); + render_pass.set_bind_group(0, &self.render_material.bind_group, &[]); + + render_pass.set_vertex_buffer(0, self.screen_quad.vertex_buffer.slice(..)); + render_pass.set_index_buffer( + self.screen_quad.index_buffer.slice(..), + wgpu::IndexFormat::Uint32, + ); + render_pass.draw_indexed(0..self.screen_quad.num_elements, 0, 0..1); + } + + self.queue.submit(std::iter::once(encoder.finish())); + frame.present(); + Ok(()) + } +}