Started the report of wgpu

This commit is contained in:
Capucho 2020-08-21 20:10:56 +01:00 committed by Imbris
parent ab5f0df06b
commit 806f240eb5
14 changed files with 1126 additions and 723 deletions

397
Cargo.lock generated
View File

@ -203,6 +203,15 @@ dependencies = [
"stable_deref_trait", "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]] [[package]]
name = "assets_manager" name = "assets_manager"
version = "0.4.4" version = "0.4.4"
@ -358,6 +367,21 @@ dependencies = [
"shlex", "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]] [[package]]
name = "bitflags" name = "bitflags"
version = "1.2.1" version = "1.2.1"
@ -764,6 +788,12 @@ dependencies = [
"walkdir 0.1.8", "walkdir 0.1.8",
] ]
[[package]]
name = "copyless"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2df960f5d869b2dd8532793fde43eb5427cceb126c929747a26823ab0eeb536"
[[package]] [[package]]
name = "copypasta" name = "copypasta"
version = "0.7.1" version = "0.7.1"
@ -1205,6 +1235,17 @@ dependencies = [
"sct", "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]] [[package]]
name = "daggy" name = "daggy"
version = "0.5.0" version = "0.5.0"
@ -1861,6 +1902,152 @@ dependencies = [
"log", "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]] [[package]]
name = "gfx_core" name = "gfx_core"
version = "0.9.2" version = "0.9.2"
@ -2432,6 +2619,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "inplace_it"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90953f308a79fe6d62a4643e51f848fbfddcd05975a38e69fdf4ab86a7baf7ca"
[[package]] [[package]]
name = "instant" name = "instant"
version = "0.1.9" version = "0.1.9"
@ -2832,6 +3025,20 @@ dependencies = [
"autocfg", "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]] [[package]]
name = "minifb" name = "minifb"
version = "0.19.1" version = "0.19.1"
@ -2947,6 +3154,20 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0debeb9fcf88823ea64d64e4a815ab1643f33127d995978e099942ce38f25238" 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]] [[package]]
name = "native-dialog" name = "native-dialog"
version = "0.5.5" version = "0.5.5"
@ -3387,6 +3608,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
dependencies = [ dependencies = [
"malloc_buf", "malloc_buf",
"objc_exception",
] ]
[[package]] [[package]]
@ -3400,6 +3622,15 @@ dependencies = [
"objc_id", "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]] [[package]]
name = "objc_id" name = "objc_id"
version = "0.1.1" version = "0.1.1"
@ -4018,6 +4249,12 @@ dependencies = [
"rand_core 0.5.1", "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]] [[package]]
name = "raw-window-handle" name = "raw-window-handle"
version = "0.3.3" version = "0.3.3"
@ -4793,6 +5030,27 @@ dependencies = [
"winapi 0.3.9", "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]] [[package]]
name = "stable_deref_trait" name = "stable_deref_trait"
version = "1.2.0" version = "1.2.0"
@ -4871,6 +5129,15 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" 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]] [[package]]
name = "str-buf" name = "str-buf"
version = "1.0.5" version = "1.0.5"
@ -4971,6 +5238,18 @@ dependencies = [
"unicode-xid 0.2.1", "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]] [[package]]
name = "tap" name = "tap"
version = "1.0.1" version = "1.0.1"
@ -5055,6 +5334,12 @@ dependencies = [
"once_cell", "once_cell",
] ]
[[package]]
name = "thunderdome"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7572415bd688d401c52f6e36f4c8e805b9ae1622619303b9fa835d531db0acae"
[[package]] [[package]]
name = "time" name = "time"
version = "0.1.43" version = "0.1.43"
@ -5339,6 +5624,12 @@ dependencies = [
"nom 5.1.2", "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]] [[package]]
name = "typenum" name = "typenum"
version = "1.13.0" version = "1.13.0"
@ -5810,6 +6101,7 @@ dependencies = [
"dot_vox", "dot_vox",
"enum-iterator", "enum-iterator",
"euc", "euc",
"futures",
"gfx", "gfx",
"gfx_device_gl", "gfx_device_gl",
"gfx_gl", "gfx_gl",
@ -5855,9 +6147,11 @@ dependencies = [
"veloren-server", "veloren-server",
"veloren-voxygen-anim", "veloren-voxygen-anim",
"veloren-world", "veloren-world",
"wgpu",
"window_clipboard 0.2.0", "window_clipboard 0.2.0",
"winit", "winit",
"winres", "winres",
"zerocopy",
] ]
[[package]] [[package]]
@ -6408,9 +6702,9 @@ dependencies = [
[[package]] [[package]]
name = "web-sys" name = "web-sys"
version = "0.3.50" version = "0.3.48"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a905d57e488fec8861446d3393670fb50d27a262344013181c2cdf9fff5481be" checksum = "ec600b26223b2948cedfde2a0aa6756dcf1fef616f43d7b3097aaf53a6c4d92b"
dependencies = [ dependencies = [
"js-sys", "js-sys",
"wasm-bindgen", "wasm-bindgen",
@ -6436,6 +6730,65 @@ dependencies = [
"winapi 0.3.9", "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]] [[package]]
name = "which" name = "which"
version = "4.1.0" version = "4.1.0"
@ -6564,6 +6917,15 @@ dependencies = [
"toml", "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]] [[package]]
name = "ws2_32-sys" name = "ws2_32-sys"
version = "0.2.1" version = "0.2.1"
@ -6583,6 +6945,16 @@ dependencies = [
"tap", "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]] [[package]]
name = "x11-clipboard" name = "x11-clipboard"
version = "0.5.1" version = "0.5.1"
@ -6700,3 +7072,24 @@ checksum = "0de7bff972b4f2a06c85f6d8454b09df153af7e3a4ec2aac81db1b105b684ddb"
dependencies = [ dependencies = [
"chrono", "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",
]

View File

@ -22,14 +22,13 @@ runtimeLibs = ["libGL", "xorg.libX11", "xorg.libXcursor", "xorg.libXrandr", "xor
buildInputs = ["xorg.libxcb"] buildInputs = ["xorg.libxcb"]
[features] [features]
gl = ["gfx_device_gl", "gfx_gl"]
hot-anim = ["anim/use-dyn-lib"] hot-anim = ["anim/use-dyn-lib"]
singleplayer = ["server"] singleplayer = ["server"]
simd = ["vek/platform_intrinsics"] simd = ["vek/platform_intrinsics"]
tracy = ["common/tracy", "common-ecs/tracy", "common-frontend/tracy", "common-net/tracy", "common-systems/tracy", "common-state/tracy", "client/tracy"] tracy = ["common/tracy", "common-ecs/tracy", "common-frontend/tracy", "common-net/tracy", "common-systems/tracy", "common-state/tracy", "client/tracy"]
plugins = ["client/plugins"] plugins = ["client/plugins"]
default = ["gl", "singleplayer", "native-dialog", "plugins", "simd"] default = ["singleplayer", "native-dialog", "plugins", "simd"]
[dependencies] [dependencies]
client = {package = "veloren-client", path = "../client"} client = {package = "veloren-client", path = "../client"}
@ -51,6 +50,8 @@ gfx_gl = {version = "0.6.1", optional = true}
glutin = "0.26.0" glutin = "0.26.0"
old_school_gfx_glutin_ext = "0.26" old_school_gfx_glutin_ext = "0.26"
winit = {version = "0.24.0", features = ["serde"]} winit = {version = "0.24.0", features = ["serde"]}
wgpu = "0.6.0"
zerocopy = "0.3.0"
# Ui # Ui
conrod_core = {git = "https://gitlab.com/veloren/conrod.git", branch="copypasta_0.7"} 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" directories-next = "2.0"
dot_vox = "4.0" dot_vox = "4.0"
enum-iterator = "0.6" enum-iterator = "0.6"
strum = "0.20" futures = "0.3"
strum_macros = "0.20"
glsl-include = "0.3.1" glsl-include = "0.3.1"
guillotiere = "0.6" guillotiere = "0.6"
hashbrown = {version = "0.9", features = ["rayon", "serde", "nightly"]} hashbrown = {version = "0.9", features = ["rayon", "serde", "nightly"]}
@ -101,6 +101,8 @@ rand = "0.8"
rodio = {version = "0.13", default-features = false, features = ["vorbis"]} rodio = {version = "0.13", default-features = false, features = ["vorbis"]}
ron = {version = "0.6", default-features = false} ron = {version = "0.6", default-features = false}
serde = {version = "1.0", features = [ "rc", "derive" ]} serde = {version = "1.0", features = [ "rc", "derive" ]}
strum = "0.20"
strum_macros = "0.20"
treeculler = "0.2" treeculler = "0.2"
tokio = { version = "1", default-features = false, features = ["rt-multi-thread"] } tokio = { version = "1", default-features = false, features = ["rt-multi-thread"] }
num_cpus = "1.0" num_cpus = "1.0"

View File

@ -2,7 +2,14 @@
#![allow(incomplete_features)] #![allow(incomplete_features)]
#![allow(clippy::option_map_unit_fn)] #![allow(clippy::option_map_unit_fn)]
#![deny(clippy::clone_on_ref_ptr)] #![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"] #![recursion_limit = "2048"]
#[macro_use] #[macro_use]

View File

@ -0,0 +1,52 @@
use super::RenderError;
use wgpu::util::DeviceExt;
use zerocopy::AsBytes;
#[derive(Clone)]
pub struct Buffer<T: Copy + AsBytes> {
pub buf: wgpu::Buffer,
// bytes
count: usize,
phantom_data: std::marker::PhantomData<T>,
}
impl<T: Copy + AsBytes> Buffer<T> {
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 }
}

View File

@ -1,36 +1,32 @@
use super::{gfx_backend, RenderError}; use super::{buffer::Buffer, RenderError};
use gfx::{self, traits::FactoryExt}; use zerocopy::AsBytes;
/// A handle to a series of constants sitting on the GPU. This is used to hold /// 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 /// information used in the rendering process that does not change throughout a
/// single render pass. /// single render pass.
#[derive(Clone)] #[derive(Clone)]
pub struct Consts<T: Copy + gfx::traits::Pod> { pub struct Consts<T: Copy + AsBytes> {
pub buf: gfx::handle::Buffer<gfx_backend::Resources, T>, buf: Buffer<T>,
} }
impl<T: Copy + gfx::traits::Pod> Consts<T> { impl<T: Copy + AsBytes> Consts<T> {
/// Create a new `Const<T>`. /// Create a new `Const<T>`.
pub fn new(factory: &mut gfx_backend::Factory, len: usize) -> Self { pub fn new(device: &mut wgpu::Device, len: usize) -> Self {
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. /// Update the GPU-side value represented by this constant handle.
pub fn update( pub fn update(
&mut self, &mut self,
encoder: &mut gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>, device: &wgpu::Device,
queue: &wgpu::Queue,
vals: &[T], vals: &[T],
offset: usize, offset: usize,
) -> Result<(), RenderError> { ) -> Result<(), RenderError> {
if vals.is_empty() { self.buf.update(device, queue, vals, offset)
Ok(())
} else {
encoder
.update_buffer(&self.buf, vals, offset)
.map_err(RenderError::UpdateError)
}
} }
pub fn buf(&self) -> &wgpu::Buffer { self.buf.buf }
} }

View File

@ -2,73 +2,20 @@
/// rendering subsystem. /// rendering subsystem.
#[derive(Debug)] #[derive(Debug)]
pub enum RenderError { pub enum RenderError {
PipelineError(gfx::PipelineStateError<String>), RequestDeviceError(wgpu::RequestDeviceError),
UpdateError(gfx::UpdateError<usize>), MappingError(wgpu::BufferAsyncError),
TexUpdateError(gfx::UpdateError<[u16; 3]>), SwapChainError(wgpu::SwapChainError),
CombinedError(gfx::CombinedError),
BufferCreationError(gfx::buffer::CreationError),
IncludeError(glsl_include::Error),
MappingError(gfx::mapping::Error),
CopyError(gfx::CopyError<[u16; 3], usize>),
CustomError(String), CustomError(String),
CouldNotFindAdapter,
} }
impl From<gfx::PipelineStateError<String>> for RenderError { impl From<wgpu::RequestDeviceError> for RenderError {
fn from(err: gfx::PipelineStateError<String>) -> Self { Self::PipelineError(err) } fn from(err: wgpu::RequestDeviceError) -> Self { Self::RequestDeviceError(err) }
} }
impl From<gfx::PipelineStateError<&str>> for RenderError { impl From<wgpu::BufferAsyncError> for RenderError {
fn from(err: gfx::PipelineStateError<&str>) -> Self { fn from(err: wgpu::BufferAsyncError) -> Self { Self::MappingError(err) }
match err {
gfx::PipelineStateError::DescriptorInit(err) => {
gfx::PipelineStateError::DescriptorInit(err)
},
err => err,
}
.into()
}
} }
impl From<gfx::shade::ProgramError> for RenderError { impl From<wgpu::SwapChainError> for RenderError {
fn from(err: gfx::shade::ProgramError) -> Self { fn from(err: wgpu::SwapChainError) -> Self { Self::SwapChainError(err) }
gfx::PipelineStateError::<String>::Program(err).into()
}
}
impl From<gfx::UpdateError<usize>> for RenderError {
fn from(err: gfx::UpdateError<usize>) -> Self { Self::UpdateError(err) }
}
impl From<gfx::UpdateError<[u16; 3]>> for RenderError {
fn from(err: gfx::UpdateError<[u16; 3]>) -> Self { Self::TexUpdateError(err) }
}
impl From<gfx::CombinedError> for RenderError {
fn from(err: gfx::CombinedError) -> Self { Self::CombinedError(err) }
}
impl From<gfx::TargetViewError> for RenderError {
fn from(err: gfx::TargetViewError) -> Self { Self::CombinedError(err.into()) }
}
impl From<gfx::ResourceViewError> for RenderError {
fn from(err: gfx::ResourceViewError) -> Self { Self::CombinedError(err.into()) }
}
impl From<gfx::texture::CreationError> for RenderError {
fn from(err: gfx::texture::CreationError) -> Self { Self::CombinedError(err.into()) }
}
impl From<gfx::buffer::CreationError> for RenderError {
fn from(err: gfx::buffer::CreationError) -> Self { Self::BufferCreationError(err) }
}
impl From<glsl_include::Error> for RenderError {
fn from(err: glsl_include::Error) -> Self { Self::IncludeError(err) }
}
impl From<gfx::mapping::Error> for RenderError {
fn from(err: gfx::mapping::Error) -> Self { Self::MappingError(err) }
}
impl From<gfx::CopyError<[u16; 3], usize>> for RenderError {
fn from(err: gfx::CopyError<[u16; 3], usize>) -> Self { Self::CopyError(err) }
} }

View File

@ -1,34 +1,30 @@
use super::{gfx_backend, RenderError}; use super::{buffer::Buffer, RenderError};
use gfx::{ use zerocopy::AsBytes;
self,
buffer::Role,
memory::{Bind, Usage},
Factory,
};
/// Represents a mesh that has been sent to the GPU. /// Represents a mesh that has been sent to the GPU.
pub struct Instances<T: Copy + gfx::traits::Pod> { #[derive(Clone)]
pub ibuf: gfx::handle::Buffer<gfx_backend::Resources, T>, pub struct Instances<T: Copy + AsBytes> {
buf: Buffer<T>,
} }
impl<T: Copy + gfx::traits::Pod> Instances<T> { impl<T: Copy + AsBytes> Instances<T> {
pub fn new(factory: &mut gfx_backend::Factory, len: usize) -> Result<Self, RenderError> { pub fn new(device: &mut wgpu::Device, len: usize) -> Self {
Ok(Self { Self {
ibuf: factory buf: Buffer::new(device, len, wgpu::BufferUsage::VERTEX),
.create_buffer(len, Role::Vertex, Usage::Dynamic, Bind::empty()) }
.map_err(RenderError::BufferCreationError)?,
})
} }
pub fn count(&self) -> usize { self.ibuf.len() } pub fn count(&self) -> usize { self.buf.count() }
pub fn update( pub fn update(
&mut self, &mut self,
encoder: &mut gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>, device: &wgpu::Device,
instances: &[T], queue: &wgpu::Queue,
vals: &[T],
offset: usize,
) -> Result<(), RenderError> { ) -> Result<(), RenderError> {
encoder self.buf.update(device, queue, vals, offset)
.update_buffer(&self.ibuf, instances, 0)
.map_err(RenderError::UpdateError)
} }
pub fn buf(&self) -> &wgpu::Buffer { self.buf.buf }
} }

View File

@ -1,15 +1,12 @@
use super::Pipeline; use super::Vertex;
use core::{iter::FromIterator, ops::Range}; use core::{iter::FromIterator, ops::Range};
/// A `Vec`-based mesh structure used to store mesh data on the CPU. /// A `Vec`-based mesh structure used to store mesh data on the CPU.
pub struct Mesh<P: Pipeline> { pub struct Mesh<V: Vertex> {
verts: Vec<P::Vertex>, verts: Vec<V>,
} }
impl<P: Pipeline> Clone for Mesh<P> impl<V: Vertex> Clone for Mesh<V> {
where
P::Vertex: Clone,
{
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self {
verts: self.verts.clone(), verts: self.verts.clone(),
@ -17,7 +14,7 @@ where
} }
} }
impl<P: Pipeline> Mesh<P> { impl<V: Vertex> Mesh<V> {
/// Create a new `Mesh`. /// Create a new `Mesh`.
#[allow(clippy::new_without_default)] // TODO: Pending review in #587 #[allow(clippy::new_without_default)] // TODO: Pending review in #587
pub fn new() -> Self { Self { verts: Vec::new() } } pub fn new() -> Self { Self { verts: Vec::new() } }
@ -26,23 +23,23 @@ impl<P: Pipeline> Mesh<P> {
pub fn clear(&mut self) { self.verts.clear(); } pub fn clear(&mut self) { self.verts.clear(); }
/// Get a slice referencing the vertices of this mesh. /// 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. /// Get a mutable slice referencing the vertices of this mesh.
pub fn vertices_mut(&mut self) -> &mut [P::Vertex] { &mut self.verts } pub fn vertices_mut(&mut self) -> &mut [P::Vertex] { &mut self.verts }
/// Push a new vertex onto the end of this mesh. /// 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. /// Push a new polygon onto the end of this mesh.
pub fn push_tri(&mut self, tri: Tri<P>) { pub fn push_tri(&mut self, tri: Tri<V>) {
self.verts.push(tri.a); self.verts.push(tri.a);
self.verts.push(tri.b); self.verts.push(tri.b);
self.verts.push(tri.c); self.verts.push(tri.c);
} }
/// Push a new quad onto the end of this mesh. /// Push a new quad onto the end of this mesh.
pub fn push_quad(&mut self, quad: Quad<P>) { pub fn push_quad(&mut self, quad: Quad<V>) {
// A quad is composed of two triangles. The code below converts the former to // A quad is composed of two triangles. The code below converts the former to
// the latter. // the latter.
@ -73,10 +70,10 @@ impl<P: Pipeline> Mesh<P> {
} }
/// Push the vertices of another mesh onto the end of this mesh. /// Push the vertices of another mesh onto the end of this mesh.
pub fn push_mesh(&mut self, other: &Mesh<P>) { self.verts.extend_from_slice(other.vertices()); } pub fn push_mesh(&mut self, other: &Mesh<V>) { self.verts.extend_from_slice(other.vertices()); }
/// Map and push the vertices of another mesh onto the end of this mesh. /// Map and push the vertices of another mesh onto the end of this mesh.
pub fn push_mesh_map<F: FnMut(P::Vertex) -> P::Vertex>(&mut self, other: &Mesh<P>, mut f: F) { pub fn push_mesh_map<F: FnMut(V) -> V>(&mut self, other: &Mesh<V>, mut f: F) {
// Reserve enough space in our Vec. This isn't necessary, but it tends to reduce // Reserve enough space in our Vec. This isn't necessary, but it tends to reduce
// the number of required (re)allocations. // the number of required (re)allocations.
self.verts.reserve(other.vertices().len()); self.verts.reserve(other.vertices().len());
@ -86,23 +83,23 @@ impl<P: Pipeline> Mesh<P> {
} }
} }
pub fn iter(&self) -> std::slice::Iter<P::Vertex> { self.verts.iter() } pub fn iter(&self) -> std::slice::Iter<V> { self.verts.iter() }
/// NOTE: Panics if vertex_range is out of bounds of vertices. /// NOTE: Panics if vertex_range is out of bounds of vertices.
pub fn iter_mut(&mut self, vertex_range: Range<usize>) -> std::slice::IterMut<P::Vertex> { pub fn iter_mut(&mut self, vertex_range: Range<usize>) -> std::slice::IterMut<V> {
self.verts[vertex_range].iter_mut() self.verts[vertex_range].iter_mut()
} }
} }
impl<P: Pipeline> IntoIterator for Mesh<P> { impl<V: Vertex> IntoIterator for Mesh<V> {
type IntoIter = std::vec::IntoIter<P::Vertex>; type IntoIter = std::vec::IntoIter<V>;
type Item = P::Vertex; type Item = V;
fn into_iter(self) -> Self::IntoIter { self.verts.into_iter() } fn into_iter(self) -> Self::IntoIter { self.verts.into_iter() }
} }
impl<P: Pipeline> FromIterator<Tri<P>> for Mesh<P> { impl<V: Vertex> FromIterator<Tri<V>> for Mesh<V> {
fn from_iter<I: IntoIterator<Item = Tri<P>>>(tris: I) -> Self { fn from_iter<I: IntoIterator<Item = Tri<V>>>(tris: I) -> Self {
tris.into_iter().fold(Self::new(), |mut this, tri| { tris.into_iter().fold(Self::new(), |mut this, tri| {
this.push_tri(tri); this.push_tri(tri);
this this
@ -110,8 +107,8 @@ impl<P: Pipeline> FromIterator<Tri<P>> for Mesh<P> {
} }
} }
impl<P: Pipeline> FromIterator<Quad<P>> for Mesh<P> { impl<V: Vertex> FromIterator<Quad<V>> for Mesh<V> {
fn from_iter<I: IntoIterator<Item = Quad<P>>>(quads: I) -> Self { fn from_iter<I: IntoIterator<Item = Quad<V>>>(quads: I) -> Self {
quads.into_iter().fold(Self::new(), |mut this, quad| { quads.into_iter().fold(Self::new(), |mut this, quad| {
this.push_quad(quad); this.push_quad(quad);
this this
@ -120,33 +117,28 @@ impl<P: Pipeline> FromIterator<Quad<P>> for Mesh<P> {
} }
/// Represents a triangle stored on the CPU. /// Represents a triangle stored on the CPU.
pub struct Tri<P: Pipeline> { pub struct Tri<V: Vertex> {
a: P::Vertex, a: V,
b: P::Vertex, b: V,
c: P::Vertex, c: V,
} }
impl<P: Pipeline> Tri<P> { impl<V: Vertex> Tri<V> {
pub fn new(a: P::Vertex, b: P::Vertex, c: P::Vertex) -> Self { Self { a, b, c } } pub fn new(a: V, b: V, c: V) -> Self { Self { a, b, c } }
} }
/// Represents a quad stored on the CPU. /// Represents a quad stored on the CPU.
pub struct Quad<P: Pipeline> { pub struct Quad<V: Vertex> {
a: P::Vertex, a: V,
b: P::Vertex, b: V,
c: P::Vertex, c: V,
d: P::Vertex, d: V,
} }
impl<P: Pipeline> Quad<P> { impl<V: Vertex> Quad<V> {
pub fn new(a: P::Vertex, b: P::Vertex, c: P::Vertex, d: P::Vertex) -> Self { pub fn new(a: V, b: V, c: V, d: V) -> Self { Self { a, b, c, d } }
Self { a, b, c, d }
}
pub fn rotated_by(self, n: usize) -> Self pub fn rotated_by(self, n: usize) -> Self {
where
P::Vertex: Clone,
{
let verts = [self.a, self.b, self.c, self.d]; let verts = [self.a, self.b, self.c, self.d];
Self { Self {

View File

@ -1,3 +1,4 @@
mod buffer;
#[allow(clippy::single_component_path_imports)] // TODO: Pending review in #587 #[allow(clippy::single_component_path_imports)] // TODO: Pending review in #587
pub mod consts; pub mod consts;
mod error; mod error;
@ -44,25 +45,9 @@ pub use self::{
}, },
texture::Texture, texture::Texture,
}; };
pub use gfx::texture::{FilterMethod, WrapMode}; pub use wgpu::{AddressMode, FilterMode};
#[cfg(feature = "gl")] trait Vertex = Clone + zerocopy::AsBytes;
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<gfx::format::Format>;
}
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
/// Anti-aliasing modes /// Anti-aliasing modes

View File

@ -1,69 +1,48 @@
use super::{gfx_backend, mesh::Mesh, Pipeline, RenderError}; use super::{buffer::Buffer, mesh::Mesh, RenderError, Vertex};
use gfx::{
buffer::Role,
memory::{Bind, Usage},
traits::FactoryExt,
Factory,
};
use std::ops::Range; use std::ops::Range;
/// Represents a mesh that has been sent to the GPU. /// Represents a mesh that has been sent to the GPU.
pub struct Model<P: Pipeline> { pub struct SubModel<'a, V: Vertex> {
pub vbuf: gfx::handle::Buffer<gfx_backend::Resources, P::Vertex>,
pub vertex_range: Range<u32>, pub vertex_range: Range<u32>,
buf: &'a wgpu::Buffer,
phantom_data: std::marker::PhantomData<V>,
} }
impl<P: Pipeline> Model<P> { impl<'a, V: Vertex> SubModel<'a, V> {
pub fn new(factory: &mut gfx_backend::Factory, mesh: &Mesh<P>) -> Self { pub fn buf(&self) -> &wgpu::Buffer { self.buf }
}
/// Represents a mesh that has been sent to the GPU.
pub struct Model<V: Vertex> {
vbuf: Buffer<V>,
}
impl<V: Vertex> Model<V> {
pub fn new(device: &wgpu::Device, mesh: &Mesh<V>) -> Self {
Self { Self {
vbuf: factory.create_vertex_buffer(mesh.vertices()), vbuf: Buffer::new_with_data(device, wgpu::BufferUsage::VERTEX, mesh.vertices()),
vertex_range: 0..mesh.vertices().len() as u32,
} }
} }
pub fn vertex_range(&self) -> Range<u32> { 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<u32>) -> Model<P> {
Model {
vbuf: self.vbuf.clone(),
vertex_range,
}
}
}
/// Represents a mesh on the GPU which can be updated dynamically.
pub struct DynamicModel<P: Pipeline> {
pub vbuf: gfx::handle::Buffer<gfx_backend::Resources, P::Vertex>,
}
impl<P: Pipeline> DynamicModel<P> {
pub fn new(factory: &mut gfx_backend::Factory, size: usize) -> Result<Self, RenderError> {
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 /// Create a model with a slice of a portion of this model to send to the
/// renderer. /// renderer.
pub fn submodel(&self, vertex_range: Range<u32>) -> Model<P> { pub fn submodel(&self, vertex_range: Range<u32>) -> SubModel<V> {
Model { SubModel {
vbuf: self.vbuf.clone(),
vertex_range, vertex_range,
buf: self.buf(),
phantom_data: std::marker::PhantomData,
} }
} }
pub fn update( pub fn update(
&self, &mut self,
encoder: &mut gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>, device: &wgpu::Device,
mesh: &Mesh<P>, queue: &wgpu::Queue,
mesh: &Mesh<V>,
offset: usize, offset: usize,
) -> Result<(), RenderError> { ) -> Result<(), RenderError> {
encoder self.buf.update(device, queue, mesh.vertices(), offset)
.update_buffer(&self.vbuf, mesh.vertices(), offset)
.map_err(RenderError::UpdateError)
} }
pub fn buf(&self) -> &wgpu::Buffer { self.vbuf.buf }
} }

View File

@ -1,56 +1,28 @@
use super::{ use super::{
super::{Mesh, Model, Pipeline, TerrainPipeline, TgtColorFmt, TgtDepthStencilFmt}, super::{Mesh, Model, TerrainPipeline, TgtColorFmt, TgtDepthStencilFmt},
shadow, Globals, Light, Shadow, shadow, Globals, Light, Shadow,
}; };
use crate::mesh::greedy::GreedyMesh; 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 vek::*;
use zerocopy::AsBytes;
gfx_defines! { #[repr(C)]
constant Locals { #[derive(Copy, Clone, Debug, AsBytes)]
model_mat: [[f32; 4]; 4] = "model_mat", pub struct Locals {
highlight_col: [f32; 4] = "highlight_col", model_mat: [[f32; 4]; 4],
model_light: [f32; 4] = "model_light", highlight_col: [f32; 4],
model_glow: [f32; 4] = "model_glow", model_light: [f32; 4],
atlas_offs: [i32; 4] = "atlas_offs", model_glow: [f32; 4],
model_pos: [f32; 3] = "model_pos", atlas_offs: [i32; 4],
flags: u32 = "flags", model_pos: [f32; 3],
} flags: u32,
}
constant BoneData { #[repr(C)]
bone_mat: [[f32; 4]; 4] = "bone_mat", #[derive(Copy, Clone, Debug, AsBytes)]
normals_mat: [[f32; 4]; 4] = "normals_mat", pub struct BoneData {
} bone_mat: [[f32; 4]; 4],
normals_mat: [[f32; 4]; 4],
pipeline pipe {
vbuf: gfx::VertexBuffer<<TerrainPipeline as Pipeline>::Vertex> = (),
// abuf: gfx::VertexBuffer<<TerrainPipeline as Pipeline>::Vertex> = (),
col_lights: gfx::TextureSampler<[f32; 4]> = "t_col_light",
locals: gfx::ConstantBuffer<Locals> = "u_locals",
globals: gfx::ConstantBuffer<Globals> = "u_globals",
bones: gfx::ConstantBuffer<BoneData> = "u_bones",
lights: gfx::ConstantBuffer<Light> = "u_lights",
shadows: gfx::ConstantBuffer<Shadow> = "u_shadows",
point_shadow_maps: gfx::TextureSampler<f32> = "t_point_shadow_maps",
directed_shadow_maps: gfx::TextureSampler<f32> = "t_directed_shadow_maps",
alt: gfx::TextureSampler<[f32; 2]> = "t_alt",
horizon: gfx::TextureSampler<[f32; 4]> = "t_horizon",
noise: gfx::TextureSampler<f32> = "t_noise",
// Shadow stuff
light_shadows: gfx::ConstantBuffer<shadow::Locals> = "u_light_shadows",
tgt_color: gfx::BlendTarget<TgtColorFmt> = ("tgt_color", ColorMask::all(), gfx::preset::blend::ALPHA),
tgt_depth_stencil: gfx::DepthTarget<TgtDepthStencilFmt> = gfx::preset::depth::LESS_EQUAL_WRITE,
// tgt_depth_stencil: gfx::DepthStencilTarget<TgtDepthStencilFmt> = (gfx::preset::depth::LESS_EQUAL_WRITE,Stencil::new(Comparison::Always,0xff,(StencilOp::Keep,StencilOp::Keep,StencilOp::Replace))),
}
} }
impl Locals { impl Locals {
@ -76,6 +48,21 @@ impl Locals {
flags, 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 { impl Default for Locals {
@ -99,16 +86,39 @@ impl BoneData {
normals_mat: normals_mat.into_col_arrays(), 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 { impl Default for BoneData {
fn default() -> Self { Self::new(anim::vek::Mat4::identity(), anim::vek::Mat4::identity()) } 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 { impl FigureLayout {
type Vertex = <TerrainPipeline as Pipeline>::Vertex; pub fn new(device: &wgpu::Device) -> Self {
Self {
locals: Locals::locals_layout(device),
bone_data: BoneData::bone_data_layout(device),
}
}
} }
pub struct FigureModel { pub struct FigureModel {
@ -130,3 +140,49 @@ impl FigureModel {
} }
pub type BoneMeshes = (Mesh<TerrainPipeline>, anim::vek::Aabb<f32>); pub type BoneMeshes = (Mesh<TerrainPipeline>, anim::vek::Aabb<f32>);
//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<<TerrainPipeline as Pipeline>::Vertex> = (),
// // abuf: gfx::VertexBuffer<<TerrainPipeline as Pipeline>::Vertex> =
// (), col_lights: gfx::TextureSampler<[f32; 4]> = "t_col_light",
//
// locals: gfx::ConstantBuffer<Locals> = "u_locals",
// globals: gfx::ConstantBuffer<Globals> = "u_globals",
// bones: gfx::ConstantBuffer<BoneData> = "u_bones",
// lights: gfx::ConstantBuffer<Light> = "u_lights",
// shadows: gfx::ConstantBuffer<Shadow> = "u_shadows",
//
// point_shadow_maps: gfx::TextureSampler<f32> = "t_point_shadow_maps",
// directed_shadow_maps: gfx::TextureSampler<f32> =
// "t_directed_shadow_maps",
//
// alt: gfx::TextureSampler<[f32; 2]> = "t_alt",
// horizon: gfx::TextureSampler<[f32; 4]> = "t_horizon",
//
// noise: gfx::TextureSampler<f32> = "t_noise",
//
// // Shadow stuff
// light_shadows: gfx::ConstantBuffer<shadow::Locals> =
// "u_light_shadows",
//
// tgt_color: gfx::BlendTarget<TgtColorFmt> = ("tgt_color",
// ColorMask::all(), gfx::preset::blend::ALPHA), tgt_depth_stencil:
// gfx::DepthTarget<TgtDepthStencilFmt> = gfx::preset::depth::LESS_EQUAL_WRITE,
// // tgt_depth_stencil: gfx::DepthStencilTarget<TgtDepthStencilFmt> =
// (gfx::preset::depth::LESS_EQUAL_WRITE,Stencil::new(Comparison::Always,0xff,
// (StencilOp::Keep,StencilOp::Keep,StencilOp::Replace))), }

View File

@ -1,28 +1,21 @@
use super::{ use super::{
consts::Consts, consts::Consts,
gfx_backend,
instances::Instances, instances::Instances,
mesh::Mesh, mesh::Mesh,
model::{DynamicModel, Model}, model::{Model},
pipelines::{ pipelines::{
clouds, figure, fluid, lod_terrain, particle, postprocess, shadow, skybox, sprite, terrain, clouds, figure, fluid, lod_terrain, particle, postprocess, shadow, skybox, sprite, terrain,
ui, GlobalModel, Globals, ui, GlobalModel, Globals,
}, },
texture::Texture, texture::Texture,
AaMode, CloudMode, FilterMethod, FluidMode, LightingMode, Pipeline, RenderError, RenderMode, AaMode, CloudMode, FilterMode, FluidMode, LightingMode, RenderError, RenderMode,
ShadowMapMode, ShadowMode, WrapMode, ShadowMapMode, ShadowMode, AddressMode,
}; };
use common::assets::{self, AssetExt, AssetHandle}; use common::assets::{self, AssetExt, AssetHandle};
use common_base::span; use common_base::span;
use core::convert::TryFrom; use core::convert::TryFrom;
use gfx::{
self,
handle::Sampler,
state::Comparison,
traits::{Device, Factory, FactoryExt},
};
use glsl_include::Context as IncludeContext; use glsl_include::Context as IncludeContext;
use tracing::{error, warn}; use tracing::{error, info, warn};
use vek::*; use vek::*;
/// Represents the format of the pre-processed color target. /// Represents the format of the pre-processed color target.
@ -225,13 +218,11 @@ impl assets::Compound for Shaders {
pub struct ShadowMapRenderer { pub struct ShadowMapRenderer {
// directed_encoder: gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>, // directed_encoder: gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>,
// point_encoder: gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>, // point_encoder: gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>,
directed_depth_stencil_view: ShadowDepthStencilView, directed_depth_stencil_view: wgpu::TextureView,
directed_res: ShadowResourceView, directed_sampler: wgpu::Sampler,
directed_sampler: Sampler<gfx_backend::Resources>,
point_depth_stencil_view: ShadowDepthStencilView, point_depth_stencil_view: wgpu::TextureView,
point_res: ShadowResourceView, point_sampler: wgpu::Sampler,
point_sampler: Sampler<gfx_backend::Resources>,
point_pipeline: GfxPipeline<shadow::pipe::Init<'static>>, point_pipeline: GfxPipeline<shadow::pipe::Init<'static>>,
terrain_directed_pipeline: GfxPipeline<shadow::pipe::Init<'static>>, terrain_directed_pipeline: GfxPipeline<shadow::pipe::Init<'static>>,
@ -243,22 +234,18 @@ pub struct ShadowMapRenderer {
/// GPU, along with pipeline state objects (PSOs) needed to renderer different /// GPU, along with pipeline state objects (PSOs) needed to renderer different
/// kinds of models to the screen. /// kinds of models to the screen.
pub struct Renderer { pub struct Renderer {
device: gfx_backend::Device, device: wgpu::Device,
encoder: gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>, queue: wgpu::Queue,
factory: gfx_backend::Factory, swap_chain: wgpu::SwapChain,
win_color_view: WinColorView, win_depth_view: wgpu::TextureView,
win_depth_view: WinDepthView,
tgt_color_view: TgtColorView, tgt_color_view: wgpu::TextureView,
tgt_depth_stencil_view: TgtDepthStencilView, tgt_depth_stencil_view: wgpu::TextureView,
tgt_color_view_pp: TgtColorView, // TODO: rename
tgt_color_pp_view: wgpu::TextureView,
tgt_color_res: TgtColorRes, sampler: wgpu::Sampler,
tgt_depth_res: TgtDepthRes,
tgt_color_res_pp: TgtColorRes,
sampler: Sampler<gfx_backend::Resources>,
shadow_map: Option<ShadowMapRenderer>, shadow_map: Option<ShadowMapRenderer>,
@ -285,11 +272,8 @@ pub struct Renderer {
impl Renderer { impl Renderer {
/// Create a new `Renderer` from a variety of backend-specific components /// Create a new `Renderer` from a variety of backend-specific components
/// and the window targets. /// and the window targets.
pub fn new( pub async fn new(
mut device: gfx_backend::Device, window: &winit::window::Window,
mut factory: gfx_backend::Factory,
win_color_view: WinColorView,
win_depth_view: WinDepthView,
mode: RenderMode, mode: RenderMode,
) -> Result<Self, RenderError> { ) -> Result<Self, RenderError> {
// Enable seamless cubemaps globally, where available--they are essentially a // 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 // Note that since we only have to enable this once globally, there is no point
// in doing this on rerender. // 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( let shadow_views = Self::create_shadow_views(
&mut factory, &device,
(dims.0, dims.1), (dims.0, dims.1),
&ShadowMapMode::try_from(mode.shadow).unwrap_or_default(), &ShadowMapMode::try_from(mode.shadow).unwrap_or_default(),
) )
@ -328,16 +359,18 @@ impl Renderer {
point_shadow_pipeline, point_shadow_pipeline,
terrain_directed_shadow_pipeline, terrain_directed_shadow_pipeline,
figure_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 ( let (
tgt_color_view, tgt_color_view,
tgt_depth_stencil_view, tgt_depth_stencil_view,
tgt_color_view_pp, tgt_color_pp_view,
tgt_color_res, win_depth_view,
tgt_depth_res, ) = Self::create_rt_views(&device, (dims.0, dims.1), &mode)?;
tgt_color_res_pp,
) = Self::create_rt_views(&mut factory, (dims.0, dims.1), &mode)?;
let shadow_map = if let ( let shadow_map = if let (
Some(point_pipeline), Some(point_pipeline),
@ -360,13 +393,11 @@ impl Renderer {
) = shadow_views; ) = shadow_views;
Some(ShadowMapRenderer { Some(ShadowMapRenderer {
directed_depth_stencil_view, directed_depth_stencil_view,
directed_res,
directed_sampler, directed_sampler,
// point_encoder: factory.create_command_buffer().into(), // point_encoder: factory.create_command_buffer().into(),
// directed_encoder: factory.create_command_buffer().into(), // directed_encoder: factory.create_command_buffer().into(),
point_depth_stencil_view, point_depth_stencil_view,
point_res,
point_sampler, point_sampler,
point_pipeline, point_pipeline,
@ -377,34 +408,36 @@ impl Renderer {
None None
}; };
let sampler = factory.create_sampler(gfx::texture::SamplerInfo::new( let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
gfx::texture::FilterMethod::Bilinear, label: None,
gfx::texture::WrapMode::Clamp, 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( let noise_tex = Texture::new(
&mut factory, &device,
&queue,
&assets::Image::load_expect("voxygen.texture.noise").read().0, &assets::Image::load_expect("voxygen.texture.noise").read().0,
Some(gfx::texture::FilterMethod::Trilinear), Some(wgpu::FilterMode::Linear),
Some(gfx::texture::WrapMode::Tile), Some(wgpu::AddressMode::Repeat),
None,
)?; )?;
Ok(Self { Ok(Self {
device, device,
encoder: factory.create_command_buffer().into(), queue,
factory, swap_chain,
win_color_view,
win_depth_view, win_depth_view,
tgt_color_view, tgt_color_view,
tgt_depth_stencil_view, tgt_depth_stencil_view,
tgt_color_view_pp, tgt_color_pp_view,
tgt_color_res,
tgt_depth_res,
tgt_color_res_pp,
sampler, sampler,
@ -483,7 +516,7 @@ impl Renderer {
let ( let (
tgt_color_view, tgt_color_view,
tgt_depth_stencil_view, tgt_depth_stencil_view,
tgt_color_view_pp, tgt_color_pp_view,
tgt_color_res, tgt_color_res,
tgt_depth_res, tgt_depth_res,
tgt_color_res_pp, tgt_color_res_pp,
@ -493,7 +526,7 @@ impl Renderer {
self.tgt_color_res_pp = tgt_color_res_pp; self.tgt_color_res_pp = tgt_color_res_pp;
self.tgt_color_view = tgt_color_view; self.tgt_color_view = tgt_color_view;
self.tgt_depth_stencil_view = tgt_depth_stencil_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)) = if let (Some(shadow_map), ShadowMode::Map(mode)) =
(self.shadow_map.as_mut(), self.mode.shadow) (self.shadow_map.as_mut(), self.mode.shadow)
{ {
@ -525,90 +558,103 @@ impl Renderer {
} }
fn create_rt_views( fn create_rt_views(
factory: &mut gfx_device_gl::Factory, device: &wgpu::Device,
size: (u16, u16), size: (u16, u16),
mode: &RenderMode, mode: &RenderMode,
) -> Result< ) -> Result<(wgpu::TextureView, wgpu::TextureView, wgpu::TextureView, wgpu::TextureView), RenderError> {
(
TgtColorView,
TgtDepthStencilView,
TgtColorView,
TgtColorRes,
TgtDepthRes,
TgtColorRes,
),
RenderError,
> {
let upscaled = Vec2::from(size) let upscaled = Vec2::from(size)
.map(|e: u16| (e as f32 * mode.upscale_mode.factor) as u16) .map(|e: u16| (e as f32 * mode.upscale_mode.factor) as u16)
.into_tuple(); .into_tuple();
let kind = match mode.aa { let (width, height, sample_count) = match mode.aa {
AaMode::None | AaMode::Fxaa => { AaMode::None | AaMode::Fxaa => (upscaled.0, upscaled.1, 1),
gfx::texture::Kind::D2(upscaled.0, upscaled.1, gfx::texture::AaMode::Single)
},
// TODO: Ensure sampling in the shader is exactly between the 4 texels // TODO: Ensure sampling in the shader is exactly between the 4 texels
AaMode::MsaaX4 => { // TODO: Figure out how to do upscaling correctly with SSAA
gfx::texture::Kind::D2(upscaled.0, upscaled.1, gfx::texture::AaMode::Multi(4)) AaMode::MsaaX4 => (upscaled.0, upscaled.1, 4),
}, AaMode::MsaaX8 => (upscaled.0, upscaled.1, 8),
AaMode::MsaaX8 => { AaMode::MsaaX16 => (upscaled.0, upscaled.1, 16),
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))
},
}; };
let levels = 1; let levels = 1;
let color_cty = <<TgtColorFmt as gfx::format::Formatted>::Channel as gfx::format::ChannelTyped let mut color_view = || {
>::get_channel_type(); let tex = device.create_texture(&wgpu::TextureDescriptor {
let mut color_tex = || { label: None,
factory.create_texture( size: wgpu::Extent3d {
kind, width,
levels, height,
gfx::memory::Bind::SHADER_RESOURCE | gfx::memory::Bind::RENDER_TARGET, depth: 1,
gfx::memory::Usage::Data, },
Some(color_cty), mip_level_count: levels,
) sample_count,
}; dimension: wgpu::TextureDimension::D2,
let tgt_color_tex = color_tex()?; format: wgpu::TextureFormat::Rgba8UnormSrgb,
let tgt_color_tex_pp = color_tex()?; usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::OUTPUT_ATTACHMENT,
let mut color_res = |tex| { });
factory.view_texture_as_shader_resource::<TgtColorFmt>(
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 depth_stencil_cty = <<TgtDepthStencilFmt as gfx::format::Formatted>::Channel as gfx::format::ChannelTyped>::get_channel_type(); tex.create_view(&wgpu::TextureViewDescriptor {
let tgt_depth_stencil_tex = factory.create_texture( label: None,
kind, format: Some(wgpu::TextureFormat::Rgba8UnormSrgb),
levels, dimension: Some(wgpu::TextureViewDimension::D2),
gfx::memory::Bind::SHADER_RESOURCE | gfx::memory::Bind::DEPTH_STENCIL, aspect: wgpu::TextureAspect::Color,
gfx::memory::Usage::Data, base_mip_level: 0,
Some(depth_stencil_cty), level_count: Some(levels),
)?; base_array_layer: 0,
let tgt_depth_res = factory.view_texture_as_shader_resource::<TgtDepthStencilFmt>( array_layer_count: None,
&tgt_depth_stencil_tex, })
(0, levels - 1), };
gfx::format::Swizzle::new(),
)?; 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 = 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(( let win_depth_tex = device.create_texture(&wgpu::TextureDescriptor {
tgt_color_view, label: None,
tgt_depth_stencil_view, size: wgpu::Extent3d {
tgt_color_view_pp, width: size.0,
tgt_color_res, height: size.1,
tgt_depth_res, depth: 1,
tgt_color_res_pp, },
)) 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. /// Create textures and views for shadow maps.
@ -616,24 +662,24 @@ impl Renderer {
// disable the type complexity lint. // disable the type complexity lint.
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
fn create_shadow_views( fn create_shadow_views(
factory: &mut gfx_device_gl::Factory, device: &wgpu::Device,
size: (u16, u16), size: (u16, u16),
mode: &ShadowMapMode, mode: &ShadowMapMode,
) -> Result< ) -> Result<
( (
ShadowDepthStencilView, wgpu::TextureView,
ShadowResourceView, wgpu::Sampler,
Sampler<gfx_backend::Resources>, wgpu::TextureView,
ShadowDepthStencilView, wgpu::Sampler,
ShadowResourceView,
Sampler<gfx_backend::Resources>,
), ),
RenderError, RenderError,
> { > {
// (Attempt to) apply resolution factor to shadow map resolution. // (Attempt to) apply resolution factor to shadow map resolution.
let resolution_factor = mode.resolution.clamped(0.25, 4.0); 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. // Limit to max texture size, rather than erroring.
let size = Vec2::new(size.0, size.1).map(|e| { let size = Vec2::new(size.0, size.1).map(|e| {
let size = f32::from(e) * resolution_factor; let size = f32::from(e) * resolution_factor;
@ -677,72 +723,76 @@ impl Renderer {
.filter(|&e| e <= max_texture_size) .filter(|&e| e <= max_texture_size)
// Limit to max texture resolution rather than error. // Limit to max texture resolution rather than error.
.unwrap_or(max_texture_size); .unwrap_or(max_texture_size);
let depth_stencil_cty = <<ShadowDepthStencilFmt as gfx::format::Formatted>::Channel as gfx::format::ChannelTyped>::get_channel_type();
let point_shadow_tex = factory let point_shadow_tex = device.create_texture(&wgpu::TextureDescriptor {
.create_texture( label: None,
gfx::texture::Kind::Cube(diag_two_size / 4), size: wgpu::Extent3d {
levels as gfx::texture::Level, width: diag_two_size / 4,
gfx::memory::Bind::SHADER_RESOURCE | gfx::memory::Bind::DEPTH_STENCIL, height: diag_two_size / 4,
gfx::memory::Usage::Data, depth: 6,
Some(depth_stencil_cty), },
) mip_level_count: levels,
.map_err(|err| RenderError::CombinedError(gfx::CombinedError::Texture(err)))?; 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 let point_tgt_shadow_view = point_shadow_tex.create_view(&wgpu::TextureViewDescriptor {
.view_texture_as_depth_stencil::<ShadowDepthStencilFmt>( label: None,
&point_shadow_tex, format: Some(wgpu::TextureFormat::Depth24Plus),
0, dimension: Some(wgpu::TextureViewDimension::Cube),
None, aspect: wgpu::TextureAspect::DepthOnly,
gfx::texture::DepthStencilFlags::empty(), base_mip_level: 0,
)?; level_count: Some(levels),
base_array_layer: 0,
array_layer_count: None,
});
let point_tgt_shadow_res = factory let directed_shadow_tex = device.create_texture(&wgpu::TextureDescriptor {
.view_texture_as_shader_resource::<ShadowDepthStencilFmt>( label: None,
&point_shadow_tex, size: wgpu::Extent3d {
(0, levels - 1), width: diag_two_size,
gfx::format::Swizzle::new(), 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 let directed_tgt_shadow_view = point_shadow_tex.create_view(&wgpu::TextureViewDescriptor {
.create_texture( label: None,
gfx::texture::Kind::D2(diag_two_size, diag_two_size, gfx::texture::AaMode::Single), format: Some(wgpu::TextureFormat::Depth24Plus),
levels as gfx::texture::Level, dimension: Some(wgpu::TextureViewDimension::D2),
gfx::memory::Bind::SHADER_RESOURCE | gfx::memory::Bind::DEPTH_STENCIL, aspect: wgpu::TextureAspect::DepthOnly,
gfx::memory::Usage::Data, base_mip_level: 0,
Some(depth_stencil_cty), level_count: Some(levels),
) base_array_layer: 0,
.map_err(|err| RenderError::CombinedError(gfx::CombinedError::Texture(err)))?; array_layer_count: None,
let directed_tgt_shadow_view = factory });
.view_texture_as_depth_stencil::<ShadowDepthStencilFmt>(
&directed_shadow_tex,
0,
None,
gfx::texture::DepthStencilFlags::empty(),
)?;
let directed_tgt_shadow_res = factory
.view_texture_as_shader_resource::<ShadowDepthStencilFmt>(
&directed_shadow_tex,
(0, levels - 1),
gfx::format::Swizzle::new(),
)?;
let mut sampler_info = gfx::texture::SamplerInfo::new( let sampler_info = wgpu::SamplerDescriptor {
gfx::texture::FilterMethod::Bilinear, label: None,
// Lights should always be assumed to flood areas we can't see. address_mode_u: wgpu::AddressMode::ClampToEdge,
gfx::texture::WrapMode::Border, address_mode_v: wgpu::AddressMode::ClampToEdge,
); address_mode_w: wgpu::AddressMode::ClampToEdge,
sampler_info.comparison = Some(Comparison::LessEqual); mag_filter: wgpu::FilterMode::Linear,
sampler_info.border = [1.0; 4].into(); min_filter: wgpu::FilterMode::Linear,
let point_shadow_tex_sampler = factory.create_sampler(sampler_info); mipmap_filter: wgpu::FilterMode::Nearest,
let directed_shadow_tex_sampler = factory.create_sampler(sampler_info); 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(( Ok((
point_tgt_shadow_view, point_tgt_shadow_view,
point_tgt_shadow_res,
point_shadow_tex_sampler, point_shadow_tex_sampler,
directed_tgt_shadow_view, directed_tgt_shadow_view,
directed_tgt_shadow_res,
directed_shadow_tex_sampler, directed_shadow_tex_sampler,
)) ))
} }
@ -797,51 +847,22 @@ impl Renderer {
/// available. /// available.
#[allow(unsafe_code)] #[allow(unsafe_code)]
fn enable_seamless_cube_maps(device: &mut gfx_backend::Device) { fn enable_seamless_cube_maps(device: &mut gfx_backend::Device) {
unsafe { todo!()
// NOTE: Currently just fail silently rather than complain if the computer is on // unsafe {
// a version lower than 3.2, where seamless cubemaps were introduced. // // NOTE: Currently just fail silently rather than complain if the
if !device.get_info().is_version_supported(3, 2) { // computer is on // a version lower than 3.2, where
return; // 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+ // // NOTE: Safe because GL_TEXTURE_CUBE_MAP_SEAMLESS is supported
// (see https://www.khronos.org/opengl/wiki/Cubemap_Texture#Seamless_cubemap); // 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 // // enabling seamless cube maps should always be safe regardless
// the OpenGL context, so no further checks are needed. // of the state of // the OpenGL context, so no further
device.with_gl(|gl| { // checks are needed. device.with_gl(|gl| {
gl.Enable(gfx_gl::TEXTURE_CUBE_MAP_SEAMLESS); // 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);
}
});
}
} }
/// Queue the clearing of the depth target ready for a new frame to be /// Queue the clearing of the depth target ready for a new frame to be
@ -1109,47 +1130,58 @@ impl Renderer {
/// a image::DynamicImage. /// a image::DynamicImage.
#[allow(clippy::map_clone)] // TODO: Pending review in #587 #[allow(clippy::map_clone)] // TODO: Pending review in #587
pub fn create_screenshot(&mut self) -> Result<image::DynamicImage, RenderError> { pub fn create_screenshot(&mut self) -> Result<image::DynamicImage, RenderError> {
let (width, height) = self.get_resolution().into_tuple(); todo!()
use gfx::{ // let (width, height) = self.get_resolution().into_tuple();
format::{Formatted, SurfaceTyped},
memory::Typed,
};
type WinSurfaceData = <<WinColorFmt as Formatted>::Surface as SurfaceTyped>::DataType;
let download = self
.factory
.create_download_buffer::<WinSurfaceData>(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();
// Assumes that the format is Rgba8. // let download_buf = self
let raw_data = self // .device
.factory // .create_buffer(&wgpu::BufferDescriptor {
.read_mapping(&download)? // label: None,
.chunks_exact(width as usize) // size: width * height * 4,
.rev() // usage : wgpu::BufferUsage::COPY_DST,
.flatten() // mapped_at_creation: true
.flatten() // });
.map(|&e| e)
.collect::<Vec<_>>(); // let encoder =
Ok(image::DynamicImage::ImageRgba8( // self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor
// Should not fail if the dimensions are correct. // {label: None});
image::ImageBuffer::from_raw(width as u32, height as u32, raw_data).unwrap(),
)) // 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::<Vec<_>>();
// 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. /// 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()), color_sampler: (self.tgt_color_res.clone(), self.sampler.clone()),
depth_sampler: (self.tgt_depth_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()), 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(),
}, },
) )
} }

View File

@ -1,38 +1,22 @@
use super::{gfx_backend, RenderError}; use super::RenderError;
use gfx::{self, traits::Factory};
use image::{DynamicImage, GenericImageView}; use image::{DynamicImage, GenericImageView};
use vek::Vec2; use vek::Vec2;
use wgpu::{util::DeviceExt, Extent3d};
type DefaultShaderFormat = (gfx::format::R8_G8_B8_A8, gfx::format::Srgb);
/// Represents an image that has been uploaded to the GPU. /// Represents an image that has been uploaded to the GPU.
#[derive(Clone)] pub struct Texture {
pub struct Texture<F: gfx::format::Formatted = DefaultShaderFormat> pub tex: wgpu::TextureView,
where pub sampler: wgpu::Sampler,
F::Surface: gfx::format::TextureSurface, size: Extent3d,
F::Channel: gfx::format::TextureChannel,
<F::Surface as gfx::format::SurfaceTyped>::DataType: Copy,
{
pub tex: gfx::handle::Texture<gfx_backend::Resources, <F as gfx::format::Formatted>::Surface>,
pub srv: gfx::handle::ShaderResourceView<
gfx_backend::Resources,
<F as gfx::format::Formatted>::View,
>,
pub sampler: gfx::handle::Sampler<gfx_backend::Resources>,
} }
impl<F: gfx::format::Formatted> Texture<F> impl Texture {
where
F::Surface: gfx::format::TextureSurface,
F::Channel: gfx::format::TextureChannel,
<F::Surface as gfx::format::SurfaceTyped>::DataType: Copy,
{
pub fn new( pub fn new(
factory: &mut gfx_backend::Factory, device: &wgpu::Device,
queue: &wgpu::Queue,
image: &DynamicImage, image: &DynamicImage,
filter_method: Option<gfx::texture::FilterMethod>, filter_method: Option<wgpu::FilterMode>,
wrap_mode: Option<gfx::texture::WrapMode>, addresse_mode: Option<wgpu::AddressMode>,
border: Option<gfx::texture::PackedColor>,
) -> Result<Self, RenderError> { ) -> Result<Self, RenderError> {
// TODO: Actualy handle images that aren't in rgba format properly. // TODO: Actualy handle images that aren't in rgba format properly.
let buffer = image.as_flat_samples_u8().ok_or_else(|| { 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(), "We currently do not support color formats using more than 4 bytes / pixel.".into(),
) )
})?; })?;
let (tex, srv) = factory
.create_texture_immutable_u8::<F>(
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<u8> 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( let size = Extent3d {
filter_method.unwrap_or(gfx::texture::FilterMethod::Scale), width: image.width(),
wrap_mode.unwrap_or(gfx::texture::WrapMode::Clamp), 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 { Ok(Self {
tex, tex,
srv, sampler: device.create_sampler(&sampler_info),
sampler: factory.create_sampler(sampler_info), size,
}) })
} }
pub fn new_dynamic( pub fn new_dynamic(device: &wgpu::Device, width: u16, height: u16) -> Self {
factory: &mut gfx_backend::Factory, let size = wgpu::Extent3d {
width: u16, width,
height: u16, height,
) -> Result<Self, RenderError> { depth: 1,
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(<<F as gfx::format::Formatted>::Channel as gfx::format::ChannelTyped>::get_channel_type()),
)
.map_err(|err| RenderError::CombinedError(gfx::CombinedError::Texture(err)))?;
let srv = factory let tex_info = device.create_texture(&wgpu::TextureDescriptor {
.view_texture_as_shader_resource::<F>(&tex, (0, 0), gfx::format::Swizzle::new()) label: None,
.map_err(|err| RenderError::CombinedError(gfx::CombinedError::Resource(err)))?; 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 { let sampler_info = wgpu::SamplerDescriptor {
tex, label: None,
srv, address_mode_u: wgpu::AddressMode::ClampToEdge,
sampler: factory.create_sampler(gfx::texture::SamplerInfo::new( address_mode_v: wgpu::AddressMode::ClampToEdge,
gfx::texture::FilterMethod::Scale, address_mode_w: wgpu::AddressMode::ClampToEdge,
gfx::texture::WrapMode::Clamp, mag_filter: wgpu::FilterMode::Nearest,
)), min_filter: wgpu::FilterMode::Nearest,
}) mipmap_filter: wgpu::FilterMode::Nearest,
} ..Default::default()
};
pub fn new_immutable_raw( Self::new_raw(device, tex_info, sampler_info)
factory: &mut gfx_backend::Factory,
kind: gfx::texture::Kind,
mipmap: gfx::texture::Mipmap,
data: &[&[<F::Surface as gfx::format::SurfaceTyped>::DataType]],
sampler_info: gfx::texture::SamplerInfo,
) -> Result<Self, RenderError> {
let (tex, srv) = factory
.create_texture_immutable::<F>(kind, mipmap, data)
.map_err(RenderError::CombinedError)?;
Ok(Self {
tex,
srv,
sampler: factory.create_sampler(sampler_info),
})
} }
pub fn new_raw( pub fn new_raw(
_device: &mut gfx_backend::Device, device: &wgpu::Device,
factory: &mut gfx_backend::Factory, texture_info: wgpu::TextureDescriptor,
kind: gfx::texture::Kind, sampler_info: wgpu::SamplerDescriptor,
max_levels: u8, ) -> Self {
bind: gfx::memory::Bind,
usage: gfx::memory::Usage,
levels: (u8, u8),
swizzle: gfx::format::Swizzle,
sampler_info: gfx::texture::SamplerInfo,
) -> Result<Self, RenderError> {
let tex = factory
.create_texture(
kind,
max_levels as gfx::texture::Level,
bind | gfx::memory::Bind::SHADER_RESOURCE,
usage,
Some(<<F as gfx::format::Formatted>::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::<F>(&tex, levels, swizzle)
.map_err(|err| RenderError::CombinedError(gfx::CombinedError::Resource(err)))?;
Ok(Self { Ok(Self {
tex, tex: device.create_texture(&texture_info),
srv, sampler: device.create_sampler(&sampler_info),
sampler: factory.create_sampler(sampler_info), size: texture_info.size,
}) })
} }
/// Update a texture with the given data (used for updating the glyph cache /// Update a texture with the given data (used for updating the glyph cache
/// texture). /// texture).
pub fn update( pub fn update(
&self, &self,
encoder: &mut gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>, device: &wgpu::Device,
queue: &wgpu::Queue,
offset: [u16; 2], offset: [u16; 2],
size: [u16; 2], size: [u16; 2],
data: &[<F::Surface as gfx::format::SurfaceTyped>::DataType], data: &[u8],
) -> Result<(), RenderError> { ) -> Result<(), RenderError> {
let info = gfx::texture::ImageInfoCommon { // TODO: Only works for 2D images
xoffset: offset[0], queue.write_texture(
yoffset: offset[1], wgpu::TextureCopyViewBase {
zoffset: 0, texture: &self.tex,
width: size[0], mip_level: 0,
height: size[1], origin: wgpu::Origin3d {
depth: 0, x: offset[0],
format: (), y: offset[1],
mipmap: 0, z: 0,
}; },
encoder },
.update_texture::<<F as gfx::format::Formatted>::Surface, F>( data,
&self.tex, None, info, data, // TODO: I heard some rumors that there are other
) // formats that are not Rgba8
.map_err(RenderError::TexUpdateError) 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. /// Get dimensions of the represented image.
pub fn get_dimensions(&self) -> Vec2<u16> { pub fn get_dimensions(&self) -> Extent3d { self.size }
let (w, h, ..) = self.tex.get_info().kind.get_dimensions();
Vec2::new(w, h)
}
} }

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
controller::*, controller::*,
render::{Renderer, WinColorFmt, WinDepthFmt}, render::Renderer,
settings::{ControlSettings, Settings}, settings::{ControlSettings, Settings},
ui, Error, ui, Error,
}; };
@ -12,7 +12,7 @@ use itertools::Itertools;
use keyboard_keynames::key_layout::KeyLayout; use keyboard_keynames::key_layout::KeyLayout;
use old_school_gfx_glutin_ext::{ContextBuilderExt, WindowInitExt, WindowUpdateExt}; use old_school_gfx_glutin_ext::{ContextBuilderExt, WindowInitExt, WindowUpdateExt};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tracing::{error, info, warn}; use tracing::{error, warn};
use vek::*; use vek::*;
use winit::monitor::VideoMode; use winit::monitor::VideoMode;
@ -519,7 +519,7 @@ impl KeyMouse {
pub struct Window { pub struct Window {
renderer: Renderer, renderer: Renderer,
window: glutin::ContextWrapper<glutin::PossiblyCurrent, winit::window::Window>, window: winit::window::Window,
cursor_grabbed: bool, cursor_grabbed: bool,
pub pan_sensitivity: u32, pub pan_sensitivity: u32,
pub zoom_sensitivity: u32, pub zoom_sensitivity: u32,
@ -565,26 +565,18 @@ impl Window {
false, false,
); );
let (window, device, factory, win_color_view, win_depth_view) = // let (window, device, factory, win_color_view, win_depth_view) =
glutin::ContextBuilder::new() // glutin::ContextBuilder::new()
.with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 3))) // .with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 3)))
.with_vsync(false) // .with_vsync(false)
.with_gfx_color_depth::<WinColorFmt, WinDepthFmt>() // .with_gfx_color_depth::<WinColorFmt, WinDepthFmt>()
.build_windowed(win_builder, &event_loop) // .build_windowed(win_builder, &event_loop)
.map_err(|err| Error::BackendError(Box::new(err)))? // .map_err(|err| Error::BackendError(Box::new(err)))?
.init_gfx::<WinColorFmt, WinDepthFmt>(); // .init_gfx::<WinColorFmt, WinDepthFmt>();
let vendor = device.get_info().platform_name.vendor; let window = win_builder.build(&event_loop)?;
let renderer = device.get_info().platform_name.renderer;
let opengl_version = device.get_info().version; let renderer = Renderer::new(&window, settings.graphics.render_mode.clone())?;
let glsl_version = device.get_info().shading_language;
info!(
?vendor,
?renderer,
?opengl_version,
?glsl_version,
"selected graphics device"
);
let keypress_map = HashMap::new(); let keypress_map = HashMap::new();
@ -632,13 +624,7 @@ impl Window {
}; };
let mut this = Self { let mut this = Self {
renderer: Renderer::new( renderer,
device,
factory,
win_color_view,
win_depth_view,
settings.graphics.render_mode.clone(),
)?,
window, window,
cursor_grabbed: false, cursor_grabbed: false,
pan_sensitivity: settings.gameplay.pan_sensitivity, pan_sensitivity: settings.gameplay.pan_sensitivity,
@ -1367,7 +1353,7 @@ impl Window {
pub fn set_size(&mut self, new_size: Vec2<u16>) { pub fn set_size(&mut self, new_size: Vec2<u16>) {
self.window self.window
.window() .window()
.set_inner_size(glutin::dpi::LogicalSize::new( .set_inner_size(winit::dpi::LogicalSize::new(
new_size.x as f64, new_size.x as f64,
new_size.y as f64, new_size.y as f64,
)); ));