From 806f240eb5af42db4f1a71ee57805bf3124098f8 Mon Sep 17 00:00:00 2001 From: Capucho Date: Fri, 21 Aug 2020 20:10:56 +0100 Subject: [PATCH] Started the report of wgpu --- Cargo.lock | 397 +++++++++++++++- voxygen/Cargo.toml | 10 +- voxygen/src/lib.rs | 9 +- voxygen/src/render/buffer.rs | 52 +++ voxygen/src/render/consts.rs | 28 +- voxygen/src/render/error.rs | 73 +-- voxygen/src/render/instances.rs | 40 +- voxygen/src/render/mesh.rs | 76 ++-- voxygen/src/render/mod.rs | 21 +- voxygen/src/render/model.rs | 75 ++- voxygen/src/render/pipelines/figure.rs | 154 +++++-- voxygen/src/render/renderer.rs | 602 +++++++++++++------------ voxygen/src/render/texture.rs | 266 +++++------ voxygen/src/window.rs | 46 +- 14 files changed, 1126 insertions(+), 723 deletions(-) create mode 100644 voxygen/src/render/buffer.rs diff --git a/Cargo.lock b/Cargo.lock index ae25780cc5..2dfc99b1a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -203,6 +203,15 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "ash" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c69a8137596e84c22d57f3da1b5de1d4230b1742a710091c85f4d7ce50f00f38" +dependencies = [ + "libloading 0.6.7", +] + [[package]] name = "assets_manager" version = "0.4.4" @@ -358,6 +367,21 @@ dependencies = [ "shlex", ] +[[package]] +name = "bit-set" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bitflags" version = "1.2.1" @@ -764,6 +788,12 @@ dependencies = [ "walkdir 0.1.8", ] +[[package]] +name = "copyless" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2df960f5d869b2dd8532793fde43eb5427cceb126c929747a26823ab0eeb536" + [[package]] name = "copypasta" version = "0.7.1" @@ -1205,6 +1235,17 @@ dependencies = [ "sct", ] +[[package]] +name = "d3d12" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a60cceb22c7c53035f8980524fdc7f17cf49681a3c154e6757d30afbec6ec4" +dependencies = [ + "bitflags", + "libloading 0.6.7", + "winapi 0.3.9", +] + [[package]] name = "daggy" version = "0.5.0" @@ -1861,6 +1902,152 @@ dependencies = [ "log", ] +[[package]] +name = "gfx-auxil" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07cd956b592970f08545b9325b87580eb95a51843b6f39da27b8667fec1a1216" +dependencies = [ + "fxhash", + "gfx-hal", + "spirv_cross", +] + +[[package]] +name = "gfx-backend-dx11" +version = "0.6.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54b43f06089866bdffe59b5a6801022c86b74d2c1dd28940a9cf301d3d014fbc" +dependencies = [ + "arrayvec", + "bitflags", + "gfx-auxil", + "gfx-hal", + "libloading 0.6.7", + "log", + "parking_lot 0.11.1", + "range-alloc", + "raw-window-handle", + "smallvec", + "spirv_cross", + "thunderdome", + "winapi 0.3.9", + "wio", +] + +[[package]] +name = "gfx-backend-dx12" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "375014deed24d76b03604736dd899f0925158a1a96db90cbefb9cce070f71af7" +dependencies = [ + "arrayvec", + "bit-set", + "bitflags", + "d3d12", + "gfx-auxil", + "gfx-hal", + "log", + "range-alloc", + "raw-window-handle", + "smallvec", + "spirv_cross", + "winapi 0.3.9", +] + +[[package]] +name = "gfx-backend-empty" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2085227c12b78f6657a900c829f2d0deb46a9be3eaf86844fde263cdc218f77c" +dependencies = [ + "gfx-hal", + "log", + "raw-window-handle", +] + +[[package]] +name = "gfx-backend-metal" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "273d60d5207f96d99e0d11d0718995f67e56533a9df1444d83baf787f4c3cb32" +dependencies = [ + "arrayvec", + "bitflags", + "block", + "cocoa-foundation", + "copyless", + "foreign-types", + "gfx-auxil", + "gfx-hal", + "lazy_static", + "log", + "metal", + "objc", + "parking_lot 0.11.1", + "range-alloc", + "raw-window-handle", + "smallvec", + "spirv_cross", + "storage-map", +] + +[[package]] +name = "gfx-backend-vulkan" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a3a63cf61067a09b7d1ac480af3cb2ae0c5ede5bed294607bbd814cb1666c45" +dependencies = [ + "arrayvec", + "ash", + "byteorder", + "core-graphics-types", + "gfx-hal", + "inplace_it", + "lazy_static", + "log", + "objc", + "raw-window-handle", + "smallvec", + "winapi 0.3.9", + "x11", +] + +[[package]] +name = "gfx-descriptor" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd8c7afcd000f279d541a490e27117e61037537279b9342279abf4938fe60c6b" +dependencies = [ + "arrayvec", + "fxhash", + "gfx-hal", + "log", +] + +[[package]] +name = "gfx-hal" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d0754f5b7a43915fd7466883b2d1bb0800d7cc4609178d0b27bf143b9e5123" +dependencies = [ + "bitflags", + "raw-window-handle", +] + +[[package]] +name = "gfx-memory" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dccdda5d2b39412f4ca2cb15c70b5a82783a86b0606f5e985342754c8ed88f05" +dependencies = [ + "bit-set", + "fxhash", + "gfx-hal", + "log", + "slab", +] + [[package]] name = "gfx_core" version = "0.9.2" @@ -2432,6 +2619,12 @@ dependencies = [ "libc", ] +[[package]] +name = "inplace_it" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90953f308a79fe6d62a4643e51f848fbfddcd05975a38e69fdf4ab86a7baf7ca" + [[package]] name = "instant" version = "0.1.9" @@ -2832,6 +3025,20 @@ dependencies = [ "autocfg", ] +[[package]] +name = "metal" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c4e8a431536529327e28c9ba6992f2cb0c15d4222f0602a16e6d7695ff3bccf" +dependencies = [ + "bitflags", + "block", + "cocoa-foundation", + "foreign-types", + "log", + "objc", +] + [[package]] name = "minifb" version = "0.19.1" @@ -2947,6 +3154,20 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0debeb9fcf88823ea64d64e4a815ab1643f33127d995978e099942ce38f25238" +[[package]] +name = "naga" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0873deb76cf44b7454fba7b2ba6a89d3de70c08aceffd2c489379b3d9d08e661" +dependencies = [ + "bitflags", + "fxhash", + "log", + "num-traits", + "spirv_headers", + "thiserror", +] + [[package]] name = "native-dialog" version = "0.5.5" @@ -3387,6 +3608,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" dependencies = [ "malloc_buf", + "objc_exception", ] [[package]] @@ -3400,6 +3622,15 @@ dependencies = [ "objc_id", ] +[[package]] +name = "objc_exception" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" +dependencies = [ + "cc", +] + [[package]] name = "objc_id" version = "0.1.1" @@ -4018,6 +4249,12 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "range-alloc" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e935c45e09cc6dcf00d2f0b2d630a58f4095320223d47fc68918722f0538b6" + [[package]] name = "raw-window-handle" version = "0.3.3" @@ -4793,6 +5030,27 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "spirv_cross" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ebd49af36be83ecd6290b57147e2a0e26145b832634b17146d934b197ca3713" +dependencies = [ + "cc", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "spirv_headers" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f5b132530b1ac069df335577e3581765995cba5a13995cdbbdbc8fb057c532c" +dependencies = [ + "bitflags", + "num-traits", +] + [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -4871,6 +5129,15 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" +[[package]] +name = "storage-map" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418bb14643aa55a7841d5303f72cf512cfb323b8cc221d51580500a1ca75206c" +dependencies = [ + "lock_api 0.4.3", +] + [[package]] name = "str-buf" version = "1.0.5" @@ -4971,6 +5238,18 @@ dependencies = [ "unicode-xid 0.2.1", ] +[[package]] +name = "synstructure" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" +dependencies = [ + "proc-macro2 1.0.26", + "quote 1.0.9", + "syn 1.0.69", + "unicode-xid 0.2.1", +] + [[package]] name = "tap" version = "1.0.1" @@ -5055,6 +5334,12 @@ dependencies = [ "once_cell", ] +[[package]] +name = "thunderdome" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7572415bd688d401c52f6e36f4c8e805b9ae1622619303b9fa835d531db0acae" + [[package]] name = "time" version = "0.1.43" @@ -5339,6 +5624,12 @@ dependencies = [ "nom 5.1.2", ] +[[package]] +name = "typed-arena" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0685c84d5d54d1c26f7d3eb96cd41550adb97baed141a761cf335d3d33bcd0ae" + [[package]] name = "typenum" version = "1.13.0" @@ -5810,6 +6101,7 @@ dependencies = [ "dot_vox", "enum-iterator", "euc", + "futures", "gfx", "gfx_device_gl", "gfx_gl", @@ -5855,9 +6147,11 @@ dependencies = [ "veloren-server", "veloren-voxygen-anim", "veloren-world", + "wgpu", "window_clipboard 0.2.0", "winit", "winres", + "zerocopy", ] [[package]] @@ -6408,9 +6702,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.50" +version = "0.3.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a905d57e488fec8861446d3393670fb50d27a262344013181c2cdf9fff5481be" +checksum = "ec600b26223b2948cedfde2a0aa6756dcf1fef616f43d7b3097aaf53a6c4d92b" dependencies = [ "js-sys", "wasm-bindgen", @@ -6436,6 +6730,65 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "wgpu" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "991903e4c9f5b7319732b30a3d0339e27a51ea992cea22769b5f6c7f7076af6d" +dependencies = [ + "arrayvec", + "futures", + "gfx-backend-vulkan", + "js-sys", + "objc", + "parking_lot 0.11.1", + "raw-window-handle", + "smallvec", + "tracing", + "typed-arena", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "wgpu-core", + "wgpu-types", +] + +[[package]] +name = "wgpu-core" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea487deeae90e06d77eb8e6cef945247774e7c0a0a226d238b31e90633594365" +dependencies = [ + "arrayvec", + "bitflags", + "copyless", + "fxhash", + "gfx-backend-dx11", + "gfx-backend-dx12", + "gfx-backend-empty", + "gfx-backend-metal", + "gfx-backend-vulkan", + "gfx-descriptor", + "gfx-hal", + "gfx-memory", + "naga", + "parking_lot 0.11.1", + "raw-window-handle", + "smallvec", + "thiserror", + "tracing", + "wgpu-types", +] + +[[package]] +name = "wgpu-types" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e3529528e608b54838ee618c3923b0f46e6db0334cfc6c42a16cf4ceb3bdb57" +dependencies = [ + "bitflags", +] + [[package]] name = "which" version = "4.1.0" @@ -6564,6 +6917,15 @@ dependencies = [ "toml", ] +[[package]] +name = "wio" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5" +dependencies = [ + "winapi 0.3.9", +] + [[package]] name = "ws2_32-sys" version = "0.2.1" @@ -6583,6 +6945,16 @@ dependencies = [ "tap", ] +[[package]] +name = "x11" +version = "2.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ecd092546cb16f25783a5451538e73afc8d32e242648d54f4ae5459ba1e773" +dependencies = [ + "libc", + "pkg-config", +] + [[package]] name = "x11-clipboard" version = "0.5.1" @@ -6700,3 +7072,24 @@ checksum = "0de7bff972b4f2a06c85f6d8454b09df153af7e3a4ec2aac81db1b105b684ddb" dependencies = [ "chrono", ] + +[[package]] +name = "zerocopy" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6580539ad917b7c026220c4b3f2c08d52ce54d6ce0dc491e66002e35388fab46" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d498dbd1fd7beb83c86709ae1c33ca50942889473473d287d56ce4770a18edfb" +dependencies = [ + "proc-macro2 1.0.26", + "syn 1.0.69", + "synstructure", +] diff --git a/voxygen/Cargo.toml b/voxygen/Cargo.toml index 6bd924bd55..a9378fef10 100644 --- a/voxygen/Cargo.toml +++ b/voxygen/Cargo.toml @@ -22,14 +22,13 @@ runtimeLibs = ["libGL", "xorg.libX11", "xorg.libXcursor", "xorg.libXrandr", "xor buildInputs = ["xorg.libxcb"] [features] -gl = ["gfx_device_gl", "gfx_gl"] hot-anim = ["anim/use-dyn-lib"] singleplayer = ["server"] simd = ["vek/platform_intrinsics"] tracy = ["common/tracy", "common-ecs/tracy", "common-frontend/tracy", "common-net/tracy", "common-systems/tracy", "common-state/tracy", "client/tracy"] plugins = ["client/plugins"] -default = ["gl", "singleplayer", "native-dialog", "plugins", "simd"] +default = ["singleplayer", "native-dialog", "plugins", "simd"] [dependencies] client = {package = "veloren-client", path = "../client"} @@ -51,6 +50,8 @@ gfx_gl = {version = "0.6.1", optional = true} glutin = "0.26.0" old_school_gfx_glutin_ext = "0.26" winit = {version = "0.24.0", features = ["serde"]} +wgpu = "0.6.0" +zerocopy = "0.3.0" # Ui conrod_core = {git = "https://gitlab.com/veloren/conrod.git", branch="copypasta_0.7"} @@ -87,8 +88,7 @@ crossbeam-channel = "0.5" directories-next = "2.0" dot_vox = "4.0" enum-iterator = "0.6" -strum = "0.20" -strum_macros = "0.20" +futures = "0.3" glsl-include = "0.3.1" guillotiere = "0.6" hashbrown = {version = "0.9", features = ["rayon", "serde", "nightly"]} @@ -101,6 +101,8 @@ rand = "0.8" rodio = {version = "0.13", default-features = false, features = ["vorbis"]} ron = {version = "0.6", default-features = false} serde = {version = "1.0", features = [ "rc", "derive" ]} +strum = "0.20" +strum_macros = "0.20" treeculler = "0.2" tokio = { version = "1", default-features = false, features = ["rt-multi-thread"] } num_cpus = "1.0" diff --git a/voxygen/src/lib.rs b/voxygen/src/lib.rs index ebf188850c..ae15b7a07d 100644 --- a/voxygen/src/lib.rs +++ b/voxygen/src/lib.rs @@ -2,7 +2,14 @@ #![allow(incomplete_features)] #![allow(clippy::option_map_unit_fn)] #![deny(clippy::clone_on_ref_ptr)] -#![feature(array_map, bool_to_option, const_generics, drain_filter, once_cell)] +#![feature( + array_map, + bool_to_option, + const_generics, + drain_filter, + once_cell, + trait_alias +)] #![recursion_limit = "2048"] #[macro_use] diff --git a/voxygen/src/render/buffer.rs b/voxygen/src/render/buffer.rs new file mode 100644 index 0000000000..63de526edf --- /dev/null +++ b/voxygen/src/render/buffer.rs @@ -0,0 +1,52 @@ +use super::RenderError; +use wgpu::util::DeviceExt; +use zerocopy::AsBytes; + +#[derive(Clone)] +pub struct Buffer { + pub buf: wgpu::Buffer, + // bytes + count: usize, + phantom_data: std::marker::PhantomData, +} + +impl Buffer { + pub fn new(device: &mut wgpu::Device, cap: usize, usage: wgpu::BufferUsage) -> Self { + Self { + buf: device.create_buffer(&wgpu::BufferDescriptor { + label: None, + mapped_at_creation: false, + size: cap, + usage: usage | wgpu::BufferUsage::MAP_WRITE, + }), + count: 0, + phantom_data: std::marker::PhantomData, + } + } + + pub fn new_with_data(device: &mut wgpu::Device, usage: wgpu::BufferUsage, data: &[T]) -> Self { + let contents = data.as_bytes(); + + Self { + buf: device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: None, + contents, + usage: usage | wgpu::BufferUsage::MAP_WRITE, + }), + count: data.len(), + phantom_data: std::marker::PhantomData, + } + } + + pub fn update( + &mut self, + device: &wgpu::Device, + queue: &wgpu::Queue, + vals: &[T], + offset: usize, + ) { + queue.write_buffer(&self.buf, offset, vals.as_bytes()) + } + + pub fn count(&self) -> usize { self.count } +} diff --git a/voxygen/src/render/consts.rs b/voxygen/src/render/consts.rs index 0eded13428..72930b2998 100644 --- a/voxygen/src/render/consts.rs +++ b/voxygen/src/render/consts.rs @@ -1,36 +1,32 @@ -use super::{gfx_backend, RenderError}; -use gfx::{self, traits::FactoryExt}; +use super::{buffer::Buffer, RenderError}; +use zerocopy::AsBytes; /// A handle to a series of constants sitting on the GPU. This is used to hold /// information used in the rendering process that does not change throughout a /// single render pass. #[derive(Clone)] -pub struct Consts { - pub buf: gfx::handle::Buffer, +pub struct Consts { + buf: Buffer, } -impl Consts { +impl Consts { /// Create a new `Const`. - pub fn new(factory: &mut gfx_backend::Factory, len: usize) -> Self { + pub fn new(device: &mut wgpu::Device, len: usize) -> Self { Self { - buf: factory.create_constant_buffer(len), + buf: Buffer::new(device, len, wgpu::BufferUsage::UNIFORM), } } /// Update the GPU-side value represented by this constant handle. - pub fn update( &mut self, - encoder: &mut gfx::Encoder, + device: &wgpu::Device, + queue: &wgpu::Queue, vals: &[T], offset: usize, ) -> Result<(), RenderError> { - if vals.is_empty() { - Ok(()) - } else { - encoder - .update_buffer(&self.buf, vals, offset) - .map_err(RenderError::UpdateError) - } + self.buf.update(device, queue, vals, offset) } + + pub fn buf(&self) -> &wgpu::Buffer { self.buf.buf } } diff --git a/voxygen/src/render/error.rs b/voxygen/src/render/error.rs index 8c9352857d..ba41795750 100644 --- a/voxygen/src/render/error.rs +++ b/voxygen/src/render/error.rs @@ -2,73 +2,20 @@ /// rendering subsystem. #[derive(Debug)] pub enum RenderError { - PipelineError(gfx::PipelineStateError), - UpdateError(gfx::UpdateError), - TexUpdateError(gfx::UpdateError<[u16; 3]>), - CombinedError(gfx::CombinedError), - BufferCreationError(gfx::buffer::CreationError), - IncludeError(glsl_include::Error), - MappingError(gfx::mapping::Error), - CopyError(gfx::CopyError<[u16; 3], usize>), + RequestDeviceError(wgpu::RequestDeviceError), + MappingError(wgpu::BufferAsyncError), + SwapChainError(wgpu::SwapChainError), CustomError(String), + CouldNotFindAdapter, } -impl From> for RenderError { - fn from(err: gfx::PipelineStateError) -> Self { Self::PipelineError(err) } +impl From for RenderError { + fn from(err: wgpu::RequestDeviceError) -> Self { Self::RequestDeviceError(err) } } -impl From> for RenderError { - fn from(err: gfx::PipelineStateError<&str>) -> Self { - match err { - gfx::PipelineStateError::DescriptorInit(err) => { - gfx::PipelineStateError::DescriptorInit(err) - }, - err => err, - } - .into() - } +impl From for RenderError { + fn from(err: wgpu::BufferAsyncError) -> Self { Self::MappingError(err) } } -impl From for RenderError { - fn from(err: gfx::shade::ProgramError) -> Self { - gfx::PipelineStateError::::Program(err).into() - } -} -impl From> for RenderError { - fn from(err: gfx::UpdateError) -> Self { Self::UpdateError(err) } -} - -impl From> for RenderError { - fn from(err: gfx::UpdateError<[u16; 3]>) -> Self { Self::TexUpdateError(err) } -} - -impl From for RenderError { - fn from(err: gfx::CombinedError) -> Self { Self::CombinedError(err) } -} - -impl From for RenderError { - fn from(err: gfx::TargetViewError) -> Self { Self::CombinedError(err.into()) } -} - -impl From for RenderError { - fn from(err: gfx::ResourceViewError) -> Self { Self::CombinedError(err.into()) } -} - -impl From for RenderError { - fn from(err: gfx::texture::CreationError) -> Self { Self::CombinedError(err.into()) } -} - -impl From for RenderError { - fn from(err: gfx::buffer::CreationError) -> Self { Self::BufferCreationError(err) } -} - -impl From for RenderError { - fn from(err: glsl_include::Error) -> Self { Self::IncludeError(err) } -} - -impl From for RenderError { - fn from(err: gfx::mapping::Error) -> Self { Self::MappingError(err) } -} - -impl From> for RenderError { - fn from(err: gfx::CopyError<[u16; 3], usize>) -> Self { Self::CopyError(err) } +impl From for RenderError { + fn from(err: wgpu::SwapChainError) -> Self { Self::SwapChainError(err) } } diff --git a/voxygen/src/render/instances.rs b/voxygen/src/render/instances.rs index c53d5ee2c2..681dbbcaa6 100644 --- a/voxygen/src/render/instances.rs +++ b/voxygen/src/render/instances.rs @@ -1,34 +1,30 @@ -use super::{gfx_backend, RenderError}; -use gfx::{ - self, - buffer::Role, - memory::{Bind, Usage}, - Factory, -}; +use super::{buffer::Buffer, RenderError}; +use zerocopy::AsBytes; /// Represents a mesh that has been sent to the GPU. -pub struct Instances { - pub ibuf: gfx::handle::Buffer, +#[derive(Clone)] +pub struct Instances { + buf: Buffer, } -impl Instances { - pub fn new(factory: &mut gfx_backend::Factory, len: usize) -> Result { - Ok(Self { - ibuf: factory - .create_buffer(len, Role::Vertex, Usage::Dynamic, Bind::empty()) - .map_err(RenderError::BufferCreationError)?, - }) +impl Instances { + pub fn new(device: &mut wgpu::Device, len: usize) -> Self { + Self { + buf: Buffer::new(device, len, wgpu::BufferUsage::VERTEX), + } } - pub fn count(&self) -> usize { self.ibuf.len() } + pub fn count(&self) -> usize { self.buf.count() } pub fn update( &mut self, - encoder: &mut gfx::Encoder, - instances: &[T], + device: &wgpu::Device, + queue: &wgpu::Queue, + vals: &[T], + offset: usize, ) -> Result<(), RenderError> { - encoder - .update_buffer(&self.ibuf, instances, 0) - .map_err(RenderError::UpdateError) + self.buf.update(device, queue, vals, offset) } + + pub fn buf(&self) -> &wgpu::Buffer { self.buf.buf } } diff --git a/voxygen/src/render/mesh.rs b/voxygen/src/render/mesh.rs index a8c6b6445e..b39cc41a4a 100644 --- a/voxygen/src/render/mesh.rs +++ b/voxygen/src/render/mesh.rs @@ -1,15 +1,12 @@ -use super::Pipeline; +use super::Vertex; use core::{iter::FromIterator, ops::Range}; /// A `Vec`-based mesh structure used to store mesh data on the CPU. -pub struct Mesh { - verts: Vec, +pub struct Mesh { + verts: Vec, } -impl Clone for Mesh

-where - P::Vertex: Clone, -{ +impl Clone for Mesh { fn clone(&self) -> Self { Self { verts: self.verts.clone(), @@ -17,7 +14,7 @@ where } } -impl Mesh

{ +impl Mesh { /// Create a new `Mesh`. #[allow(clippy::new_without_default)] // TODO: Pending review in #587 pub fn new() -> Self { Self { verts: Vec::new() } } @@ -26,23 +23,23 @@ impl Mesh

{ pub fn clear(&mut self) { self.verts.clear(); } /// Get a slice referencing the vertices of this mesh. - pub fn vertices(&self) -> &[P::Vertex] { &self.verts } + pub fn vertices(&self) -> &[V] { &self.verts } /// Get a mutable slice referencing the vertices of this mesh. pub fn vertices_mut(&mut self) -> &mut [P::Vertex] { &mut self.verts } /// Push a new vertex onto the end of this mesh. - pub fn push(&mut self, vert: P::Vertex) { self.verts.push(vert); } + pub fn push(&mut self, vert: V) { self.verts.push(vert); } /// Push a new polygon onto the end of this mesh. - pub fn push_tri(&mut self, tri: Tri

) { + pub fn push_tri(&mut self, tri: Tri) { self.verts.push(tri.a); self.verts.push(tri.b); self.verts.push(tri.c); } /// Push a new quad onto the end of this mesh. - pub fn push_quad(&mut self, quad: Quad

) { + pub fn push_quad(&mut self, quad: Quad) { // A quad is composed of two triangles. The code below converts the former to // the latter. @@ -73,10 +70,10 @@ impl Mesh

{ } /// Push the vertices of another mesh onto the end of this mesh. - pub fn push_mesh(&mut self, other: &Mesh

) { self.verts.extend_from_slice(other.vertices()); } + pub fn push_mesh(&mut self, other: &Mesh) { self.verts.extend_from_slice(other.vertices()); } /// Map and push the vertices of another mesh onto the end of this mesh. - pub fn push_mesh_map P::Vertex>(&mut self, other: &Mesh

, mut f: F) { + pub fn push_mesh_map V>(&mut self, other: &Mesh, mut f: F) { // Reserve enough space in our Vec. This isn't necessary, but it tends to reduce // the number of required (re)allocations. self.verts.reserve(other.vertices().len()); @@ -86,23 +83,23 @@ impl Mesh

{ } } - pub fn iter(&self) -> std::slice::Iter { self.verts.iter() } + pub fn iter(&self) -> std::slice::Iter { self.verts.iter() } /// NOTE: Panics if vertex_range is out of bounds of vertices. - pub fn iter_mut(&mut self, vertex_range: Range) -> std::slice::IterMut { + pub fn iter_mut(&mut self, vertex_range: Range) -> std::slice::IterMut { self.verts[vertex_range].iter_mut() } } -impl IntoIterator for Mesh

{ - type IntoIter = std::vec::IntoIter; - type Item = P::Vertex; +impl IntoIterator for Mesh { + type IntoIter = std::vec::IntoIter; + type Item = V; fn into_iter(self) -> Self::IntoIter { self.verts.into_iter() } } -impl FromIterator> for Mesh

{ - fn from_iter>>(tris: I) -> Self { +impl FromIterator> for Mesh { + fn from_iter>>(tris: I) -> Self { tris.into_iter().fold(Self::new(), |mut this, tri| { this.push_tri(tri); this @@ -110,8 +107,8 @@ impl FromIterator> for Mesh

{ } } -impl FromIterator> for Mesh

{ - fn from_iter>>(quads: I) -> Self { +impl FromIterator> for Mesh { + fn from_iter>>(quads: I) -> Self { quads.into_iter().fold(Self::new(), |mut this, quad| { this.push_quad(quad); this @@ -120,33 +117,28 @@ impl FromIterator> for Mesh

{ } /// Represents a triangle stored on the CPU. -pub struct Tri { - a: P::Vertex, - b: P::Vertex, - c: P::Vertex, +pub struct Tri { + a: V, + b: V, + c: V, } -impl Tri

{ - pub fn new(a: P::Vertex, b: P::Vertex, c: P::Vertex) -> Self { Self { a, b, c } } +impl Tri { + pub fn new(a: V, b: V, c: V) -> Self { Self { a, b, c } } } /// Represents a quad stored on the CPU. -pub struct Quad { - a: P::Vertex, - b: P::Vertex, - c: P::Vertex, - d: P::Vertex, +pub struct Quad { + a: V, + b: V, + c: V, + d: V, } -impl Quad

{ - pub fn new(a: P::Vertex, b: P::Vertex, c: P::Vertex, d: P::Vertex) -> Self { - Self { a, b, c, d } - } +impl Quad { + pub fn new(a: V, b: V, c: V, d: V) -> Self { Self { a, b, c, d } } - pub fn rotated_by(self, n: usize) -> Self - where - P::Vertex: Clone, - { + pub fn rotated_by(self, n: usize) -> Self { let verts = [self.a, self.b, self.c, self.d]; Self { diff --git a/voxygen/src/render/mod.rs b/voxygen/src/render/mod.rs index 2c96ec0020..ec166f0106 100644 --- a/voxygen/src/render/mod.rs +++ b/voxygen/src/render/mod.rs @@ -1,3 +1,4 @@ +mod buffer; #[allow(clippy::single_component_path_imports)] // TODO: Pending review in #587 pub mod consts; mod error; @@ -44,25 +45,9 @@ pub use self::{ }, texture::Texture, }; -pub use gfx::texture::{FilterMethod, WrapMode}; +pub use wgpu::{AddressMode, FilterMode}; -#[cfg(feature = "gl")] -use gfx_device_gl as gfx_backend; - -/// Used to represent a specific rendering configuration. -/// -/// Note that pipelines are tied to the -/// rendering backend, and as such it is necessary to modify the rendering -/// subsystem when adding new pipelines - custom pipelines are not currently an -/// objective of the rendering subsystem. -/// -/// # Examples -/// -/// - `SkyboxPipeline` -/// - `FigurePipeline` -pub trait Pipeline { - type Vertex: Clone + gfx::traits::Pod + gfx::pso::buffer::Structure; -} +trait Vertex = Clone + zerocopy::AsBytes; use serde::{Deserialize, Serialize}; /// Anti-aliasing modes diff --git a/voxygen/src/render/model.rs b/voxygen/src/render/model.rs index 119f314feb..6d6ca3a7c8 100644 --- a/voxygen/src/render/model.rs +++ b/voxygen/src/render/model.rs @@ -1,69 +1,48 @@ -use super::{gfx_backend, mesh::Mesh, Pipeline, RenderError}; -use gfx::{ - buffer::Role, - memory::{Bind, Usage}, - traits::FactoryExt, - Factory, -}; +use super::{buffer::Buffer, mesh::Mesh, RenderError, Vertex}; use std::ops::Range; /// Represents a mesh that has been sent to the GPU. -pub struct Model { - pub vbuf: gfx::handle::Buffer, +pub struct SubModel<'a, V: Vertex> { pub vertex_range: Range, + buf: &'a wgpu::Buffer, + phantom_data: std::marker::PhantomData, } -impl Model

{ - pub fn new(factory: &mut gfx_backend::Factory, mesh: &Mesh

) -> Self { +impl<'a, V: Vertex> SubModel<'a, V> { + pub fn buf(&self) -> &wgpu::Buffer { self.buf } +} + +/// Represents a mesh that has been sent to the GPU. +pub struct Model { + vbuf: Buffer, +} + +impl Model { + pub fn new(device: &wgpu::Device, mesh: &Mesh) -> Self { Self { - vbuf: factory.create_vertex_buffer(mesh.vertices()), - vertex_range: 0..mesh.vertices().len() as u32, + vbuf: Buffer::new_with_data(device, wgpu::BufferUsage::VERTEX, mesh.vertices()), } } - pub fn vertex_range(&self) -> Range { self.vertex_range.clone() } - - /// Create a model with a slice of a portion of this model to send to the - /// renderer. - pub fn submodel(&self, vertex_range: Range) -> Model

{ - Model { - vbuf: self.vbuf.clone(), - vertex_range, - } - } -} - -/// Represents a mesh on the GPU which can be updated dynamically. -pub struct DynamicModel { - pub vbuf: gfx::handle::Buffer, -} - -impl DynamicModel

{ - pub fn new(factory: &mut gfx_backend::Factory, size: usize) -> Result { - Ok(Self { - vbuf: factory - .create_buffer(size, Role::Vertex, Usage::Dynamic, Bind::empty()) - .map_err(RenderError::BufferCreationError)?, - }) - } - /// Create a model with a slice of a portion of this model to send to the /// renderer. - pub fn submodel(&self, vertex_range: Range) -> Model

{ - Model { - vbuf: self.vbuf.clone(), + pub fn submodel(&self, vertex_range: Range) -> SubModel { + SubModel { vertex_range, + buf: self.buf(), + phantom_data: std::marker::PhantomData, } } pub fn update( - &self, - encoder: &mut gfx::Encoder, - mesh: &Mesh

, + &mut self, + device: &wgpu::Device, + queue: &wgpu::Queue, + mesh: &Mesh, offset: usize, ) -> Result<(), RenderError> { - encoder - .update_buffer(&self.vbuf, mesh.vertices(), offset) - .map_err(RenderError::UpdateError) + self.buf.update(device, queue, mesh.vertices(), offset) } + + pub fn buf(&self) -> &wgpu::Buffer { self.vbuf.buf } } diff --git a/voxygen/src/render/pipelines/figure.rs b/voxygen/src/render/pipelines/figure.rs index d9f5f45b74..a1afda3872 100644 --- a/voxygen/src/render/pipelines/figure.rs +++ b/voxygen/src/render/pipelines/figure.rs @@ -1,56 +1,28 @@ use super::{ - super::{Mesh, Model, Pipeline, TerrainPipeline, TgtColorFmt, TgtDepthStencilFmt}, + super::{Mesh, Model, TerrainPipeline, TgtColorFmt, TgtDepthStencilFmt}, shadow, Globals, Light, Shadow, }; use crate::mesh::greedy::GreedyMesh; -use gfx::{ - self, gfx_constant_struct_meta, gfx_defines, gfx_impl_struct_meta, gfx_pipeline, - gfx_pipeline_inner, state::ColorMask, -}; use vek::*; +use zerocopy::AsBytes; -gfx_defines! { - constant Locals { - model_mat: [[f32; 4]; 4] = "model_mat", - highlight_col: [f32; 4] = "highlight_col", - model_light: [f32; 4] = "model_light", - model_glow: [f32; 4] = "model_glow", - atlas_offs: [i32; 4] = "atlas_offs", - model_pos: [f32; 3] = "model_pos", - flags: u32 = "flags", - } +#[repr(C)] +#[derive(Copy, Clone, Debug, AsBytes)] +pub struct Locals { + model_mat: [[f32; 4]; 4], + highlight_col: [f32; 4], + model_light: [f32; 4], + model_glow: [f32; 4], + atlas_offs: [i32; 4], + model_pos: [f32; 3], + flags: u32, +} - constant BoneData { - bone_mat: [[f32; 4]; 4] = "bone_mat", - normals_mat: [[f32; 4]; 4] = "normals_mat", - } - - pipeline pipe { - vbuf: gfx::VertexBuffer<::Vertex> = (), - // abuf: gfx::VertexBuffer<::Vertex> = (), - col_lights: gfx::TextureSampler<[f32; 4]> = "t_col_light", - - locals: gfx::ConstantBuffer = "u_locals", - globals: gfx::ConstantBuffer = "u_globals", - bones: gfx::ConstantBuffer = "u_bones", - lights: gfx::ConstantBuffer = "u_lights", - shadows: gfx::ConstantBuffer = "u_shadows", - - point_shadow_maps: gfx::TextureSampler = "t_point_shadow_maps", - directed_shadow_maps: gfx::TextureSampler = "t_directed_shadow_maps", - - alt: gfx::TextureSampler<[f32; 2]> = "t_alt", - horizon: gfx::TextureSampler<[f32; 4]> = "t_horizon", - - noise: gfx::TextureSampler = "t_noise", - - // Shadow stuff - light_shadows: gfx::ConstantBuffer = "u_light_shadows", - - tgt_color: gfx::BlendTarget = ("tgt_color", ColorMask::all(), gfx::preset::blend::ALPHA), - tgt_depth_stencil: gfx::DepthTarget = gfx::preset::depth::LESS_EQUAL_WRITE, - // tgt_depth_stencil: gfx::DepthStencilTarget = (gfx::preset::depth::LESS_EQUAL_WRITE,Stencil::new(Comparison::Always,0xff,(StencilOp::Keep,StencilOp::Keep,StencilOp::Replace))), - } +#[repr(C)] +#[derive(Copy, Clone, Debug, AsBytes)] +pub struct BoneData { + bone_mat: [[f32; 4]; 4], + normals_mat: [[f32; 4]; 4], } impl Locals { @@ -76,6 +48,21 @@ impl Locals { flags, } } + + fn layout(device: &wgpu::Device) -> wgpu::BindGroupLayout { + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: None, + entries: &[wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::UniformBuffer { + dynamic: false, + min_binding_size: None, + }, + count: None, + }], + }) + } } impl Default for Locals { @@ -99,16 +86,39 @@ impl BoneData { normals_mat: normals_mat.into_col_arrays(), } } + + fn layout(device: &wgpu::Device) -> wgpu::BindGroupLayout { + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: None, + entries: &[wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::UniformBuffer { + dynamic: false, + min_binding_size: None, + }, + count: None, + }], + }) + } } impl Default for BoneData { fn default() -> Self { Self::new(anim::vek::Mat4::identity(), anim::vek::Mat4::identity()) } } -pub struct FigurePipeline; +pub struct FigureLayout { + pub locals: wgpu::BindGroupLayout, + pub bone_data: wgpu::BindGroupLayout, +} -impl Pipeline for FigurePipeline { - type Vertex = ::Vertex; +impl FigureLayout { + pub fn new(device: &wgpu::Device) -> Self { + Self { + locals: Locals::locals_layout(device), + bone_data: BoneData::bone_data_layout(device), + } + } } pub struct FigureModel { @@ -130,3 +140,49 @@ impl FigureModel { } pub type BoneMeshes = (Mesh, anim::vek::Aabb); + +//gfx_defines! { +// constant Locals { +// model_mat: [[f32; 4]; 4] = "model_mat", +// highlight_col: [f32; 4] = "highlight_col", +// model_light: [f32; 4] = "model_light", +// atlas_offs: [i32; 4] = "atlas_offs", +// model_pos: [f32; 3] = "model_pos", +// flags: u32 = "flags", +// } +// +// constant BoneData { +// bone_mat: [[f32; 4]; 4] = "bone_mat", +// normals_mat: [[f32; 4]; 4] = "normals_mat", +// } +// +// pipeline pipe { +// vbuf: gfx::VertexBuffer<::Vertex> = (), +// // abuf: gfx::VertexBuffer<::Vertex> = +// (), col_lights: gfx::TextureSampler<[f32; 4]> = "t_col_light", +// +// locals: gfx::ConstantBuffer = "u_locals", +// globals: gfx::ConstantBuffer = "u_globals", +// bones: gfx::ConstantBuffer = "u_bones", +// lights: gfx::ConstantBuffer = "u_lights", +// shadows: gfx::ConstantBuffer = "u_shadows", +// +// point_shadow_maps: gfx::TextureSampler = "t_point_shadow_maps", +// directed_shadow_maps: gfx::TextureSampler = +// "t_directed_shadow_maps", +// +// alt: gfx::TextureSampler<[f32; 2]> = "t_alt", +// horizon: gfx::TextureSampler<[f32; 4]> = "t_horizon", +// +// noise: gfx::TextureSampler = "t_noise", +// +// // Shadow stuff +// light_shadows: gfx::ConstantBuffer = +// "u_light_shadows", +// +// tgt_color: gfx::BlendTarget = ("tgt_color", +// ColorMask::all(), gfx::preset::blend::ALPHA), tgt_depth_stencil: +// gfx::DepthTarget = gfx::preset::depth::LESS_EQUAL_WRITE, +// // tgt_depth_stencil: gfx::DepthStencilTarget = +// (gfx::preset::depth::LESS_EQUAL_WRITE,Stencil::new(Comparison::Always,0xff, +// (StencilOp::Keep,StencilOp::Keep,StencilOp::Replace))), } diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index d83048baa7..05ffcc6891 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -1,28 +1,21 @@ use super::{ consts::Consts, - gfx_backend, instances::Instances, mesh::Mesh, - model::{DynamicModel, Model}, + model::{Model}, pipelines::{ clouds, figure, fluid, lod_terrain, particle, postprocess, shadow, skybox, sprite, terrain, ui, GlobalModel, Globals, }, texture::Texture, - AaMode, CloudMode, FilterMethod, FluidMode, LightingMode, Pipeline, RenderError, RenderMode, - ShadowMapMode, ShadowMode, WrapMode, + AaMode, CloudMode, FilterMode, FluidMode, LightingMode, RenderError, RenderMode, + ShadowMapMode, ShadowMode, AddressMode, }; use common::assets::{self, AssetExt, AssetHandle}; use common_base::span; use core::convert::TryFrom; -use gfx::{ - self, - handle::Sampler, - state::Comparison, - traits::{Device, Factory, FactoryExt}, -}; use glsl_include::Context as IncludeContext; -use tracing::{error, warn}; +use tracing::{error, info, warn}; use vek::*; /// Represents the format of the pre-processed color target. @@ -225,13 +218,11 @@ impl assets::Compound for Shaders { pub struct ShadowMapRenderer { // directed_encoder: gfx::Encoder, // point_encoder: gfx::Encoder, - directed_depth_stencil_view: ShadowDepthStencilView, - directed_res: ShadowResourceView, - directed_sampler: Sampler, + directed_depth_stencil_view: wgpu::TextureView, + directed_sampler: wgpu::Sampler, - point_depth_stencil_view: ShadowDepthStencilView, - point_res: ShadowResourceView, - point_sampler: Sampler, + point_depth_stencil_view: wgpu::TextureView, + point_sampler: wgpu::Sampler, point_pipeline: GfxPipeline>, terrain_directed_pipeline: GfxPipeline>, @@ -243,22 +234,18 @@ pub struct ShadowMapRenderer { /// GPU, along with pipeline state objects (PSOs) needed to renderer different /// kinds of models to the screen. pub struct Renderer { - device: gfx_backend::Device, - encoder: gfx::Encoder, - factory: gfx_backend::Factory, + device: wgpu::Device, + queue: wgpu::Queue, + swap_chain: wgpu::SwapChain, - win_color_view: WinColorView, - win_depth_view: WinDepthView, + win_depth_view: wgpu::TextureView, - tgt_color_view: TgtColorView, - tgt_depth_stencil_view: TgtDepthStencilView, - tgt_color_view_pp: TgtColorView, + tgt_color_view: wgpu::TextureView, + tgt_depth_stencil_view: wgpu::TextureView, + // TODO: rename + tgt_color_pp_view: wgpu::TextureView, - tgt_color_res: TgtColorRes, - tgt_depth_res: TgtDepthRes, - tgt_color_res_pp: TgtColorRes, - - sampler: Sampler, + sampler: wgpu::Sampler, shadow_map: Option, @@ -285,11 +272,8 @@ pub struct Renderer { impl Renderer { /// Create a new `Renderer` from a variety of backend-specific components /// and the window targets. - pub fn new( - mut device: gfx_backend::Device, - mut factory: gfx_backend::Factory, - win_color_view: WinColorView, - win_depth_view: WinDepthView, + pub async fn new( + window: &winit::window::Window, mode: RenderMode, ) -> Result { // Enable seamless cubemaps globally, where available--they are essentially a @@ -297,12 +281,59 @@ impl Renderer { // // Note that since we only have to enable this once globally, there is no point // in doing this on rerender. - Self::enable_seamless_cube_maps(&mut device); + // Self::enable_seamless_cube_maps(&mut device); - let dims = win_color_view.get_dimensions(); + let dims = window.inner_size(); + + let instance = wgpu::Instance::new(wgpu::BackendBit::PRIMARY | wgpu::BackendBit::SECONDARY); + + // This is unsafe because the window handle must be valid, if you find a way to + // have an invalid winit::Window then you have bigger issues + #[allow(unsafe_code)] + let surface = unsafe { instance.create_surface(window) }; + + let adapter = instance + .request_adapter(wgpu::RequestAdapterOptionsBase { + power_preference: wgpu::PowerPreference::HighPerformance, + compatible_surface: Some(surface), + }) + .await + .ok_or(RenderError::CouldNotFindAdapter)?; + + use wgpu::{Features, Limits}; + + let (device, queue) = adapter + .request_device( + wgpu::DeviceDescriptor { + // TODO + features: Features::DEPTH_CLAMPING, + limits: Limits::default(), + shader_validation: true, + }, + None, + ) + .await?; + + let info = device.get_info(); + info!( + ?info.name, + ?info.vendor, + ?info.backend, + ?info.device, + ?info.device_type, + "selected graphics device" + ); + + let swap_chain = device.create_swap_chain(&surface, &wgpu::SwapChainDescriptor { + usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, + format: wgpu::TextureFormat::Bgra8UnormSrgb, + width: dims.0, + height: dims.1, + present_mode: wgpu::PresentMode::Immediate, + }); let shadow_views = Self::create_shadow_views( - &mut factory, + &device, (dims.0, dims.1), &ShadowMapMode::try_from(mode.shadow).unwrap_or_default(), ) @@ -328,16 +359,18 @@ impl Renderer { point_shadow_pipeline, terrain_directed_shadow_pipeline, figure_directed_shadow_pipeline, - ) = create_pipelines(&mut factory, &shaders.read(), &mode, shadow_views.is_some())?; + ) = create_pipelines( + &device, + &mode, + shadow_views.is_some(), + )?; let ( tgt_color_view, tgt_depth_stencil_view, - tgt_color_view_pp, - tgt_color_res, - tgt_depth_res, - tgt_color_res_pp, - ) = Self::create_rt_views(&mut factory, (dims.0, dims.1), &mode)?; + tgt_color_pp_view, + win_depth_view, + ) = Self::create_rt_views(&device, (dims.0, dims.1), &mode)?; let shadow_map = if let ( Some(point_pipeline), @@ -360,13 +393,11 @@ impl Renderer { ) = shadow_views; Some(ShadowMapRenderer { directed_depth_stencil_view, - directed_res, directed_sampler, // point_encoder: factory.create_command_buffer().into(), // directed_encoder: factory.create_command_buffer().into(), point_depth_stencil_view, - point_res, point_sampler, point_pipeline, @@ -377,34 +408,36 @@ impl Renderer { None }; - let sampler = factory.create_sampler(gfx::texture::SamplerInfo::new( - gfx::texture::FilterMethod::Bilinear, - gfx::texture::WrapMode::Clamp, - )); + let sampler = device.create_sampler(&wgpu::SamplerDescriptor { + label: None, + address_mode_u: wgpu::AddressMode::ClampToEdge, + address_mode_v: wgpu::AddressMode::ClampToEdge, + address_mode_w: wgpu::AddressMode::ClampToEdge, + mag_filter: wgpu::FilterMode::Linear, + min_filter: wgpu::FilterMode::Linear, + mipmap_filter: wgpu::FilterMode::Nearest, + compare: None, + ..Default::default() + }); let noise_tex = Texture::new( - &mut factory, + &device, + &queue, &assets::Image::load_expect("voxygen.texture.noise").read().0, - Some(gfx::texture::FilterMethod::Trilinear), - Some(gfx::texture::WrapMode::Tile), - None, + Some(wgpu::FilterMode::Linear), + Some(wgpu::AddressMode::Repeat), )?; Ok(Self { device, - encoder: factory.create_command_buffer().into(), - factory, + queue, + swap_chain, - win_color_view, win_depth_view, tgt_color_view, tgt_depth_stencil_view, - tgt_color_view_pp, - - tgt_color_res, - tgt_depth_res, - tgt_color_res_pp, + tgt_color_pp_view, sampler, @@ -483,7 +516,7 @@ impl Renderer { let ( tgt_color_view, tgt_depth_stencil_view, - tgt_color_view_pp, + tgt_color_pp_view, tgt_color_res, tgt_depth_res, tgt_color_res_pp, @@ -493,7 +526,7 @@ impl Renderer { self.tgt_color_res_pp = tgt_color_res_pp; self.tgt_color_view = tgt_color_view; self.tgt_depth_stencil_view = tgt_depth_stencil_view; - self.tgt_color_view_pp = tgt_color_view_pp; + self.tgt_color_pp_view = tgt_color_pp_view; if let (Some(shadow_map), ShadowMode::Map(mode)) = (self.shadow_map.as_mut(), self.mode.shadow) { @@ -525,90 +558,103 @@ impl Renderer { } fn create_rt_views( - factory: &mut gfx_device_gl::Factory, + device: &wgpu::Device, size: (u16, u16), mode: &RenderMode, - ) -> Result< - ( - TgtColorView, - TgtDepthStencilView, - TgtColorView, - TgtColorRes, - TgtDepthRes, - TgtColorRes, - ), - RenderError, - > { + ) -> Result<(wgpu::TextureView, wgpu::TextureView, wgpu::TextureView, wgpu::TextureView), RenderError> { let upscaled = Vec2::from(size) .map(|e: u16| (e as f32 * mode.upscale_mode.factor) as u16) .into_tuple(); - let kind = match mode.aa { - AaMode::None | AaMode::Fxaa => { - gfx::texture::Kind::D2(upscaled.0, upscaled.1, gfx::texture::AaMode::Single) - }, + let (width, height, sample_count) = match mode.aa { + AaMode::None | AaMode::Fxaa => (upscaled.0, upscaled.1, 1), // TODO: Ensure sampling in the shader is exactly between the 4 texels - AaMode::MsaaX4 => { - gfx::texture::Kind::D2(upscaled.0, upscaled.1, gfx::texture::AaMode::Multi(4)) - }, - AaMode::MsaaX8 => { - gfx::texture::Kind::D2(upscaled.0, upscaled.1, gfx::texture::AaMode::Multi(8)) - }, - AaMode::MsaaX16 => { - gfx::texture::Kind::D2(upscaled.0, upscaled.1, gfx::texture::AaMode::Multi(16)) - }, + // TODO: Figure out how to do upscaling correctly with SSAA + AaMode::MsaaX4 => (upscaled.0, upscaled.1, 4), + AaMode::MsaaX8 => (upscaled.0, upscaled.1, 8), + AaMode::MsaaX16 => (upscaled.0, upscaled.1, 16), }; let levels = 1; - let color_cty = <::Channel as gfx::format::ChannelTyped - >::get_channel_type(); - let mut color_tex = || { - factory.create_texture( - kind, - levels, - gfx::memory::Bind::SHADER_RESOURCE | gfx::memory::Bind::RENDER_TARGET, - gfx::memory::Usage::Data, - Some(color_cty), - ) - }; - let tgt_color_tex = color_tex()?; - let tgt_color_tex_pp = color_tex()?; - let mut color_res = |tex| { - factory.view_texture_as_shader_resource::( - tex, - (0, levels - 1), - gfx::format::Swizzle::new(), - ) - }; - let tgt_color_res = color_res(&tgt_color_tex)?; - let tgt_color_res_pp = color_res(&tgt_color_tex_pp)?; - let tgt_color_view = factory.view_texture_as_render_target(&tgt_color_tex, 0, None)?; - let tgt_color_view_pp = - factory.view_texture_as_render_target(&tgt_color_tex_pp, 0, None)?; + let mut color_view = || { + let tex = device.create_texture(&wgpu::TextureDescriptor { + label: None, + size: wgpu::Extent3d { + width, + height, + depth: 1, + }, + mip_level_count: levels, + sample_count, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Rgba8UnormSrgb, + usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::OUTPUT_ATTACHMENT, + }); - let depth_stencil_cty = <::Channel as gfx::format::ChannelTyped>::get_channel_type(); - let tgt_depth_stencil_tex = factory.create_texture( - kind, - levels, - gfx::memory::Bind::SHADER_RESOURCE | gfx::memory::Bind::DEPTH_STENCIL, - gfx::memory::Usage::Data, - Some(depth_stencil_cty), - )?; - let tgt_depth_res = factory.view_texture_as_shader_resource::( - &tgt_depth_stencil_tex, - (0, levels - 1), - gfx::format::Swizzle::new(), - )?; + tex.create_view(&wgpu::TextureViewDescriptor { + label: None, + format: Some(wgpu::TextureFormat::Rgba8UnormSrgb), + dimension: Some(wgpu::TextureViewDimension::D2), + aspect: wgpu::TextureAspect::Color, + base_mip_level: 0, + level_count: Some(levels), + base_array_layer: 0, + array_layer_count: None, + }) + }; + + let tgt_color_view = color_view(); + let tgt_color_pp_view = color_view(); + + let tgt_depth_stencil_tex = device.create_texture(&wgpu::TextureDescriptor { + label: None, + size: wgpu::Extent3d { + width, + height, + depth: 1, + }, + mip_level_count: levels, + sample_count, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Depth24Plus, + usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::OUTPUT_ATTACHMENT, + }); let tgt_depth_stencil_view = - factory.view_texture_as_depth_stencil_trivial(&tgt_depth_stencil_tex)?; + tgt_depth_stencil_tex.create_view(&wgpu::TextureViewDescriptor { + label: None, + format: Some(wgpu::TextureFormat::Depth24Plus), + dimension: Some(wgpu::TextureViewDimension::D2), + aspect: wgpu::TextureAspect::DepthOnly, + base_mip_level: 0, + level_count: Some(levels), + base_array_layer: 0, + array_layer_count: None, + }); - Ok(( - tgt_color_view, - tgt_depth_stencil_view, - tgt_color_view_pp, - tgt_color_res, - tgt_depth_res, - tgt_color_res_pp, - )) + let win_depth_tex = device.create_texture(&wgpu::TextureDescriptor { + label: None, + size: wgpu::Extent3d { + width: size.0, + height: size.1, + depth: 1, + }, + mip_level_count: levels, + sample_count, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Depth24Plus, + usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, + }); + let win_depth_view = tgt_depth_stencil_tex.create_view(&wgpu::TextureViewDescriptor { + label: None, + format: Some(wgpu::TextureFormat::Depth24Plus), + dimension: Some(wgpu::TextureViewDimension::D2), + aspect: wgpu::TextureAspect::DepthOnly, + base_mip_level: 0, + level_count: Some(levels), + base_array_layer: 0, + array_layer_count: None, + }); + + Ok((tgt_color_view, tgt_depth_stencil_view, tgt_color_pp_view, win_depth_view)) } /// Create textures and views for shadow maps. @@ -616,24 +662,24 @@ impl Renderer { // disable the type complexity lint. #[allow(clippy::type_complexity)] fn create_shadow_views( - factory: &mut gfx_device_gl::Factory, + device: &wgpu::Device, size: (u16, u16), mode: &ShadowMapMode, ) -> Result< ( - ShadowDepthStencilView, - ShadowResourceView, - Sampler, - ShadowDepthStencilView, - ShadowResourceView, - Sampler, + wgpu::TextureView, + wgpu::Sampler, + wgpu::TextureView, + wgpu::Sampler, ), RenderError, > { // (Attempt to) apply resolution factor to shadow map resolution. let resolution_factor = mode.resolution.clamped(0.25, 4.0); - let max_texture_size = Self::max_texture_size_raw(factory); + // This value is temporary as there are plans to include a way to get this in + // wgpu this is just a sane standard for now + let max_texture_size = 8000; // Limit to max texture size, rather than erroring. let size = Vec2::new(size.0, size.1).map(|e| { let size = f32::from(e) * resolution_factor; @@ -677,72 +723,76 @@ impl Renderer { .filter(|&e| e <= max_texture_size) // Limit to max texture resolution rather than error. .unwrap_or(max_texture_size); - let depth_stencil_cty = <::Channel as gfx::format::ChannelTyped>::get_channel_type(); - let point_shadow_tex = factory - .create_texture( - gfx::texture::Kind::Cube(diag_two_size / 4), - levels as gfx::texture::Level, - gfx::memory::Bind::SHADER_RESOURCE | gfx::memory::Bind::DEPTH_STENCIL, - gfx::memory::Usage::Data, - Some(depth_stencil_cty), - ) - .map_err(|err| RenderError::CombinedError(gfx::CombinedError::Texture(err)))?; + let point_shadow_tex = device.create_texture(&wgpu::TextureDescriptor { + label: None, + size: wgpu::Extent3d { + width: diag_two_size / 4, + height: diag_two_size / 4, + depth: 6, + }, + mip_level_count: levels, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Depth24Plus, + usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::OUTPUT_ATTACHMENT, + }); - let point_tgt_shadow_view = factory - .view_texture_as_depth_stencil::( - &point_shadow_tex, - 0, - None, - gfx::texture::DepthStencilFlags::empty(), - )?; + let point_tgt_shadow_view = point_shadow_tex.create_view(&wgpu::TextureViewDescriptor { + label: None, + format: Some(wgpu::TextureFormat::Depth24Plus), + dimension: Some(wgpu::TextureViewDimension::Cube), + aspect: wgpu::TextureAspect::DepthOnly, + base_mip_level: 0, + level_count: Some(levels), + base_array_layer: 0, + array_layer_count: None, + }); - let point_tgt_shadow_res = factory - .view_texture_as_shader_resource::( - &point_shadow_tex, - (0, levels - 1), - gfx::format::Swizzle::new(), - )?; + let directed_shadow_tex = device.create_texture(&wgpu::TextureDescriptor { + label: None, + size: wgpu::Extent3d { + width: diag_two_size, + height: diag_two_size, + depth: 1, + }, + mip_level_count: levels, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Depth24Plus, + usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::OUTPUT_ATTACHMENT, + }); - let directed_shadow_tex = factory - .create_texture( - gfx::texture::Kind::D2(diag_two_size, diag_two_size, gfx::texture::AaMode::Single), - levels as gfx::texture::Level, - gfx::memory::Bind::SHADER_RESOURCE | gfx::memory::Bind::DEPTH_STENCIL, - gfx::memory::Usage::Data, - Some(depth_stencil_cty), - ) - .map_err(|err| RenderError::CombinedError(gfx::CombinedError::Texture(err)))?; - let directed_tgt_shadow_view = factory - .view_texture_as_depth_stencil::( - &directed_shadow_tex, - 0, - None, - gfx::texture::DepthStencilFlags::empty(), - )?; - let directed_tgt_shadow_res = factory - .view_texture_as_shader_resource::( - &directed_shadow_tex, - (0, levels - 1), - gfx::format::Swizzle::new(), - )?; + let directed_tgt_shadow_view = point_shadow_tex.create_view(&wgpu::TextureViewDescriptor { + label: None, + format: Some(wgpu::TextureFormat::Depth24Plus), + dimension: Some(wgpu::TextureViewDimension::D2), + aspect: wgpu::TextureAspect::DepthOnly, + base_mip_level: 0, + level_count: Some(levels), + base_array_layer: 0, + array_layer_count: None, + }); - let mut sampler_info = gfx::texture::SamplerInfo::new( - gfx::texture::FilterMethod::Bilinear, - // Lights should always be assumed to flood areas we can't see. - gfx::texture::WrapMode::Border, - ); - sampler_info.comparison = Some(Comparison::LessEqual); - sampler_info.border = [1.0; 4].into(); - let point_shadow_tex_sampler = factory.create_sampler(sampler_info); - let directed_shadow_tex_sampler = factory.create_sampler(sampler_info); + let sampler_info = wgpu::SamplerDescriptor { + label: None, + address_mode_u: wgpu::AddressMode::ClampToEdge, + address_mode_v: wgpu::AddressMode::ClampToEdge, + address_mode_w: wgpu::AddressMode::ClampToEdge, + mag_filter: wgpu::FilterMode::Linear, + min_filter: wgpu::FilterMode::Linear, + mipmap_filter: wgpu::FilterMode::Nearest, + compare: Some(wgpu::CompareFunction::LessEqual), + ..Default::default() + }; + + let point_shadow_tex_sampler = device.create_sampler(&sampler_info); + let directed_shadow_tex_sampler = device.create_sampler(&sampler_info); Ok(( point_tgt_shadow_view, - point_tgt_shadow_res, point_shadow_tex_sampler, directed_tgt_shadow_view, - directed_tgt_shadow_res, directed_shadow_tex_sampler, )) } @@ -797,51 +847,22 @@ impl Renderer { /// available. #[allow(unsafe_code)] fn enable_seamless_cube_maps(device: &mut gfx_backend::Device) { - unsafe { - // NOTE: Currently just fail silently rather than complain if the computer is on - // a version lower than 3.2, where seamless cubemaps were introduced. - if !device.get_info().is_version_supported(3, 2) { - return; - } + todo!() + // unsafe { + // // NOTE: Currently just fail silently rather than complain if the + // computer is on // a version lower than 3.2, where + // seamless cubemaps were introduced. if !device.get_info(). + // is_version_supported(3, 2) { return; + // } - // NOTE: Safe because GL_TEXTURE_CUBE_MAP_SEAMLESS is supported by OpenGL 3.2+ - // (see https://www.khronos.org/opengl/wiki/Cubemap_Texture#Seamless_cubemap); - // enabling seamless cube maps should always be safe regardless of the state of - // the OpenGL context, so no further checks are needed. - device.with_gl(|gl| { - gl.Enable(gfx_gl::TEXTURE_CUBE_MAP_SEAMLESS); - }); - } - } - - /// NOTE: Supported by all but a handful of mobile GPUs - /// (see https://github.com/gpuweb/gpuweb/issues/480) - /// so wgpu should support it too. - #[allow(unsafe_code)] - fn set_depth_clamp(device: &mut gfx_backend::Device, depth_clamp: bool) { - unsafe { - // NOTE: Currently just fail silently rather than complain if the computer is on - // a version lower than 3.3, though we probably will complain - // elsewhere regardless, since shadow mapping is an optional feature - // and having depth clamping disabled won't cause undefined - // behavior, just incorrect shadowing from objects behind the viewer. - if !device.get_info().is_version_supported(3, 3) { - return; - } - - // NOTE: Safe because glDepthClamp is (I believe) supported by - // OpenGL 3.3, so we shouldn't have to check for other OpenGL versions which - // may use different extensions. Also, enabling depth clamping should - // essentially always be safe regardless of the state of the OpenGL - // context, so no further checks are needed. - device.with_gl(|gl| { - if depth_clamp { - gl.Enable(gfx_gl::DEPTH_CLAMP); - } else { - gl.Disable(gfx_gl::DEPTH_CLAMP); - } - }); - } + // // NOTE: Safe because GL_TEXTURE_CUBE_MAP_SEAMLESS is supported + // by OpenGL 3.2+ // (see https://www.khronos.org/opengl/wiki/Cubemap_Texture#Seamless_cubemap); + // // enabling seamless cube maps should always be safe regardless + // of the state of // the OpenGL context, so no further + // checks are needed. device.with_gl(|gl| { + // gl.Enable(gfx_gl::TEXTURE_CUBE_MAP_SEAMLESS); + // }); + // } } /// Queue the clearing of the depth target ready for a new frame to be @@ -1109,47 +1130,58 @@ impl Renderer { /// a image::DynamicImage. #[allow(clippy::map_clone)] // TODO: Pending review in #587 pub fn create_screenshot(&mut self) -> Result { - let (width, height) = self.get_resolution().into_tuple(); - use gfx::{ - format::{Formatted, SurfaceTyped}, - memory::Typed, - }; - type WinSurfaceData = <::Surface as SurfaceTyped>::DataType; - let download = self - .factory - .create_download_buffer::(width as usize * height as usize)?; - self.encoder.copy_texture_to_buffer_raw( - self.win_color_view.raw().get_texture(), - None, - gfx::texture::RawImageInfo { - xoffset: 0, - yoffset: 0, - zoffset: 0, - width, - height, - depth: 0, - format: WinColorFmt::get_format(), - mipmap: 0, - }, - download.raw(), - 0, - )?; - self.flush(); + todo!() + // let (width, height) = self.get_resolution().into_tuple(); - // Assumes that the format is Rgba8. - let raw_data = self - .factory - .read_mapping(&download)? - .chunks_exact(width as usize) - .rev() - .flatten() - .flatten() - .map(|&e| e) - .collect::>(); - Ok(image::DynamicImage::ImageRgba8( - // Should not fail if the dimensions are correct. - image::ImageBuffer::from_raw(width as u32, height as u32, raw_data).unwrap(), - )) + // let download_buf = self + // .device + // .create_buffer(&wgpu::BufferDescriptor { + // label: None, + // size: width * height * 4, + // usage : wgpu::BufferUsage::COPY_DST, + // mapped_at_creation: true + // }); + + // let encoder = + // self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor + // {label: None}); + + // encoder.copy_texture_to_buffer(&wgpu::TextureCopyViewBase { + // origin: &self.wi + // }, destination, copy_size) + + // self.encoder.copy_texture_to_buffer_raw( + // self.win_color_view.raw().get_texture(), + // None, + // gfx::texture::RawImageInfo { + // xoffset: 0, + // yoffset: 0, + // zoffset: 0, + // width, + // height, + // depth: 0, + // format: WinColorFmt::get_format(), + // mipmap: 0, + // }, + // download.raw(), + // 0, + // )?; + // self.flush(); + + // // Assumes that the format is Rgba8. + // let raw_data = self + // .factory + // .read_mapping(&download)? + // .chunks_exact(width as usize) + // .rev() + // .flatten() + // .flatten() + // .map(|&e| e) + // .collect::>(); + // Ok(image::DynamicImage::ImageRgba8( + // // Should not fail if the dimensions are correct. + // image::ImageBuffer::from_raw(width as u32, height as u32, + // raw_data).unwrap(), )) } /// Queue the rendering of the provided skybox model in the upcoming frame. @@ -1825,7 +1857,7 @@ impl Renderer { color_sampler: (self.tgt_color_res.clone(), self.sampler.clone()), depth_sampler: (self.tgt_depth_res.clone(), self.sampler.clone()), noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()), - tgt_color: self.tgt_color_view_pp.clone(), + tgt_color: self.tgt_color_pp_view.clone(), }, ) } diff --git a/voxygen/src/render/texture.rs b/voxygen/src/render/texture.rs index ae9edbced1..993971e162 100644 --- a/voxygen/src/render/texture.rs +++ b/voxygen/src/render/texture.rs @@ -1,38 +1,22 @@ -use super::{gfx_backend, RenderError}; -use gfx::{self, traits::Factory}; +use super::RenderError; use image::{DynamicImage, GenericImageView}; use vek::Vec2; - -type DefaultShaderFormat = (gfx::format::R8_G8_B8_A8, gfx::format::Srgb); +use wgpu::{util::DeviceExt, Extent3d}; /// Represents an image that has been uploaded to the GPU. -#[derive(Clone)] -pub struct Texture -where - F::Surface: gfx::format::TextureSurface, - F::Channel: gfx::format::TextureChannel, - ::DataType: Copy, -{ - pub tex: gfx::handle::Texture::Surface>, - pub srv: gfx::handle::ShaderResourceView< - gfx_backend::Resources, - ::View, - >, - pub sampler: gfx::handle::Sampler, +pub struct Texture { + pub tex: wgpu::TextureView, + pub sampler: wgpu::Sampler, + size: Extent3d, } -impl Texture -where - F::Surface: gfx::format::TextureSurface, - F::Channel: gfx::format::TextureChannel, - ::DataType: Copy, -{ +impl Texture { pub fn new( - factory: &mut gfx_backend::Factory, + device: &wgpu::Device, + queue: &wgpu::Queue, image: &DynamicImage, - filter_method: Option, - wrap_mode: Option, - border: Option, + filter_method: Option, + addresse_mode: Option, ) -> Result { // TODO: Actualy handle images that aren't in rgba format properly. let buffer = image.as_flat_samples_u8().ok_or_else(|| { @@ -40,147 +24,143 @@ where "We currently do not support color formats using more than 4 bytes / pixel.".into(), ) })?; - let (tex, srv) = factory - .create_texture_immutable_u8::( - gfx::texture::Kind::D2( - image.width() as u16, - image.height() as u16, - gfx::texture::AaMode::Single, - ), - gfx::texture::Mipmap::Provided, - // Guarenteed to be correct, since all the conversions from DynamicImage to - // FlatSamples go through the underlying ImageBuffer's implementation of - // as_flat_samples(), which guarantees that the resulting FlatSamples is - // well-formed. - &[buffer.as_slice()], - ) - .map_err(RenderError::CombinedError)?; - let mut sampler_info = gfx::texture::SamplerInfo::new( - filter_method.unwrap_or(gfx::texture::FilterMethod::Scale), - wrap_mode.unwrap_or(gfx::texture::WrapMode::Clamp), + let size = Extent3d { + width: image.width(), + height: image.height(), + depth: 1, + }; + + let tex = device.create_texture(&wgpu::TextureDescriptor { + label: None, + size, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Rgba8UnormSrgb, + usage: wgpu::TextureUsage::COPY_DST | wgpu::TextureUsage::SAMPLED, + }); + + let mut command_encoder = + device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); + + queue.write_texture( + wgpu::TextureCopyViewBase { + texture: &tex, + mip_level: 0, + origin: wgpu::Origin3d::ZERO, + }, + &[buffer.as_slice()], + wgpu::TextureDataLayout { + offset: 0, + bytes_per_row: image.width() * 4, + rows_per_image: image.height(), + }, + wgpu::Extent3d { + width: image.width(), + height: image.height(), + depth: 1, + }, ); - let transparent = [0.0, 0.0, 0.0, 1.0].into(); - sampler_info.border = border.unwrap_or(transparent); + + let sampler_info = wgpu::SamplerDescriptor { + label: None, + address_mode_u: addresse_mode.unwrap_or(wgpu::AddressMode::ClampToEdge), + address_mode_v: addresse_mode.unwrap_or(wgpu::AddressMode::ClampToEdge), + address_mode_w: addresse_mode.unwrap_or(wgpu::AddressMode::ClampToEdge), + mag_filter: filter_method.unwrap_or(wgpu::FilterMode::Nearest), + min_filter: filter_method.unwrap_or(wgpu::FilterMode::Nearest), + mipmap_filter: wgpu::FilterMode::Nearest, + ..Default::default() + }; + Ok(Self { tex, - srv, - sampler: factory.create_sampler(sampler_info), + sampler: device.create_sampler(&sampler_info), + size, }) } - pub fn new_dynamic( - factory: &mut gfx_backend::Factory, - width: u16, - height: u16, - ) -> Result { - let tex = factory.create_texture( - gfx::texture::Kind::D2( - width, - height, - gfx::texture::AaMode::Single, - ), - 1_u8, - gfx::memory::Bind::SHADER_RESOURCE, - gfx::memory::Usage::Dynamic, - Some(<::Channel as gfx::format::ChannelTyped>::get_channel_type()), - ) - .map_err(|err| RenderError::CombinedError(gfx::CombinedError::Texture(err)))?; + pub fn new_dynamic(device: &wgpu::Device, width: u16, height: u16) -> Self { + let size = wgpu::Extent3d { + width, + height, + depth: 1, + }; - let srv = factory - .view_texture_as_shader_resource::(&tex, (0, 0), gfx::format::Swizzle::new()) - .map_err(|err| RenderError::CombinedError(gfx::CombinedError::Resource(err)))?; + let tex_info = device.create_texture(&wgpu::TextureDescriptor { + label: None, + size, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Rgba8UnormSrgb, + usage: wgpu::TextureUsage::COPY_DST | wgpu::TextureUsage::SAMPLED, + }); - Ok(Self { - tex, - srv, - sampler: factory.create_sampler(gfx::texture::SamplerInfo::new( - gfx::texture::FilterMethod::Scale, - gfx::texture::WrapMode::Clamp, - )), - }) - } + let sampler_info = wgpu::SamplerDescriptor { + label: None, + address_mode_u: wgpu::AddressMode::ClampToEdge, + address_mode_v: wgpu::AddressMode::ClampToEdge, + address_mode_w: wgpu::AddressMode::ClampToEdge, + mag_filter: wgpu::FilterMode::Nearest, + min_filter: wgpu::FilterMode::Nearest, + mipmap_filter: wgpu::FilterMode::Nearest, + ..Default::default() + }; - pub fn new_immutable_raw( - factory: &mut gfx_backend::Factory, - kind: gfx::texture::Kind, - mipmap: gfx::texture::Mipmap, - data: &[&[::DataType]], - sampler_info: gfx::texture::SamplerInfo, - ) -> Result { - let (tex, srv) = factory - .create_texture_immutable::(kind, mipmap, data) - .map_err(RenderError::CombinedError)?; - - Ok(Self { - tex, - srv, - sampler: factory.create_sampler(sampler_info), - }) + Self::new_raw(device, tex_info, sampler_info) } pub fn new_raw( - _device: &mut gfx_backend::Device, - factory: &mut gfx_backend::Factory, - kind: gfx::texture::Kind, - max_levels: u8, - bind: gfx::memory::Bind, - usage: gfx::memory::Usage, - levels: (u8, u8), - swizzle: gfx::format::Swizzle, - sampler_info: gfx::texture::SamplerInfo, - ) -> Result { - let tex = factory - .create_texture( - kind, - max_levels as gfx::texture::Level, - bind | gfx::memory::Bind::SHADER_RESOURCE, - usage, - Some(<::Channel as gfx::format::ChannelTyped>::get_channel_type()) - ) - .map_err(|err| RenderError::CombinedError(gfx::CombinedError::Texture(err)))?; - - let srv = factory - .view_texture_as_shader_resource::(&tex, levels, swizzle) - .map_err(|err| RenderError::CombinedError(gfx::CombinedError::Resource(err)))?; - + device: &wgpu::Device, + texture_info: wgpu::TextureDescriptor, + sampler_info: wgpu::SamplerDescriptor, + ) -> Self { Ok(Self { - tex, - srv, - sampler: factory.create_sampler(sampler_info), + tex: device.create_texture(&texture_info), + sampler: device.create_sampler(&sampler_info), + size: texture_info.size, }) } /// Update a texture with the given data (used for updating the glyph cache /// texture). - pub fn update( &self, - encoder: &mut gfx::Encoder, + device: &wgpu::Device, + queue: &wgpu::Queue, offset: [u16; 2], size: [u16; 2], - data: &[::DataType], + data: &[u8], ) -> Result<(), RenderError> { - let info = gfx::texture::ImageInfoCommon { - xoffset: offset[0], - yoffset: offset[1], - zoffset: 0, - width: size[0], - height: size[1], - depth: 0, - format: (), - mipmap: 0, - }; - encoder - .update_texture::<::Surface, F>( - &self.tex, None, info, data, - ) - .map_err(RenderError::TexUpdateError) + // TODO: Only works for 2D images + queue.write_texture( + wgpu::TextureCopyViewBase { + texture: &self.tex, + mip_level: 0, + origin: wgpu::Origin3d { + x: offset[0], + y: offset[1], + z: 0, + }, + }, + data, + // TODO: I heard some rumors that there are other + // formats that are not Rgba8 + wgpu::TextureDataLayout { + offset: 0, + bytes_per_row: self.size.x * 4, + rows_per_image: self.size.y, + }, + wgpu::Extent3d { + width: size[0], + height: size[1], + depth: 1, + }, + ); } /// Get dimensions of the represented image. - pub fn get_dimensions(&self) -> Vec2 { - let (w, h, ..) = self.tex.get_info().kind.get_dimensions(); - Vec2::new(w, h) - } + pub fn get_dimensions(&self) -> Extent3d { self.size } } diff --git a/voxygen/src/window.rs b/voxygen/src/window.rs index 06179e860a..2c00558bb4 100644 --- a/voxygen/src/window.rs +++ b/voxygen/src/window.rs @@ -1,6 +1,6 @@ use crate::{ controller::*, - render::{Renderer, WinColorFmt, WinDepthFmt}, + render::Renderer, settings::{ControlSettings, Settings}, ui, Error, }; @@ -12,7 +12,7 @@ use itertools::Itertools; use keyboard_keynames::key_layout::KeyLayout; use old_school_gfx_glutin_ext::{ContextBuilderExt, WindowInitExt, WindowUpdateExt}; use serde::{Deserialize, Serialize}; -use tracing::{error, info, warn}; +use tracing::{error, warn}; use vek::*; use winit::monitor::VideoMode; @@ -519,7 +519,7 @@ impl KeyMouse { pub struct Window { renderer: Renderer, - window: glutin::ContextWrapper, + window: winit::window::Window, cursor_grabbed: bool, pub pan_sensitivity: u32, pub zoom_sensitivity: u32, @@ -565,26 +565,18 @@ impl Window { false, ); - let (window, device, factory, win_color_view, win_depth_view) = - glutin::ContextBuilder::new() - .with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 3))) - .with_vsync(false) - .with_gfx_color_depth::() - .build_windowed(win_builder, &event_loop) - .map_err(|err| Error::BackendError(Box::new(err)))? - .init_gfx::(); + // let (window, device, factory, win_color_view, win_depth_view) = + // glutin::ContextBuilder::new() + // .with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 3))) + // .with_vsync(false) + // .with_gfx_color_depth::() + // .build_windowed(win_builder, &event_loop) + // .map_err(|err| Error::BackendError(Box::new(err)))? + // .init_gfx::(); - let vendor = device.get_info().platform_name.vendor; - let renderer = device.get_info().platform_name.renderer; - let opengl_version = device.get_info().version; - let glsl_version = device.get_info().shading_language; - info!( - ?vendor, - ?renderer, - ?opengl_version, - ?glsl_version, - "selected graphics device" - ); + let window = win_builder.build(&event_loop)?; + + let renderer = Renderer::new(&window, settings.graphics.render_mode.clone())?; let keypress_map = HashMap::new(); @@ -632,13 +624,7 @@ impl Window { }; let mut this = Self { - renderer: Renderer::new( - device, - factory, - win_color_view, - win_depth_view, - settings.graphics.render_mode.clone(), - )?, + renderer, window, cursor_grabbed: false, pan_sensitivity: settings.gameplay.pan_sensitivity, @@ -1367,7 +1353,7 @@ impl Window { pub fn set_size(&mut self, new_size: Vec2) { self.window .window() - .set_inner_size(glutin::dpi::LogicalSize::new( + .set_inner_size(winit::dpi::LogicalSize::new( new_size.x as f64, new_size.y as f64, ));