Backed out changeset 9c05fa3c0fcc (bug 1575008) for bustages on WebrtcIPCTraits.h. CLOSED TREE

--HG--
rename : third_party/rust/arrayvec-0.4.11/build.rs => third_party/rust/arrayvec/build.rs
rename : third_party/rust/arrayvec-0.4.11/src/maybe_uninit_nodrop.rs => third_party/rust/arrayvec/src/maybe_uninit_nodrop.rs
rename : third_party/rust/arrayvec-0.4.11/src/maybe_uninit_stable.rs => third_party/rust/arrayvec/src/maybe_uninit_stable.rs
rename : third_party/rust/arrayvec-0.4.11/src/range.rs => third_party/rust/arrayvec/src/range.rs
This commit is contained in:
Csoregi Natalia 2019-11-05 06:44:15 +02:00
parent faac13944b
commit 1e1d192ff3
652 changed files with 1956 additions and 245747 deletions

View File

@ -7,16 +7,6 @@ branch = "master"
git = "https://github.com/mozilla/neqo"
replace-with = "vendored-sources"
[source."https://github.com/kvark/spirv_cross"]
branch = "wgpu-test"
git = "https://github.com/kvark/spirv_cross"
replace-with = "vendored-sources"
[source."https://github.com/kvark/rust-objc-exception"]
branch = "cc"
git = "https://github.com/kvark/rust-objc-exception"
replace-with = "vendored-sources"
[source."https://github.com/hsivonen/packed_simd"]
branch = "rust_1_32"
git = "https://github.com/hsivonen/packed_simd"

View File

@ -38,7 +38,6 @@ layout/style/nsStyleStructList.h
# Autogenerated file
gfx/gl/GLConsts.h
gfx/webrender_bindings/webrender_ffi_generated.h
dom/webgpu/ffi/wgpu_ffi_generated.h
intl/unicharutil/util/nsSpecialCasingData.cpp
intl/unicharutil/util/nsUnicodePropertyData.cpp
intl/unicharutil/util/nsUnicodeScriptCodes.h

397
Cargo.lock generated
View File

@ -52,24 +52,6 @@ dependencies = [
"nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "arrayvec"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ash"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"shared_library 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "atom"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "atomic"
version = "0.4.5"
@ -183,13 +165,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "backtrace"
version = "0.3.38"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-demangle 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -359,11 +342,6 @@ dependencies = [
"constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "block"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "block-buffer"
version = "0.7.3"
@ -516,25 +494,6 @@ dependencies = [
"cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cocoa"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)",
"foreign-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
"objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "colorful"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "comedy"
version = "0.1.0"
@ -558,11 +517,6 @@ dependencies = [
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "copyless"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "core-foundation"
version = "0.6.3"
@ -579,7 +533,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "core-graphics"
version = "0.17.3"
version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -594,7 +548,7 @@ version = "13.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
"foreign-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -853,16 +807,6 @@ dependencies = [
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "d3d12"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "darling"
version = "0.10.1"
@ -1081,7 +1025,7 @@ name = "failure"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
"backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1251,116 +1195,6 @@ dependencies = [
"typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gfx-auxil"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx-hal 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"spirv_cross 0.16.0 (git+https://github.com/kvark/spirv_cross?branch=wgpu-test)",
]
[[package]]
name = "gfx-backend-dx11"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx-auxil 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx-hal 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"range-alloc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"raw-window-handle 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
"spirv_cross 0.16.0 (git+https://github.com/kvark/spirv_cross?branch=wgpu-test)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"wio 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gfx-backend-dx12"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"d3d12 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx-auxil 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx-hal 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"range-alloc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"raw-window-handle 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
"spirv_cross 0.16.0 (git+https://github.com/kvark/spirv_cross?branch=wgpu-test)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gfx-backend-empty"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gfx-hal 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"raw-window-handle 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gfx-backend-metal"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"cocoa 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
"copyless 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)",
"foreign-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx-auxil 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx-hal 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"metal 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
"objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"range-alloc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"raw-window-handle 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
"spirv_cross 0.16.0 (git+https://github.com/kvark/spirv_cross?branch=wgpu-test)",
"storage-map 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gfx-backend-vulkan"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ash 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx-hal 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"raw-window-handle 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"x11 2.18.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gfx-hal"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"raw-window-handle 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gkrust"
version = "0.1.0"
@ -1421,7 +1255,6 @@ dependencies = [
"static_prefs 0.1.0",
"storage 0.1.0",
"webrender_bindings 0.1.0",
"wgpu-remote 0.1.0",
"xpcom 0.1.0",
"xulstore 0.1.0",
]
@ -1535,14 +1368,6 @@ dependencies = [
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "hibitset"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"atom 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "http"
version = "0.1.17"
@ -1856,14 +1681,6 @@ dependencies = [
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "malloc_buf"
version = "0.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "malloc_size_of"
version = "0.0.1"
@ -1937,20 +1754,6 @@ dependencies = [
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "metal"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"cocoa 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)",
"foreign-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "mime"
version = "0.3.13"
@ -2180,7 +1983,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "neqo-common"
version = "0.1.4"
source = "git+https://github.com/mozilla/neqo#fa4b17afd26be8bf2c78cbc7247a31223b9cd2ca"
source = "git+https://github.com/mozilla/neqo#a3230a21d75066a117bab10a38d9a831c3d707d5"
dependencies = [
"env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2191,7 +1994,7 @@ dependencies = [
[[package]]
name = "neqo-crypto"
version = "0.1.4"
source = "git+https://github.com/mozilla/neqo#fa4b17afd26be8bf2c78cbc7247a31223b9cd2ca"
source = "git+https://github.com/mozilla/neqo#a3230a21d75066a117bab10a38d9a831c3d707d5"
dependencies = [
"bindgen 0.51.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2204,7 +2007,7 @@ dependencies = [
[[package]]
name = "neqo-http3"
version = "0.1.4"
source = "git+https://github.com/mozilla/neqo#fa4b17afd26be8bf2c78cbc7247a31223b9cd2ca"
source = "git+https://github.com/mozilla/neqo#a3230a21d75066a117bab10a38d9a831c3d707d5"
dependencies = [
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"neqo-common 0.1.4 (git+https://github.com/mozilla/neqo)",
@ -2218,7 +2021,7 @@ dependencies = [
[[package]]
name = "neqo-qpack"
version = "0.1.4"
source = "git+https://github.com/mozilla/neqo#fa4b17afd26be8bf2c78cbc7247a31223b9cd2ca"
source = "git+https://github.com/mozilla/neqo#a3230a21d75066a117bab10a38d9a831c3d707d5"
dependencies = [
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"neqo-common 0.1.4 (git+https://github.com/mozilla/neqo)",
@ -2229,7 +2032,7 @@ dependencies = [
[[package]]
name = "neqo-transport"
version = "0.1.4"
source = "git+https://github.com/mozilla/neqo#fa4b17afd26be8bf2c78cbc7247a31223b9cd2ca"
source = "git+https://github.com/mozilla/neqo#a3230a21d75066a117bab10a38d9a831c3d707d5"
dependencies = [
"derive_more 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2376,23 +2179,6 @@ dependencies = [
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "objc"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"objc_exception 0.1.2 (git+https://github.com/kvark/rust-objc-exception?branch=cc)",
]
[[package]]
name = "objc_exception"
version = "0.1.2"
source = "git+https://github.com/kvark/rust-objc-exception?branch=cc#c86ad3a52984461fc5c63980d12e8ceed847854c"
dependencies = [
"cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "object"
version = "0.14.0"
@ -2784,19 +2570,6 @@ dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "range-alloc"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "raw-window-handle"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rayon"
version = "1.2.0"
@ -2868,15 +2641,6 @@ name = "regex-syntax"
version = "0.6.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "relevant"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "remove_dir_all"
version = "0.5.2"
@ -2885,31 +2649,6 @@ dependencies = [
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rendy-descriptor"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gfx-hal 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"relevant 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rendy-memory"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"colorful 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx-hal 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"hibitset 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"relevant 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ringbuf"
version = "0.1.4"
@ -3208,15 +2947,6 @@ dependencies = [
"opaque-debug 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "shared_library"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "shift_or_euc"
version = "0.1.0"
@ -3288,14 +3018,6 @@ dependencies = [
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "spirv_cross"
version = "0.16.0"
source = "git+https://github.com/kvark/spirv_cross?branch=wgpu-test#a7c0cdbdb679999810d5a656d27c44807fd9f1e8"
dependencies = [
"cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "stable_deref_trait"
version = "1.0.0"
@ -3316,14 +3038,6 @@ dependencies = [
"xpcom 0.1.0",
]
[[package]]
name = "storage-map"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "storage_variant"
version = "0.1.0"
@ -3985,7 +3699,7 @@ dependencies = [
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
"core-text 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cstr 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"dwrote 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -4023,7 +3737,7 @@ dependencies = [
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
"derive_more 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
"malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -4042,7 +3756,7 @@ dependencies = [
"app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
"dwrote 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
"foreign-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -4082,40 +3796,6 @@ dependencies = [
"nom 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "wgpu-native"
version = "0.4.0"
dependencies = [
"arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"copyless 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx-backend-dx11 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx-backend-dx12 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx-backend-empty 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx-backend-metal 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx-backend-vulkan 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx-hal 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"raw-window-handle 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rendy-descriptor 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rendy-memory 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
"vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "wgpu-remote"
version = "0.1.0"
dependencies = [
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"wgpu-native 0.4.0",
]
[[package]]
name = "winapi"
version = "0.2.8"
@ -4170,14 +3850,6 @@ dependencies = [
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "wio"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "wr_malloc_size_of"
version = "0.0.1"
@ -4212,15 +3884,6 @@ dependencies = [
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "x11"
version = "2.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "xml-rs"
version = "0.8.0"
@ -4304,16 +3967,13 @@ dependencies = [
"checksum app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9dadc668390b373e73e4abbfc1f07238b09a25858f2f39c06cebc6d8e141d774"
"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
"checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba"
"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
"checksum ash 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "003d1fb2eb12eb06d4a03dbe02eea67a9fac910fa97932ab9e3a75b96a1ea5e5"
"checksum atom 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3c86699c3f02778ec07158376991c8f783dd1f2f95c579ffaf0738dc984b2fe2"
"checksum atomic 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c210c1f4db048cda477b652d170572d84c9640695835f17663595d3bd543fc28"
"checksum atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fb2dcb6e6d35f20276943cc04bb98e538b348d525a04ac79c10021561d202f21"
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
"checksum audio_thread_priority 0.20.2 (registry+https://github.com/rust-lang/crates.io-index)" = "197b2d259505d11c92d266e1784f01cc935eb764d2f54e16aedf4e5085197871"
"checksum authenticator 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ec149e5d5d4caa2c9ead53a8ce1ea9c4204c388c65bf3b96c2d1dc0fcf4aeb66"
"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875"
"checksum backtrace 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)" = "690a62be8920ccf773ee00ef0968649b0e724cda8bd5b12286302b4ae955fdf5"
"checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a"
"checksum backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c66d56ac8dabd07f6aacdaf633f4b8262f5b3601a810a0dcddffd5c22c69daa0"
"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
"checksum binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "88ceb0d16c4fd0e42876e298d7d3ce3780dd9ebdcbe4199816a32c77e08597ff"
@ -4325,7 +3985,6 @@ dependencies = [
"checksum bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a606a02debe2813760609f57a64a2ffd27d9fdf5b2f133eaca0b248dd92cdd2"
"checksum bitreader 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "80b13e2ab064ff3aa0bdbf1eff533f9822dc37899821f5f98c67f263eab51707"
"checksum blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "5850aeee1552f495dd0250014cf64b82b7c8879a89d83b33bbdace2cc4f63182"
"checksum block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
"checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
"checksum block-padding 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc4358306e344bf9775d0197fd00d2603e5afb0771bb353538630f022068ea3"
"checksum boxfnonce 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8380105befe91099e6f69206164072c05bc92427ff6aa8a5171388317346dd75"
@ -4340,15 +3999,12 @@ dependencies = [
"checksum clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f16b89cbb9ee36d87483dc939fe9f1e13c05898d56d7b230a0d4dff033a536"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "56d741ea7a69e577f6d06b36b7dff4738f680593dc27a701ffa8506b73ce28bb"
"checksum cocoa 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8cd20045e880893b4a8286d5639e9ade85fb1f6a14c291f882cf8cf2149d37d9"
"checksum colorful 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0bca1619ff57dd7a56b58a8e25ef4199f123e78e503fe1653410350a1b98ae65"
"checksum comedy 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4f03fbb05a4df3523a44cda10340e6ae6bea03ee9d01240a1a2c1ef6c73e95"
"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
"checksum cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "888604f00b3db336d2af898ec3c1d5d0ddf5e6d462220f2ededc33a87ac4bbd5"
"checksum copyless 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6ff9c56c9fb2a49c05ef0e431485a22400af20d33226dc0764d891d09e724127"
"checksum core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4e2640d6d0bf22e82bed1b73c6aef8d5dd31e5abe6666c57e6d45e2649f4f887"
"checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"
"checksum core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)" = "56790968ab1c8a1202a102e6de05fc6e1ec87da99e4e93e9a7d13efbfc1e95a9"
"checksum core-graphics 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)" = "62ceafe1622ffc9a332199096841d0ff9912ec8cf8f9cde01e254a7d5217cd10"
"checksum core-text 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f3f46450d6f2397261af420b4ccce23807add2e45fa206410a03d66fb7f050ae"
"checksum coreaudio-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e8f5954c1c7ccb55340443e8b29fca24013545a5e7d72c1ca7db4fc02b982ce"
"checksum cose 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "72fa26cb151d3ae4b70f63d67d0fed57ce04220feafafbae7f503bef7aae590d"
@ -4373,7 +4029,6 @@ dependencies = [
"checksum cubeb-backend 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5a1e7add4e7642a8aebb24172922318482bed52389a12cb339f728bbd4c4ed9c"
"checksum cubeb-core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfd9b2ea1cb6afed9419b0d18fc4093df552ccb2300eb57793629f8cd370b4c8"
"checksum cubeb-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "309c5839c5fa03c08363bd308566cbe4654b25a9984342d7546a33d55b80a3d6"
"checksum d3d12 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc7ed48e89905e5e146bcc1951cc3facb9e44aea9adf5dc01078cda1bd24b662"
"checksum darling 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe629a532efad5526454efb0700f86d5ad7ff001acb37e431c8bf017a432a8e"
"checksum darling_core 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ee54512bec54b41cf2337a22ddfadb53c7d4c738494dc2a186d7b037ad683b85"
"checksum darling_macro 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0cd3e432e52c0810b72898296a69d66b1d78d1517dff6cde7a130557a55a62c1"
@ -4410,13 +4065,6 @@ dependencies = [
"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4"
"checksum fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
"checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592"
"checksum gfx-auxil 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "572eee952a9a23c99cfe3e4fd95d277784058a89ac3c77ff6fa3d80a4e321919"
"checksum gfx-backend-dx11 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c66c77836ff26cf9916e5c8745715a22eae1fc61d994ffa0bea8a7dbd708ece2"
"checksum gfx-backend-dx12 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b6e913cc800fb12eaba2c420091a02aca9aafbefd672600dfc5b52654343d341"
"checksum gfx-backend-empty 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d383e6bc48867cb37d298a20139fd1eec298f8f6d594690cd1c50ef25470cc7"
"checksum gfx-backend-metal 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8de5c71f18ba805c95b84d6c78c472ef44485a6fc46e3b49fe1e6739c8d7b0c0"
"checksum gfx-backend-vulkan 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "62538fedd66a78968a162e8e1a29d085ffbc97f8782634684b2f7da7aea59207"
"checksum gfx-hal 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "977716fea7800ab5bc9a1e048dd2f72b23af166d8c2f48c6fb6d1ce37d77ca7e"
"checksum gl_generator 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "39a23d5e872a275135d66895d954269cf5e8661d234eb1c2480f4ce0d586acbd"
"checksum gleam 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)" = "7f46fd8874e043ffac0d638ed1567a2584f7814f6d72b4db37ab1689004a26c4"
"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
@ -4426,7 +4074,6 @@ dependencies = [
"checksum headers 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc6e2e51d356081258ef05ff4c648138b5d3fe64b7300aaad3b820554a2b7fb6"
"checksum headers-core 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "967131279aaa9f7c20c7205b45a391638a83ab118e6509b2d0ccbe08de044237"
"checksum headers-derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f33cf300c485e3cbcba0235013fcc768723451c9b84d1b31aa7fec0491ac9a11"
"checksum hibitset 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "47e7292fd9f7fe89fa35c98048f2d0a69b79ed243604234d18f6f8a1aa6f408d"
"checksum http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "eed324f0f0daf6ec10c474f150505af2c143f251722bf9dbd1261bd1f2ee2c1a"
"checksum httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83"
"checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e"
@ -4457,13 +4104,11 @@ dependencies = [
"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
"checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084"
"checksum mach 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa"
"checksum malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
"checksum malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "35adee9ed962cf7d07d62cb58bc45029f3227f5b5b86246caa8632f06c187bc3"
"checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376"
"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
"checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
"checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f"
"checksum metal 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ddf8052f20601c7af6293d3f7bf7b9159aee5974804fe65d871d437f933ec1eb"
"checksum mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "3e27ca21f40a310bd06d9031785f4801710d566c184a6e15bad4f1d9b65f9425"
"checksum mime_guess 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1a0ed03949aef72dbdf3116a383d7b38b4768e6f960528cd6a6044aa9ed68599"
"checksum miniz_oxide 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7108aff85b876d06f22503dcce091e29f76733b2bfdd91eebce81f5e68203a10"
@ -4493,8 +4138,6 @@ dependencies = [
"checksum num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e96f040177bb3da242b5b1ecf3f54b5d5af3efbbfb18608977a5d2767b22f10"
"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
"checksum num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "514f0d73e64be53ff320680ca671b64fe3fb91da01e1ae2ddc99eb51d453b20d"
"checksum objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "31d20fd2b37e07cf5125be68357b588672e8cefe9a96f8c17a9d46053b3e590d"
"checksum objc_exception 0.1.2 (git+https://github.com/kvark/rust-objc-exception?branch=cc)" = "<none>"
"checksum object 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "81afbc5773e99efe9533d8a539dfac37e531dcd0f4eeb41584bae03ccf76d4c2"
"checksum once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "891f486f630e5c5a4916c7e16c4b24a53e78c860b646e9f8e005e4f16847bfed"
"checksum opaque-debug 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "51ecbcb821e1bd256d456fe858aaa7f380b63863eab2eb86eee1bd9f33dd6682"
@ -4534,8 +4177,6 @@ dependencies = [
"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
"checksum range-alloc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd5927936723a9e8b715d37d7e4b390455087c4bdf25b9f702309460577b14f9"
"checksum raw-window-handle 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2e815b85b31e4d397ca9dd8eb1d692e9cb458b9f6ae8ac2232c995dca8236f87"
"checksum rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83a27732a533a1be0a0035a111fe76db89ad312f6f0347004c220c57f209a123"
"checksum rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98dcf634205083b17d0861252431eb2acbfb698ab7478a2d20de07954f47ec7b"
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
@ -4544,10 +4185,7 @@ dependencies = [
"checksum redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ecedbca3bf205f8d8f5c2b44d83cd0690e39ee84b951ed649e9f1841132b66d"
"checksum regex 1.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "d9d8297cc20bbb6184f8b45ff61c8ee6a9ac56c156cec8e38c3e5084773c44ad"
"checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716"
"checksum relevant 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bbc232e13d37f4547f5b9b42a5efc380cabe5dbc1807f8b893580640b2ab0308"
"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
"checksum rendy-descriptor 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f475bcc0505946e998590f1f0545c52ef4b559174a1b353a7ce6638def8b621e"
"checksum rendy-memory 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08f99de535d9e48d9cfab780b521702cc0d7183d354872d223967b75abae1199"
"checksum ringbuf 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "588456c74d5ff0a5806bc084818e043e767533f743c11ee6f3ccf298599c6847"
"checksum rkv 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9aab7c645d32e977e186448b0a5c2c3139a91a7f630cfd8a8c314d1d145e78bf"
"checksum ron 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "da06feaa07f69125ab9ddc769b11de29090122170b402547f64b86fe16ebc399"
@ -4579,7 +4217,6 @@ dependencies = [
"checksum serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)" = "38b08a9a90e5260fe01c6480ec7c811606df6d3a660415808c3c3fa8ed95b582"
"checksum sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "23962131a91661d643c98940b20fcaffe62d776a823247be80a48fcb8b6fce68"
"checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d"
"checksum shared_library 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11"
"checksum shift_or_euc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f930dea4685b9803954b9d74cdc175c6d946a22f2eafe5aa2e9a58cdcae7da8c"
"checksum shift_or_euc_c 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c81ec08c8a68c45c48d8ef58b80ce038cc9945891c4a4996761e2ec5cba05abc"
"checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
@ -4589,9 +4226,7 @@ dependencies = [
"checksum smallbitvec 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1764fe2b30ee783bfe3b9b37b2649d8d590b3148bb12e0079715d4d5c673562e"
"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7"
"checksum socket2 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)" = "df028e0e632c2a1823d920ad74895e7f9128e6438cbc4bc6fd1f180e644767b9"
"checksum spirv_cross 0.16.0 (git+https://github.com/kvark/spirv_cross?branch=wgpu-test)" = "<none>"
"checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b"
"checksum storage-map 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fd0a4829a5c591dc24a944a736d6b1e4053e51339a79fd5d4702c4c999a9c45e"
"checksum string 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00caf261d6f90f588f8450b8e1230fa0d5be49ee6140fdfbcb55335aff350970"
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
"checksum svg_fmt 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c666f0fed8e1e20e057af770af9077d72f3d5a33157b8537c1475dd8ffd6d32b"
@ -4658,10 +4293,8 @@ dependencies = [
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
"checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9"
"checksum winreg 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a27a759395c1195c4cc5cda607ef6f8f6498f64e78f7900f5de0a127a424704a"
"checksum wio 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5"
"checksum ws 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a6f5bb86663ff4d1639408410f50bf6050367a8525d644d49a6894cd618a631"
"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
"checksum x11 2.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39697e3123f715483d311b5826e254b6f3cfebdd83cf7ef3358f579c3d68e235"
"checksum xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "541b12c998c5b56aa2b4e6f18f03664eef9a4fd0a246a55594efae6cc2d964b5"
"checksum yaml-rust 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "95acf0db5515d07da9965ec0e0ba6cc2d825e2caeb7303b66ca441729801254e"
"checksum zip 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "36b9e08fb518a65cf7e08a1e482573eb87a2f4f8c6619316612a3c1f162fe822"

View File

@ -61,8 +61,6 @@ codegen-units = 1
[patch.crates-io]
libudev-sys = { path = "dom/webauthn/libudev-sys" }
packed_simd = { git = "https://github.com/hsivonen/packed_simd", branch = "rust_1_32" }
spirv_cross = { git = "https://github.com/kvark/spirv_cross", branch = "wgpu-test" }
objc_exception = { git = "https://github.com/kvark/rust-objc-exception", branch = "cc" }
[patch.crates-io.cranelift-codegen]
git = "https://github.com/CraneStation/Cranelift"

View File

@ -845,6 +845,7 @@ class PromiseDocumentFlushedResolver final {
nsGlobalWindowInner::nsGlobalWindowInner(nsGlobalWindowOuter* aOuterWindow,
WindowGlobalChild* aActor)
: nsPIDOMWindowInner(aOuterWindow, aActor),
mozilla::webgpu::InstanceProvider(this),
mWasOffline(false),
mHasHadSlowScript(false),
mIsChrome(false),
@ -1401,6 +1402,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindowInner)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentFlushedResolvers[i]->mCallback);
}
static_cast<mozilla::webgpu::InstanceProvider*>(tmp)->CcTraverse(cb);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindowInner)
@ -1515,6 +1518,8 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindowInner)
}
tmp->mDocumentFlushedResolvers.Clear();
static_cast<mozilla::webgpu::InstanceProvider*>(tmp)->CcUnlink();
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_UNLINK_END

View File

@ -47,6 +47,7 @@
#include "mozilla/LinkedList.h"
#include "mozilla/OwningNonNull.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/webgpu/InstanceProvider.h"
#include "nsWrapperCacheInlines.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/EventTarget.h"
@ -180,7 +181,8 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
public nsSupportsWeakReference,
public nsIInterfaceRequestor,
public PRCListStr,
public nsAPostRefreshObserver {
public nsAPostRefreshObserver,
public mozilla::webgpu::InstanceProvider {
public:
typedef mozilla::dom::BrowsingContext RemoteProxy;

View File

@ -6,10 +6,7 @@
#include "mozilla/dom/WebGPUBinding.h"
#include "Adapter.h"
#include "Device.h"
#include "Instance.h"
#include "ipc/WebGPUChild.h"
#include "mozilla/dom/Promise.h"
namespace mozilla {
namespace webgpu {
@ -17,29 +14,7 @@ namespace webgpu {
GPU_IMPL_CYCLE_COLLECTION(Adapter, mParent)
GPU_IMPL_JS_WRAP(Adapter)
Adapter::Adapter(RefPtr<Instance> aParent, RawId aId)
: ChildOf(aParent), mBridge(aParent->GetBridge()), mId(aId) {}
Adapter::~Adapter() = default;
RefPtr<WebGPUChild> Adapter::GetBridge() const { return mBridge; }
already_AddRefed<dom::Promise> Adapter::RequestDevice(
const dom::GPUDeviceDescriptor& aDesc, ErrorResult& aRv) {
RefPtr<dom::Promise> promise = dom::Promise::Create(GetParentObject(), aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
Maybe<RawId> id = mBridge->AdapterRequestDevice(mId, aDesc);
if (id.isSome()) {
RefPtr<Device> device = new Device(this, id.value());
promise->MaybeResolve(device);
} else {
promise->MaybeReject(nsresult(0));
}
return promise.forget();
}
} // namespace webgpu
} // namespace mozilla

View File

@ -7,7 +7,6 @@
#define GPU_Adapter_H_
#include "mozilla/AlreadyAddRefed.h"
#include "mozilla/webgpu/WebGPUTypes.h"
#include "nsString.h"
#include "ObjectModel.h"
@ -22,28 +21,20 @@ struct GPUFeatures;
namespace webgpu {
class Device;
class Instance;
class WebGPUChild;
class Adapter final : public ObjectBase, public ChildOf<Instance> {
public:
GPU_DECL_CYCLE_COLLECTION(Adapter)
GPU_DECL_JS_WRAP(Adapter)
const nsString mName;
private:
Adapter() = delete;
virtual ~Adapter();
const RefPtr<WebGPUChild> mBridge;
const RawId mId;
const nsString mName;
public:
explicit Adapter(RefPtr<Instance> aParent, RawId aId);
void GetName(nsString& out) const { out = mName; }
RefPtr<WebGPUChild> GetBridge() const;
already_AddRefed<dom::Promise> RequestDevice(
const dom::GPUDeviceDescriptor& aDesc, ErrorResult& aRv);
};
} // namespace webgpu

View File

@ -7,7 +7,6 @@
#include "Device.h"
#include "Adapter.h"
#include "ipc/WebGPUChild.h"
namespace mozilla {
namespace webgpu {
@ -16,18 +15,9 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(Device, DOMEventTargetHelper)
NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(Device, DOMEventTargetHelper)
GPU_IMPL_JS_WRAP(Device)
Device::Device(RefPtr<Adapter> aParent, RawId aId)
: DOMEventTargetHelper(aParent->GetParentObject()),
mBridge(aParent->GetBridge()),
mId(aId) {
Unused << mId; // TODO: remove
}
Device::Device(nsIGlobalObject* aGlobal) : DOMEventTargetHelper(aGlobal) {}
Device::~Device() {
if (mBridge->IsOpen()) {
mBridge->SendDeviceDestroy(mId);
}
}
Device::~Device() = default;
void Device::GetLabel(nsAString& aValue) const { aValue = mLabel; }
void Device::SetLabel(const nsAString& aLabel) { mLabel = aLabel; }

View File

@ -7,7 +7,7 @@
#define GPU_DEVICE_H_
#include "mozilla/RefPtr.h"
#include "mozilla/webgpu/WebGPUTypes.h"
#include "mozilla/DOMEventTargetHelper.h"
namespace mozilla {
@ -55,7 +55,6 @@ class RenderPipeline;
class Sampler;
class ShaderModule;
class Texture;
class WebGPUChild;
class Device final : public DOMEventTargetHelper {
public:
@ -63,16 +62,15 @@ class Device final : public DOMEventTargetHelper {
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(Device, DOMEventTargetHelper)
GPU_DECL_JS_WRAP(Device)
explicit Device(nsIGlobalObject* aGlobal);
private:
Device() = delete;
virtual ~Device();
const RefPtr<WebGPUChild> mBridge;
const RawId mId;
nsString mLabel;
public:
explicit Device(RefPtr<Adapter> aParent, RawId aId);
void GetLabel(nsAString& aValue) const;
void SetLabel(const nsAString& aLabel);

View File

@ -6,34 +6,20 @@
#include "Instance.h"
#include "Adapter.h"
#include "gfxConfig.h"
#include "InstanceProvider.h"
#include "nsIGlobalObject.h"
#include "ipc/WebGPUChild.h"
#include "ipc/WebGPUTypes.h"
#include "mozilla/layers/CompositorBridgeChild.h"
namespace mozilla {
namespace webgpu {
GPU_IMPL_CYCLE_COLLECTION(Instance, mOwner)
GPU_IMPL_CYCLE_COLLECTION(Instance, mParent)
/*static*/
RefPtr<Instance> Instance::Create(nsIGlobalObject* aOwner) {
if (!gfx::gfxConfig::IsEnabled(gfx::Feature::WEBGPU)) {
return nullptr;
}
RefPtr<WebGPUChild> bridge =
layers::CompositorBridgeChild::Get()->GetWebGPUChild();
if (NS_WARN_IF(!bridge)) {
MOZ_CRASH("Failed to create an IPDL bridge for WebGPU!");
}
return new Instance(aOwner, bridge);
RefPtr<Instance> Instance::Create(nsIGlobalObject* parent) {
return new Instance(parent);
}
Instance::Instance(nsIGlobalObject* aOwner, WebGPUChild* aBridge)
: mOwner(aOwner), mBridge(aBridge) {}
Instance::Instance(nsIGlobalObject* parent) : mParent(parent) {}
Instance::~Instance() = default;
@ -42,31 +28,5 @@ JSObject* Instance::WrapObject(JSContext* cx,
return dom::GPU_Binding::Wrap(cx, this, givenProto);
}
RefPtr<WebGPUChild> Instance::GetBridge() const { return mBridge; }
already_AddRefed<dom::Promise> Instance::RequestAdapter(
const dom::GPURequestAdapterOptions& aOptions, ErrorResult& aRv) {
RefPtr<dom::Promise> promise = dom::Promise::Create(mOwner, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
RefPtr<Instance> instance = this;
mBridge->InstanceRequestAdapter(aOptions)->Then(
GetMainThreadSerialEventTarget(), __func__,
[promise, instance](RawId id) {
MOZ_ASSERT(id != 0);
RefPtr<Adapter> adapter = new Adapter(instance, id);
promise->MaybeResolve(adapter);
},
[promise](const Maybe<ipc::ResponseRejectReason>& aRv) {
promise->MaybeReject(aRv.isSome() ? NS_ERROR_CONNECTION_REFUSED
: NS_ERROR_FAILURE);
});
return promise.forget();
}
} // namespace webgpu
} // namespace mozilla

View File

@ -19,29 +19,23 @@ struct GPURequestAdapterOptions;
namespace webgpu {
class Adapter;
class GPUAdapter;
class WebGPUChild;
class InstanceProvider;
class Instance final : public nsWrapperCache {
public:
GPU_DECL_CYCLE_COLLECTION(Instance)
GPU_DECL_JS_WRAP(Instance)
static RefPtr<Instance> Create(nsIGlobalObject* aOwner);
nsCOMPtr<nsIGlobalObject> mParent;
already_AddRefed<dom::Promise> RequestAdapter(
const dom::GPURequestAdapterOptions& aOptions, ErrorResult& aRv);
static RefPtr<Instance> Create(nsIGlobalObject* parent);
private:
explicit Instance(nsIGlobalObject* aOwner, WebGPUChild* aBridge);
explicit Instance(nsIGlobalObject* parent);
virtual ~Instance();
nsCOMPtr<nsIGlobalObject> mOwner;
const RefPtr<WebGPUChild> mBridge;
public:
nsIGlobalObject* GetParentObject() const { return mOwner.get(); }
RefPtr<WebGPUChild> GetBridge() const;
nsIGlobalObject* GetParentObject() const { return mParent.get(); }
};
} // namespace webgpu

View File

@ -0,0 +1,38 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "InstanceProvider.h"
#include "Instance.h"
namespace mozilla {
namespace webgpu {
InstanceProvider::InstanceProvider(nsIGlobalObject* const global)
: mGlobal(global) {}
InstanceProvider::~InstanceProvider() = default;
already_AddRefed<Instance> InstanceProvider::Webgpu() const {
if (!mInstance) {
const auto inst = Instance::Create(mGlobal);
mInstance = Some(inst);
}
auto ret = mInstance.value();
return ret.forget();
}
void InstanceProvider::CcTraverse(
nsCycleCollectionTraversalCallback& callback) const {
if (mInstance) {
CycleCollectionNoteChild(callback, mInstance.ref().get(),
"webgpu::InstanceProvider::mInstance", 0);
}
}
void InstanceProvider::CcUnlink() { mInstance = Some(nullptr); }
} // namespace webgpu
} // namespace mozilla

View File

@ -0,0 +1,55 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GPU_INSTANCE_PROVIDER_H_
#define GPU_INSTANCE_PROVIDER_H_
#include "mozilla/AlreadyAddRefed.h"
#include "mozilla/Maybe.h"
#include "mozilla/RefPtr.h"
class nsCycleCollectionTraversalCallback;
class nsIGlobalObject;
namespace mozilla {
namespace webgpu {
class Instance;
class InstanceProvider {
private:
nsIGlobalObject* const mGlobal;
mutable Maybe<RefPtr<Instance>> mInstance;
protected:
explicit InstanceProvider(nsIGlobalObject* global);
virtual ~InstanceProvider();
public:
already_AddRefed<Instance> Webgpu() const;
nsIGlobalObject* GetParentObject() const { return mGlobal; }
void CcTraverse(nsCycleCollectionTraversalCallback&) const;
void CcUnlink();
};
template <typename T>
void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback,
const Maybe<T>& field, const char* name,
uint32_t flags) {
if (field) {
CycleCollectionNoteChild(callback, field.value(), name, flags);
}
}
template <typename T>
void ImplCycleCollectionUnlink(Maybe<T>& field) {
field = Nothing();
}
} // namespace webgpu
} // namespace mozilla
#endif // GPU_INSTANCE_PROVIDER_H_

View File

@ -19,8 +19,8 @@ class ChildOf {
public:
const RefPtr<T> mParent;
explicit ChildOf(T* const parent);
explicit ChildOf(
T* parent = nullptr); // TODO: This can't be nullptr eventually.
protected:
virtual ~ChildOf();

View File

@ -1,32 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
EXPORTS.mozilla.webgpu.ffi += [
'wgpu.h',
]
UNIFIED_SOURCES += [
]
if CONFIG['COMPILE_ENVIRONMENT']:
GENERATED_FILES += [
'wgpu_ffi_generated.h',
]
EXPORTS.mozilla.webgpu.ffi += [
'!wgpu_ffi_generated.h',
]
ffi_generated = GENERATED_FILES['wgpu_ffi_generated.h']
ffi_generated.script = '/layout/style/RunCbindgen.py:generate'
ffi_generated.inputs = [
'/dom/webgpu/wgpu-remote',
]
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'

View File

@ -1,31 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef WGPU_h
#define WGPU_h
// Prelude of types necessary before including wgpu_ffi_generated.h
namespace mozilla {
namespace webgpu {
namespace ffi {
#define WGPU_INLINE
#define WGPU_FUNC
#define WGPU_DESTRUCTOR_SAFE_FUNC
extern "C" {
#include "wgpu_ffi_generated.h"
}
#undef WGPU_INLINE
#undef WGPU_FUNC
#undef WGPU_DESTRUCTOR_SAFE_FUNC
} // namespace ffi
} // namespace webgpu
} // namespace mozilla
#endif // WGPU_h

View File

@ -1,38 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
using RawId from "mozilla/webgpu/WebGPUTypes.h";
using dom::GPURequestAdapterOptions from "mozilla/dom/WebGPUBinding.h";
using dom::GPUDeviceDescriptor from "mozilla/dom/WebGPUBinding.h";
include "mozilla/webgpu/WebGPUSerialize.h";
include protocol PCompositorBridge;
namespace mozilla {
namespace webgpu {
/**
* Represents the connection between a WebGPUChild actor that issues WebGPU
* command from the content process, and a WebGPUParent in the compositor
* process that runs the commands.
*/
async protocol PWebGPU
{
manager PCompositorBridge;
parent:
async InstanceRequestAdapter(GPURequestAdapterOptions options, RawId[] ids) returns (RawId adapterId);
async AdapterRequestDevice(RawId selfId, GPUDeviceDescriptor desc, RawId newId);
async DeviceDestroy(RawId selfId);
async Shutdown();
child:
async __delete__();
};
} // webgpu
} // mozilla

View File

@ -1,80 +0,0 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WebGPUChild.h"
#include "mozilla/dom/WebGPUBinding.h"
#include "mozilla/webgpu/ffi/wgpu.h"
namespace mozilla {
namespace webgpu {
static ffi::WGPUClient* initialize() {
ffi::WGPUInfrastructure infra = ffi::wgpu_client_new();
return infra.client;
}
WebGPUChild::WebGPUChild() : mClient(initialize()), mIPCOpen(false) {}
WebGPUChild::~WebGPUChild() {
if (mClient) {
ffi::wgpu_client_delete(mClient);
}
}
RefPtr<RawIdPromise> WebGPUChild::InstanceRequestAdapter(
const dom::GPURequestAdapterOptions& aOptions) {
const int max_ids = 10;
RawId ids[max_ids] = {0};
unsigned long count =
ffi::wgpu_client_make_adapter_ids(mClient, ids, max_ids);
auto client = mClient;
nsTArray<RawId> sharedIds;
for (unsigned long i = 0; i != count; ++i) {
sharedIds.AppendElement(ids[i]);
}
return SendInstanceRequestAdapter(aOptions, sharedIds)
->Then(
GetCurrentThreadSerialEventTarget(), __func__,
[client, ids, count](const RawId& aId) {
if (aId == 0) {
ffi::wgpu_client_kill_adapter_ids(client, ids, count);
return RawIdPromise::CreateAndReject(Nothing(), __func__);
} else {
// find the position in the list
unsigned int i = 0;
while (ids[i] != aId) {
i++;
}
if (i > 0) {
ffi::wgpu_client_kill_adapter_ids(client, ids, i);
}
if (i + 1 < count) {
ffi::wgpu_client_kill_adapter_ids(client, ids + i + 1,
count - i - 1);
}
return RawIdPromise::CreateAndResolve(aId, __func__);
}
},
[client, ids, count](const ipc::ResponseRejectReason& aReason) {
ffi::wgpu_client_kill_adapter_ids(client, ids, count);
return RawIdPromise::CreateAndReject(Some(aReason), __func__);
});
}
Maybe<RawId> WebGPUChild::AdapterRequestDevice(
RawId aSelfId, const dom::GPUDeviceDescriptor& aDesc) {
RawId id = ffi::wgpu_client_make_device_id(mClient, aSelfId);
if (SendAdapterRequestDevice(aSelfId, aDesc, id)) {
return Some(id);
} else {
ffi::wgpu_client_kill_device_id(mClient, id);
return Nothing();
}
}
} // namespace webgpu
} // namespace mozilla

View File

@ -1,66 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef WEBGPU_CHILD_H_
#define WEBGPU_CHILD_H_
#include "mozilla/webgpu/PWebGPUChild.h"
#include "mozilla/MozPromise.h"
namespace mozilla {
namespace dom {
struct GPURequestAdapterOptions;
} // namespace dom
namespace layers {
class CompositorBridgeChild;
} // namespace layers
namespace webgpu {
namespace ffi {
struct WGPUClient;
} // namespace ffi
typedef MozPromise<RawId, Maybe<ipc::ResponseRejectReason>, true> RawIdPromise;
class WebGPUChild final : public PWebGPUChild {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebGPUChild)
friend class layers::CompositorBridgeChild;
public:
explicit WebGPUChild();
bool IsOpen() const { return mIPCOpen; }
RefPtr<RawIdPromise> InstanceRequestAdapter(
const dom::GPURequestAdapterOptions& aOptions);
Maybe<RawId> AdapterRequestDevice(RawId aSelfId,
const dom::GPUDeviceDescriptor& aDesc);
private:
virtual ~WebGPUChild();
// AddIPDLReference and ReleaseIPDLReference are only to be called by
// CompositorBridgeChild's AllocPWebGPUChild and DeallocPWebGPUChild methods
// respectively. We intentionally make them private to prevent misuse.
// The purpose of these methods is to be aware of when the IPC system around
// this actor goes down: mIPCOpen is then set to false.
void AddIPDLReference() {
MOZ_ASSERT(!mIPCOpen);
mIPCOpen = true;
AddRef();
}
void ReleaseIPDLReference() {
MOZ_ASSERT(mIPCOpen);
mIPCOpen = false;
Release();
}
ffi::WGPUClient* const mClient;
bool mIPCOpen;
};
} // namespace webgpu
} // namespace mozilla
#endif // WEBGPU_CHILD_H_

View File

@ -1,57 +0,0 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WebGPUParent.h"
#include "mozilla/webgpu/ffi/wgpu.h"
namespace mozilla {
namespace webgpu {
WebGPUParent::WebGPUParent() : mContext(ffi::wgpu_server_new()) {}
WebGPUParent::~WebGPUParent() = default;
ipc::IPCResult WebGPUParent::RecvInstanceRequestAdapter(
const dom::GPURequestAdapterOptions& aOptions,
const nsTArray<RawId>& aTargetIds,
InstanceRequestAdapterResolver&& resolver) {
ffi::WGPURequestAdapterOptions options = {};
if (aOptions.mPowerPreference.WasPassed()) {
options.power_preference = static_cast<ffi::WGPUPowerPreference>(
aOptions.mPowerPreference.Value());
}
// TODO: make available backends configurable by prefs
int8_t index = ffi::wgpu_server_instance_request_adapter(
mContext, &options, aTargetIds.Elements(), aTargetIds.Length());
if (index >= 0) {
resolver(aTargetIds[index]);
} else {
resolver(0);
}
return IPC_OK();
}
ipc::IPCResult WebGPUParent::RecvAdapterRequestDevice(
RawId aSelfId, const dom::GPUDeviceDescriptor& aOptions, RawId aNewId) {
ffi::WGPUDeviceDescriptor desc = {};
// TODO: fill up the descriptor
ffi::wgpu_server_adapter_request_device(mContext, aSelfId, &desc, aNewId);
return IPC_OK();
}
ipc::IPCResult WebGPUParent::RecvDeviceDestroy(RawId aSelfId) {
ffi::wgpu_server_device_destroy(mContext, aSelfId);
return IPC_OK();
}
ipc::IPCResult WebGPUParent::RecvShutdown() {
ffi::wgpu_server_delete(const_cast<ffi::WGPUGlobal*>(mContext));
return IPC_OK();
}
} // namespace webgpu
} // namespace mozilla

View File

@ -1,43 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef WEBGPU_PARENT_H_
#define WEBGPU_PARENT_H_
#include "mozilla/webgpu/PWebGPUParent.h"
#include "WebGPUTypes.h"
namespace mozilla {
namespace webgpu {
namespace ffi {
struct WGPUGlobal;
} // namespace ffi
class WebGPUParent final : public PWebGPUParent {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebGPUParent)
public:
explicit WebGPUParent();
ipc::IPCResult RecvInstanceRequestAdapter(
const dom::GPURequestAdapterOptions& aOptions,
const nsTArray<RawId>& aTargetIds,
InstanceRequestAdapterResolver&& resolver);
ipc::IPCResult RecvAdapterRequestDevice(RawId aSelfId,
const dom::GPUDeviceDescriptor& aDesc,
RawId aNewId);
ipc::IPCResult RecvDeviceDestroy(RawId aSelfId);
ipc::IPCResult RecvShutdown();
private:
virtual ~WebGPUParent();
const ffi::WGPUGlobal* const mContext;
};
} // namespace webgpu
} // namespace mozilla
#endif // WEBGPU_PARENT_H_

View File

@ -1,35 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef WEBGPU_SERIALIZE_H_
#define WEBGPU_SERIALIZE_H_
#include "WebGPUTypes.h"
#include "mozilla/dom/WebGPUBinding.h"
// TODO: move this into a more generic place
#include "mozilla/media/webrtc/WebrtcIPCTraits.h"
namespace IPC {
#define DEFINE_IPC_SERIALIZER_ENUM(something) \
template <> \
struct ParamTraits<something> \
: public ContiguousEnumSerializer<something, something(0), \
something::EndGuard_> {}
DEFINE_IPC_SERIALIZER_ENUM(mozilla::dom::GPUPowerPreference);
DEFINE_IPC_SERIALIZER_WITH_FIELDS(mozilla::dom::GPURequestAdapterOptions,
mPowerPreference);
DEFINE_IPC_SERIALIZER_WITH_FIELDS(mozilla::dom::GPUExtensions,
mAnisotropicFiltering);
DEFINE_IPC_SERIALIZER_WITH_FIELDS(mozilla::dom::GPULimits, mMaxBindGroups);
DEFINE_IPC_SERIALIZER_WITH_FIELDS(mozilla::dom::GPUDeviceDescriptor,
mExtensions, mLimits);
#undef DEFINE_IPC_SERIALIZER_ENUM
} // namespace IPC
#endif // WEBGPU_SERIALIZE_H_

View File

@ -1,18 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef WEBGPU_TYPES_H_
#define WEBGPU_TYPES_H_
namespace mozilla {
namespace webgpu {
typedef uint64_t RawId;
} // namespace webgpu
} // namespace mozilla
#endif // WEBGPU_TYPES_H_

View File

@ -3,4 +3,4 @@ subsuite = webgl1-core
prefs = dom.webgpu.enable=true
[test_enabled.html]
[test_device_creation.html]

View File

@ -1,25 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset='utf-8'>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head>
<body>
<script>
ok(SpecialPowers.getBoolPref('dom.webgpu.enable'), 'Pref should be enabled.');
const func = async function() {
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
ok(device !== undefined, 'device !== undefined');
};
SimpleTest.waitForExplicitFinish();
func().finally(() => SimpleTest.finish());
</script>
</body>
</html>

View File

@ -13,7 +13,7 @@ MOCHITEST_MANIFESTS += [
]
DIRS += [
'ffi',
'thread',
]
h_and_cpp = [
@ -30,6 +30,7 @@ h_and_cpp = [
'DeviceLostInfo',
'Fence',
'Instance',
'InstanceProvider',
'ObjectModel',
'OutOfMemoryError',
'PipelineLayout',
@ -50,22 +51,4 @@ h_and_cpp = [
EXPORTS.mozilla.webgpu += [x + '.h' for x in h_and_cpp]
UNIFIED_SOURCES += [x + '.cpp' for x in h_and_cpp]
IPDL_SOURCES += [
'ipc/PWebGPU.ipdl',
]
EXPORTS.mozilla.webgpu += [
'ipc/WebGPUChild.h',
'ipc/WebGPUParent.h',
'ipc/WebGPUSerialize.h',
'ipc/WebGPUTypes.h',
]
UNIFIED_SOURCES += [
'ipc/WebGPUChild.cpp',
'ipc/WebGPUParent.cpp',
]
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'

View File

@ -0,0 +1,61 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WebGPUThreading.h"
#include "mtransport/runnable_utils.h"
namespace mozilla {
namespace webgpu {
static StaticRefPtr<WebGPUThreading> sWebGPUThread;
WebGPUThreading::WebGPUThreading(base::Thread* aThread) : mThread(aThread) {}
WebGPUThreading::~WebGPUThreading() { delete mThread; }
// static
void WebGPUThreading::Start() {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!sWebGPUThread);
base::Thread* thread = new base::Thread("WebGPU");
base::Thread::Options options;
if (!thread->StartWithOptions(options)) {
delete thread;
return;
}
sWebGPUThread = new WebGPUThreading(thread);
const auto fnInit = []() {};
RefPtr<Runnable> runnable =
NS_NewRunnableFunction("WebGPUThreading fnInit", fnInit);
sWebGPUThread->GetLoop()->PostTask(runnable.forget());
}
// static
void WebGPUThreading::ShutDown() {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(sWebGPUThread);
const auto fnExit = []() {};
RefPtr<Runnable> runnable =
NS_NewRunnableFunction("WebGPUThreading fnExit", fnExit);
sWebGPUThread->GetLoop()->PostTask(runnable.forget());
sWebGPUThread = nullptr;
}
// static
MessageLoop* WebGPUThreading::GetLoop() {
MOZ_ASSERT(NS_IsMainThread());
return sWebGPUThread ? sWebGPUThread->mThread->message_loop() : nullptr;
}
} // namespace webgpu
} // namespace mozilla

View File

@ -0,0 +1,42 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef MOZILLA_WEBGPU_THREADING_H
#define MOZILLA_WEBGPU_THREADING_H
#include "ThreadSafeRefcountingWithMainThreadDestruction.h"
#include "base/thread.h" // for Thread
#include "mozilla/layers/SynchronousTask.h"
namespace mozilla {
namespace webgpu {
class WebGPUThreading final {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(
WebGPUThreading)
public:
/// Can only be called from the main thread.
static void Start();
/// Can only be called from the main thread.
static void ShutDown();
/// Can be called from any thread. Returns `nullptr` if
/// the threading is not initialized.
static MessageLoop* GetLoop();
private:
explicit WebGPUThreading(base::Thread* aThread);
~WebGPUThreading();
base::Thread* const mThread;
};
} // namespace webgpu
} // namespace mozilla
#endif // MOZILLA_WEBGPU_THREADING_H

View File

@ -0,0 +1,18 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
h_and_cpp = [
'WebGPUThreading',
]
EXPORTS.mozilla.webgpu += [x + '.h' for x in h_and_cpp]
UNIFIED_SOURCES += [x + '.cpp' for x in h_and_cpp]
LOCAL_INCLUDES += [
'/ipc/chromium/src',
]
FINAL_LIBRARY = 'xul'

View File

@ -1,53 +0,0 @@
[package]
name = "wgpu-native"
version = "0.4.0"
authors = [
"Dzmitry Malyshau <kvark@mozilla.com>",
"Joshua Groves <josh@joshgroves.com>",
]
edition = "2018"
description = "WebGPU native implementation on gfx-hal"
homepage = "https://github.com/gfx-rs/wgpu"
repository = "https://github.com/gfx-rs/wgpu"
keywords = ["graphics"]
license = "MPL-2.0"
[lib]
#crate-type = ["lib", "cdylib", "staticlib"]
crate-type = ["lib"]
[features]
default = []
local = ["lazy_static", "raw-window-handle"]
metal-auto-capture = ["gfx-backend-metal/auto-capture"]
#NOTE: glutin feature is not stable, use at your own risk
#glutin = ["gfx-backend-gl/glutin"]
[dependencies]
arrayvec = "0.5"
bitflags = "1.0"
copyless = "0.1"
fxhash = "0.2"
lazy_static = { version = "1.1.0", optional = true }
log = "0.4"
hal = { package = "gfx-hal", version = "0.4" }
gfx-backend-empty = { version = "0.4" }
parking_lot = "0.9"
raw-window-handle = { version = "0.3", optional = true }
rendy-memory = "0.5"
rendy-descriptor = "0.5"
serde = { version = "1.0", features = ["serde_derive"], optional = true }
smallvec = "0.6"
vec_map = "0.8"
[target.'cfg(any(target_os = "ios", target_os = "macos"))'.dependencies]
gfx-backend-metal = { version = "0.4" }
gfx-backend-vulkan = { version = "0.4", optional = true }
[target.'cfg(all(unix, not(target_os = "ios"), not(target_os = "macos")))'.dependencies]
gfx-backend-vulkan = { version = "0.4", features = ["x11"] }
[target.'cfg(windows)'.dependencies]
gfx-backend-dx12 = { version = "0.4.1" }
gfx-backend-dx11 = { version = "0.4" }
gfx-backend-vulkan = { version = "0.4" }

View File

@ -1,37 +0,0 @@
header = """
#define WGPU_LOCAL
"""
include_version = true
braces = "SameLine"
line_length = 100
tab_width = 2
language = "C"
[export]
prefix = "WGPU"
#TODO: figure out why cbindgen even tries to export a private type...
exclude = ["BufferMapResult"]
[parse]
parse_deps = false
[parse.expand]
features = ["local"]
[fn]
[struct]
derive_eq = true
[enum]
prefix_with_name = true
derive_helper_methods = true
[macro_expansion]
bitflags = true
[defines]
"feature = local" = "WGPU_LOCAL"
"feature = gfx-backend-gl" = "WGPU_BACKEND_GL"
"feature = winit" = "WGPU_WINIT"
"feature = glutin" = "WGPU_GLUTIN"

View File

@ -1,132 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use crate::{
resource::TextureViewDimension,
track::TrackerSet,
BindGroupLayoutId,
BufferAddress,
BufferId,
DeviceId,
LifeGuard,
RefCount,
SamplerId,
Stored,
TextureViewId,
};
use arrayvec::ArrayVec;
use bitflags::bitflags;
use rendy_descriptor::{DescriptorRanges, DescriptorSet};
use std::borrow::Borrow;
pub const MAX_BIND_GROUPS: usize = 4;
bitflags! {
#[repr(transparent)]
pub struct ShaderStage: u32 {
const NONE = 0;
const VERTEX = 1;
const FRAGMENT = 2;
const COMPUTE = 4;
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum BindingType {
UniformBuffer = 0,
StorageBuffer = 1,
ReadonlyStorageBuffer = 2,
Sampler = 3,
SampledTexture = 4,
StorageTexture = 5,
}
#[repr(C)]
#[derive(Clone, Debug, Hash)]
pub struct BindGroupLayoutBinding {
pub binding: u32,
pub visibility: ShaderStage,
pub ty: BindingType,
pub texture_dimension: TextureViewDimension,
pub multisampled: bool,
pub dynamic: bool,
}
#[repr(C)]
#[derive(Debug)]
pub struct BindGroupLayoutDescriptor {
pub bindings: *const BindGroupLayoutBinding,
pub bindings_length: usize,
}
#[derive(Debug)]
pub struct BindGroupLayout<B: hal::Backend> {
pub(crate) raw: B::DescriptorSetLayout,
pub(crate) bindings: Vec<BindGroupLayoutBinding>,
pub(crate) desc_ranges: DescriptorRanges,
pub(crate) dynamic_count: usize,
}
#[repr(C)]
#[derive(Debug)]
pub struct PipelineLayoutDescriptor {
pub bind_group_layouts: *const BindGroupLayoutId,
pub bind_group_layouts_length: usize,
}
#[derive(Debug)]
pub struct PipelineLayout<B: hal::Backend> {
pub(crate) raw: B::PipelineLayout,
pub(crate) bind_group_layout_ids: ArrayVec<[BindGroupLayoutId; MAX_BIND_GROUPS]>,
}
#[repr(C)]
#[derive(Debug)]
pub struct BufferBinding {
pub buffer: BufferId,
pub offset: BufferAddress,
pub size: BufferAddress,
}
#[repr(C)]
#[derive(Debug)]
pub enum BindingResource {
Buffer(BufferBinding),
Sampler(SamplerId),
TextureView(TextureViewId),
}
#[repr(C)]
#[derive(Debug)]
pub struct BindGroupBinding {
pub binding: u32,
pub resource: BindingResource,
}
#[repr(C)]
#[derive(Debug)]
pub struct BindGroupDescriptor {
pub layout: BindGroupLayoutId,
pub bindings: *const BindGroupBinding,
pub bindings_length: usize,
}
#[derive(Debug)]
pub struct BindGroup<B: hal::Backend> {
pub(crate) raw: DescriptorSet<B>,
pub(crate) device_id: Stored<DeviceId>,
pub(crate) layout_id: BindGroupLayoutId,
pub(crate) life_guard: LifeGuard,
pub(crate) used: TrackerSet,
pub(crate) dynamic_count: usize,
}
impl<B: hal::Backend> Borrow<RefCount> for BindGroup<B> {
fn borrow(&self) -> &RefCount {
&self.life_guard.ref_count
}
}

View File

@ -1,165 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use super::CommandBuffer;
use crate::{
hub::GfxBackend,
track::TrackerSet,
DeviceId,
Features,
LifeGuard,
Stored,
SubmissionIndex,
};
use hal::{command::CommandBuffer as _, device::Device as _, pool::CommandPool as _};
use parking_lot::Mutex;
use std::{collections::HashMap, sync::atomic::Ordering, thread};
#[derive(Debug)]
struct CommandPool<B: hal::Backend> {
raw: B::CommandPool,
available: Vec<B::CommandBuffer>,
}
impl<B: hal::Backend> CommandPool<B> {
fn allocate(&mut self) -> B::CommandBuffer {
if self.available.is_empty() {
let extra = unsafe {
self.raw.allocate_vec(20, hal::command::Level::Primary)
};
self.available.extend(extra);
}
self.available.pop().unwrap()
}
}
#[derive(Debug)]
struct Inner<B: hal::Backend> {
pools: HashMap<thread::ThreadId, CommandPool<B>>,
pending: Vec<CommandBuffer<B>>,
}
impl<B: hal::Backend> Inner<B> {
fn recycle(&mut self, cmd_buf: CommandBuffer<B>) {
let pool = self.pools.get_mut(&cmd_buf.recorded_thread_id).unwrap();
for mut raw in cmd_buf.raw {
unsafe {
raw.reset(false);
}
pool.available.push(raw);
}
}
}
#[derive(Debug)]
pub struct CommandAllocator<B: hal::Backend> {
queue_family: hal::queue::QueueFamilyId,
inner: Mutex<Inner<B>>,
}
impl<B: GfxBackend> CommandAllocator<B> {
pub(crate) fn allocate(
&self,
device_id: Stored<DeviceId>,
device: &B::Device,
features: Features,
) -> CommandBuffer<B> {
//debug_assert_eq!(device_id.backend(), B::VARIANT);
let thread_id = thread::current().id();
let mut inner = self.inner.lock();
let pool = inner.pools.entry(thread_id).or_insert_with(|| CommandPool {
raw: unsafe {
device.create_command_pool(
self.queue_family,
hal::pool::CommandPoolCreateFlags::RESET_INDIVIDUAL,
)
}
.unwrap(),
available: Vec::new(),
});
let init = pool.allocate();
CommandBuffer {
raw: vec![init],
is_recording: true,
recorded_thread_id: thread_id,
device_id,
life_guard: LifeGuard::new(),
trackers: TrackerSet::new(B::VARIANT),
used_swap_chain: None,
features,
}
}
}
impl<B: hal::Backend> CommandAllocator<B> {
pub fn new(queue_family: hal::queue::QueueFamilyId) -> Self {
CommandAllocator {
queue_family,
inner: Mutex::new(Inner {
pools: HashMap::new(),
pending: Vec::new(),
}),
}
}
pub fn extend(&self, cmd_buf: &CommandBuffer<B>) -> B::CommandBuffer {
let mut inner = self.inner.lock();
let pool = inner.pools.get_mut(&cmd_buf.recorded_thread_id).unwrap();
if pool.available.is_empty() {
let extra = unsafe {
pool.raw.allocate_vec(20, hal::command::Level::Primary)
};
pool.available.extend(extra);
}
pool.available.pop().unwrap()
}
pub fn after_submit(&self, mut cmd_buf: CommandBuffer<B>, submit_index: SubmissionIndex) {
cmd_buf.trackers.clear();
cmd_buf
.life_guard
.submission_index
.store(submit_index, Ordering::Release);
self.inner.lock().pending.push(cmd_buf);
}
pub fn maintain(&self, last_done: SubmissionIndex) {
let mut inner = self.inner.lock();
for i in (0 .. inner.pending.len()).rev() {
let index = inner.pending[i]
.life_guard
.submission_index
.load(Ordering::Acquire);
if index <= last_done {
let cmd_buf = inner.pending.swap_remove(i);
log::trace!(
"recycling comb submitted in {} when {} is done",
index,
last_done
);
inner.recycle(cmd_buf);
}
}
}
pub fn destroy(self, device: &B::Device) {
let mut inner = self.inner.lock();
while let Some(cmd_buf) = inner.pending.pop() {
inner.recycle(cmd_buf);
}
for (_, mut pool) in inner.pools.drain() {
unsafe {
pool.raw.free(pool.available);
device.destroy_command_pool(pool.raw);
}
}
}
}

View File

@ -1,222 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use crate::{
hub::GfxBackend,
BindGroup,
BindGroupId,
BindGroupLayoutId,
BufferAddress,
PipelineLayoutId,
Stored,
};
use smallvec::{smallvec, SmallVec};
use std::convert::identity;
pub const DEFAULT_BIND_GROUPS: usize = 4;
type BindGroupMask = u8;
#[derive(Clone, Debug)]
pub struct BindGroupPair {
layout_id: BindGroupLayoutId,
group_id: Stored<BindGroupId>,
}
#[derive(Debug)]
pub enum LayoutChange<'a> {
Unchanged,
Match(BindGroupId, &'a [BufferAddress]),
Mismatch,
}
#[derive(Debug)]
pub enum Provision {
Unchanged,
Changed { was_compatible: bool },
}
struct TakeSome<I> {
iter: I,
}
impl<T, I> Iterator for TakeSome<I>
where
I: Iterator<Item = Option<T>>,
{
type Item = T;
fn next(&mut self) -> Option<T> {
self.iter.next().and_then(identity)
}
}
#[derive(Clone, Default, Debug)]
pub struct BindGroupEntry {
expected_layout_id: Option<BindGroupLayoutId>,
provided: Option<BindGroupPair>,
dynamic_offsets: Vec<BufferAddress>,
}
impl BindGroupEntry {
fn provide<B: GfxBackend>(
&mut self,
bind_group_id: BindGroupId,
bind_group: &BindGroup<B>,
offsets: &[BufferAddress],
) -> Provision {
debug_assert_eq!(B::VARIANT, bind_group_id.backend());
let was_compatible = match self.provided {
Some(BindGroupPair {
layout_id,
ref group_id,
}) => {
if group_id.value == bind_group_id && offsets == self.dynamic_offsets.as_slice() {
assert_eq!(layout_id, bind_group.layout_id);
return Provision::Unchanged;
}
self.expected_layout_id == Some(layout_id)
}
None => true,
};
self.provided = Some(BindGroupPair {
layout_id: bind_group.layout_id,
group_id: Stored {
value: bind_group_id,
ref_count: bind_group.life_guard.ref_count.clone(),
},
});
//TODO: validate the count of dynamic offsets to match the layout
self.dynamic_offsets.clear();
self.dynamic_offsets.extend_from_slice(offsets);
Provision::Changed { was_compatible }
}
pub fn expect_layout(&mut self, bind_group_layout_id: BindGroupLayoutId) -> LayoutChange {
let some = Some(bind_group_layout_id);
if self.expected_layout_id != some {
self.expected_layout_id = some;
match self.provided {
Some(BindGroupPair {
layout_id,
ref group_id,
}) if layout_id == bind_group_layout_id => {
LayoutChange::Match(group_id.value, &self.dynamic_offsets)
}
Some(_) | None => LayoutChange::Mismatch,
}
} else {
LayoutChange::Unchanged
}
}
fn is_valid(&self) -> bool {
match (self.expected_layout_id, self.provided.as_ref()) {
(None, _) => true,
(Some(_), None) => false,
(Some(layout), Some(pair)) => layout == pair.layout_id,
}
}
fn actual_value(&self) -> Option<BindGroupId> {
self.expected_layout_id.and_then(|layout_id| {
self.provided.as_ref().and_then(|pair| {
if pair.layout_id == layout_id {
Some(pair.group_id.value)
} else {
None
}
})
})
}
}
#[derive(Debug)]
pub struct Binder {
pub(crate) pipeline_layout_id: Option<PipelineLayoutId>, //TODO: strongly `Stored`
pub(crate) entries: SmallVec<[BindGroupEntry; DEFAULT_BIND_GROUPS]>,
}
impl Binder {
pub(crate) fn new(max_bind_groups: u32) -> Self {
Self {
pipeline_layout_id: None,
entries: smallvec![Default::default(); max_bind_groups as usize],
}
}
pub(crate) fn reset_expectations(&mut self, length: usize) {
for entry in self.entries[length ..].iter_mut() {
entry.expected_layout_id = None;
}
}
/// Attempt to set the value of the specified bind group index.
/// Returns Some() when the new bind group is ready to be actually bound
/// (i.e. compatible with current expectations). Also returns an iterator
/// of bind group IDs to be bound with it: those are compatible bind groups
/// that were previously blocked because the current one was incompatible.
pub(crate) fn provide_entry<'a, B: GfxBackend>(
&'a mut self,
index: usize,
bind_group_id: BindGroupId,
bind_group: &BindGroup<B>,
offsets: &[BufferAddress],
) -> Option<(
PipelineLayoutId,
impl 'a + Iterator<Item = BindGroupId>,
impl 'a + Iterator<Item = &'a BufferAddress>,
)> {
log::trace!("\tBinding [{}] = group {:?}", index, bind_group_id);
debug_assert_eq!(B::VARIANT, bind_group_id.backend());
match self.entries[index].provide(bind_group_id, bind_group, offsets) {
Provision::Unchanged => None,
Provision::Changed { was_compatible, .. } => {
let compatible_count = self.compatible_count();
if index < compatible_count {
let end = compatible_count.min(if was_compatible {
index + 1
} else {
self.entries.len()
});
log::trace!("\t\tbinding up to {}", end);
Some((
self.pipeline_layout_id?,
TakeSome {
iter: self.entries[index + 1 .. end]
.iter()
.map(|entry| entry.actual_value()),
},
self.entries[index + 1 .. end]
.iter()
.flat_map(|entry| entry.dynamic_offsets.as_slice()),
))
} else {
log::trace!("\t\tskipping above compatible {}", compatible_count);
None
}
}
}
}
pub(crate) fn invalid_mask(&self) -> BindGroupMask {
self.entries.iter().enumerate().fold(0, |mask, (i, entry)| {
if entry.is_valid() {
mask
} else {
mask | 1u8 << i
}
})
}
fn compatible_count(&self) -> usize {
self.entries
.iter()
.position(|entry| !entry.is_valid())
.unwrap_or(self.entries.len())
}
}

View File

@ -1,316 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use crate::{
command::bind::{Binder, LayoutChange},
device::all_buffer_stages,
hub::{GfxBackend, Global, Token},
track::{Stitch, TrackerSet},
BindGroupId,
BufferAddress,
BufferId,
BufferUsage,
CommandBuffer,
CommandBufferId,
ComputePassId,
ComputePipelineId,
RawString,
Stored,
BIND_BUFFER_ALIGNMENT,
};
#[cfg(feature = "local")]
use crate::{gfx_select, hub::GLOBAL};
use hal::{self, command::CommandBuffer as _};
use std::iter;
#[cfg(feature = "local")]
use std::slice;
#[derive(Debug)]
pub struct ComputePass<B: hal::Backend> {
raw: B::CommandBuffer,
cmb_id: Stored<CommandBufferId>,
binder: Binder,
trackers: TrackerSet,
}
impl<B: hal::Backend> ComputePass<B> {
pub(crate) fn new(
raw: B::CommandBuffer,
cmb_id: Stored<CommandBufferId>,
trackers: TrackerSet,
max_bind_groups: u32,
) -> Self {
ComputePass {
raw,
cmb_id,
binder: Binder::new(max_bind_groups),
trackers,
}
}
}
// Common routines between render/compute
pub fn compute_pass_end_pass<B: GfxBackend>(global: &Global, pass_id: ComputePassId) {
let mut token = Token::root();
let hub = B::hub(global);
let (mut cmb_guard, mut token) = hub.command_buffers.write(&mut token);
let (pass, _) = hub.compute_passes.unregister(pass_id, &mut token);
let cmb = &mut cmb_guard[pass.cmb_id.value];
// There are no transitions to be made: we've already been inserting barriers
// into the parent command buffer while recording this compute pass.
cmb.trackers = pass.trackers;
cmb.raw.push(pass.raw);
}
#[cfg(feature = "local")]
#[no_mangle]
pub extern "C" fn wgpu_compute_pass_end_pass(pass_id: ComputePassId) {
gfx_select!(pass_id => compute_pass_end_pass(&*GLOBAL, pass_id))
}
pub fn compute_pass_set_bind_group<B: GfxBackend>(
global: &Global,
pass_id: ComputePassId,
index: u32,
bind_group_id: BindGroupId,
offsets: &[BufferAddress],
) {
let hub = B::hub(global);
let mut token = Token::root();
let (pipeline_layout_guard, mut token) = hub.pipeline_layouts.read(&mut token);
let (bind_group_guard, mut token) = hub.bind_groups.read(&mut token);
let (mut pass_guard, mut token) = hub.compute_passes.write(&mut token);
let pass = &mut pass_guard[pass_id];
let bind_group = pass
.trackers
.bind_groups
.use_extend(&*bind_group_guard, bind_group_id, (), ())
.unwrap();
assert_eq!(bind_group.dynamic_count, offsets.len());
if cfg!(debug_assertions) {
for off in offsets {
assert_eq!(
*off % BIND_BUFFER_ALIGNMENT,
0,
"Misaligned dynamic buffer offset: {} does not align with {}",
off,
BIND_BUFFER_ALIGNMENT
);
}
}
//Note: currently, WebGPU compute passes have synchronization defined
// at a dispatch granularity, so we insert the necessary barriers here.
let (buffer_guard, mut token) = hub.buffers.read(&mut token);
let (texture_guard, _) = hub.textures.read(&mut token);
log::trace!(
"Encoding barriers on binding of {:?} in pass {:?}",
bind_group_id,
pass_id
);
CommandBuffer::insert_barriers(
&mut pass.raw,
&mut pass.trackers,
&bind_group.used,
Stitch::Last,
&*buffer_guard,
&*texture_guard,
);
if let Some((pipeline_layout_id, follow_up_sets, follow_up_offsets)) = pass
.binder
.provide_entry(index as usize, bind_group_id, bind_group, offsets)
{
let bind_groups = iter::once(bind_group.raw.raw())
.chain(follow_up_sets.map(|bg_id| bind_group_guard[bg_id].raw.raw()));
unsafe {
pass.raw.bind_compute_descriptor_sets(
&pipeline_layout_guard[pipeline_layout_id].raw,
index as usize,
bind_groups,
offsets
.iter()
.chain(follow_up_offsets)
.map(|&off| off as hal::command::DescriptorSetOffset),
);
}
};
}
#[cfg(feature = "local")]
#[no_mangle]
pub extern "C" fn wgpu_compute_pass_set_bind_group(
pass_id: ComputePassId,
index: u32,
bind_group_id: BindGroupId,
offsets: *const BufferAddress,
offsets_length: usize,
) {
let offsets = if offsets_length != 0 {
unsafe { slice::from_raw_parts(offsets, offsets_length) }
} else {
&[]
};
gfx_select!(pass_id => compute_pass_set_bind_group(&*GLOBAL, pass_id, index, bind_group_id, offsets))
}
#[no_mangle]
pub extern "C" fn wgpu_compute_pass_push_debug_group(_pass_id: ComputePassId, _label: RawString) {
//TODO
}
#[no_mangle]
pub extern "C" fn wgpu_compute_pass_pop_debug_group(_pass_id: ComputePassId) {
//TODO
}
#[no_mangle]
pub extern "C" fn wgpu_compute_pass_insert_debug_marker(
_pass_id: ComputePassId,
_label: RawString,
) {
//TODO
}
// Compute-specific routines
pub fn compute_pass_dispatch<B: GfxBackend>(
global: &Global,
pass_id: ComputePassId,
x: u32,
y: u32,
z: u32,
) {
let hub = B::hub(global);
let mut token = Token::root();
let (mut pass_guard, _) = hub.compute_passes.write(&mut token);
unsafe {
pass_guard[pass_id].raw.dispatch([x, y, z]);
}
}
#[cfg(feature = "local")]
#[no_mangle]
pub extern "C" fn wgpu_compute_pass_dispatch(pass_id: ComputePassId, x: u32, y: u32, z: u32) {
gfx_select!(pass_id => compute_pass_dispatch(&*GLOBAL, pass_id, x, y, z))
}
pub fn compute_pass_dispatch_indirect<B: GfxBackend>(
global: &Global,
pass_id: ComputePassId,
indirect_buffer_id: BufferId,
indirect_offset: BufferAddress,
) {
let hub = B::hub(global);
let mut token = Token::root();
let (buffer_guard, _) = hub.buffers.read(&mut token);
let (mut pass_guard, _) = hub.compute_passes.write(&mut token);
let pass = &mut pass_guard[pass_id];
let (src_buffer, src_pending) = pass.trackers.buffers.use_replace(
&*buffer_guard,
indirect_buffer_id,
(),
BufferUsage::INDIRECT,
);
assert!(src_buffer.usage.contains(BufferUsage::INDIRECT));
let barriers = src_pending.map(|pending| hal::memory::Barrier::Buffer {
states: pending.to_states(),
target: &src_buffer.raw,
families: None,
range: None .. None,
});
unsafe {
pass.raw.pipeline_barrier(
all_buffer_stages() .. all_buffer_stages(),
hal::memory::Dependencies::empty(),
barriers,
);
pass.raw.dispatch_indirect(&src_buffer.raw, indirect_offset);
}
}
#[cfg(feature = "local")]
#[no_mangle]
pub extern "C" fn wgpu_compute_pass_dispatch_indirect(
pass_id: ComputePassId,
indirect_buffer_id: BufferId,
indirect_offset: BufferAddress,
) {
gfx_select!(pass_id => compute_pass_dispatch_indirect(&*GLOBAL, pass_id, indirect_buffer_id, indirect_offset))
}
pub fn compute_pass_set_pipeline<B: GfxBackend>(
global: &Global,
pass_id: ComputePassId,
pipeline_id: ComputePipelineId,
) {
let hub = B::hub(global);
let mut token = Token::root();
let (pipeline_layout_guard, mut token) = hub.pipeline_layouts.read(&mut token);
let (bind_group_guard, mut token) = hub.bind_groups.read(&mut token);
let (mut pass_guard, mut token) = hub.compute_passes.write(&mut token);
let pass = &mut pass_guard[pass_id];
let (pipeline_guard, _) = hub.compute_pipelines.read(&mut token);
let pipeline = &pipeline_guard[pipeline_id];
unsafe {
pass.raw.bind_compute_pipeline(&pipeline.raw);
}
// Rebind resources
if pass.binder.pipeline_layout_id != Some(pipeline.layout_id.clone()) {
let pipeline_layout = &pipeline_layout_guard[pipeline.layout_id];
pass.binder.pipeline_layout_id = Some(pipeline.layout_id.clone());
pass.binder
.reset_expectations(pipeline_layout.bind_group_layout_ids.len());
let mut is_compatible = true;
for (index, (entry, &bgl_id)) in pass
.binder
.entries
.iter_mut()
.zip(&pipeline_layout.bind_group_layout_ids)
.enumerate()
{
match entry.expect_layout(bgl_id) {
LayoutChange::Match(bg_id, offsets) if is_compatible => {
let desc_set = bind_group_guard[bg_id].raw.raw();
unsafe {
pass.raw.bind_compute_descriptor_sets(
&pipeline_layout.raw,
index,
iter::once(desc_set),
offsets.iter().map(|offset| *offset as u32),
);
}
}
LayoutChange::Match(..) | LayoutChange::Unchanged => {}
LayoutChange::Mismatch => {
is_compatible = false;
}
}
}
}
}
#[cfg(feature = "local")]
#[no_mangle]
pub extern "C" fn wgpu_compute_pass_set_pipeline(
pass_id: ComputePassId,
pipeline_id: ComputePipelineId,
) {
gfx_select!(pass_id => compute_pass_set_pipeline(&*GLOBAL, pass_id, pipeline_id))
}

View File

@ -1,769 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
mod allocator;
mod bind;
mod compute;
mod render;
mod transfer;
pub(crate) use self::allocator::CommandAllocator;
pub use self::compute::*;
pub use self::render::*;
pub use self::transfer::*;
use crate::{
conv,
device::{
all_buffer_stages,
all_image_stages,
FramebufferKey,
RenderPassContext,
RenderPassKey,
},
hub::{GfxBackend, Global, Storage, Token},
id::{Input, Output},
resource::TextureViewInner,
track::{Stitch, TrackerSet},
Buffer,
BufferId,
Color,
CommandBufferId,
CommandEncoderId,
ComputePassId,
DeviceId,
Features,
LifeGuard,
RenderPassId,
Stored,
Texture,
TextureId,
TextureUsage,
TextureViewId,
};
#[cfg(feature = "local")]
use crate::{gfx_select, hub::GLOBAL};
use arrayvec::ArrayVec;
use hal::{adapter::PhysicalDevice as _, command::CommandBuffer as _, device::Device as _};
#[cfg(feature = "local")]
use std::marker::PhantomData;
use std::{borrow::Borrow, collections::hash_map::Entry, iter, mem, ptr, slice, thread::ThreadId};
pub struct RenderBundle<B: hal::Backend> {
_raw: B::CommandBuffer,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum LoadOp {
Clear = 0,
Load = 1,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum StoreOp {
Clear = 0,
Store = 1,
}
#[repr(C)]
#[derive(Debug)]
pub struct RenderPassColorAttachmentDescriptor {
pub attachment: TextureViewId,
pub resolve_target: *const TextureViewId,
pub load_op: LoadOp,
pub store_op: StoreOp,
pub clear_color: Color,
}
#[repr(C)]
#[derive(Debug)]
pub struct RenderPassDepthStencilAttachmentDescriptor<T> {
pub attachment: T,
pub depth_load_op: LoadOp,
pub depth_store_op: StoreOp,
pub clear_depth: f32,
pub stencil_load_op: LoadOp,
pub stencil_store_op: StoreOp,
pub clear_stencil: u32,
}
#[repr(C)]
#[derive(Debug)]
pub struct RenderPassDescriptor {
pub color_attachments: *const RenderPassColorAttachmentDescriptor,
pub color_attachments_length: usize,
pub depth_stencil_attachment: *const RenderPassDepthStencilAttachmentDescriptor<TextureViewId>,
}
#[repr(C)]
#[derive(Clone, Debug, Default)]
pub struct ComputePassDescriptor {
pub todo: u32,
}
#[derive(Debug)]
pub struct CommandBuffer<B: hal::Backend> {
pub(crate) raw: Vec<B::CommandBuffer>,
is_recording: bool,
recorded_thread_id: ThreadId,
pub(crate) device_id: Stored<DeviceId>,
pub(crate) life_guard: LifeGuard,
pub(crate) trackers: TrackerSet,
pub(crate) used_swap_chain: Option<(Stored<TextureViewId>, B::Framebuffer)>,
pub(crate) features: Features,
}
impl<B: GfxBackend> CommandBuffer<B> {
pub(crate) fn insert_barriers(
raw: &mut B::CommandBuffer,
base: &mut TrackerSet,
head: &TrackerSet,
stitch: Stitch,
buffer_guard: &Storage<Buffer<B>, BufferId>,
texture_guard: &Storage<Texture<B>, TextureId>,
) {
log::trace!("\tstitch {:?}", stitch);
debug_assert_eq!(B::VARIANT, base.backend());
debug_assert_eq!(B::VARIANT, head.backend());
let buffer_barriers = base
.buffers
.merge_replace(&head.buffers, stitch)
.map(|pending| {
log::trace!("\tbuffer -> {:?}", pending);
hal::memory::Barrier::Buffer {
states: pending.to_states(),
target: &buffer_guard[pending.id].raw,
range: None .. None,
families: None,
}
});
let texture_barriers = base
.textures
.merge_replace(&head.textures, stitch)
.map(|pending| {
log::trace!("\ttexture -> {:?}", pending);
hal::memory::Barrier::Image {
states: pending.to_states(),
target: &texture_guard[pending.id].raw,
range: pending.selector,
families: None,
}
});
base.views.merge_extend(&head.views).unwrap();
base.bind_groups.merge_extend(&head.bind_groups).unwrap();
base.samplers.merge_extend(&head.samplers).unwrap();
let stages = all_buffer_stages() | all_image_stages();
unsafe {
raw.pipeline_barrier(
stages .. stages,
hal::memory::Dependencies::empty(),
buffer_barriers.chain(texture_barriers),
);
}
}
}
#[repr(C)]
#[derive(Clone, Debug, Default)]
pub struct CommandEncoderDescriptor {
// MSVC doesn't allow zero-sized structs
// We can remove this when we actually have a field
pub todo: u32,
}
#[repr(C)]
#[derive(Clone, Debug, Default)]
pub struct CommandBufferDescriptor {
pub todo: u32,
}
pub fn command_encoder_finish<B: GfxBackend>(
global: &Global,
encoder_id: CommandEncoderId,
_desc: &CommandBufferDescriptor,
) -> CommandBufferId {
let hub = B::hub(global);
let mut token = Token::root();
//TODO: actually close the last recorded command buffer
let (mut comb_guard, _) = hub.command_buffers.write(&mut token);
let comb = &mut comb_guard[encoder_id];
assert!(comb.is_recording);
comb.is_recording = false;
// stop tracking the swapchain image, if used
if let Some((ref view_id, _)) = comb.used_swap_chain {
comb.trackers.views.remove(view_id.value);
}
encoder_id
}
#[cfg(feature = "local")]
#[no_mangle]
pub extern "C" fn wgpu_command_encoder_finish(
encoder_id: CommandEncoderId,
desc: Option<&CommandBufferDescriptor>,
) -> CommandBufferId {
let desc = &desc.cloned().unwrap_or_default();
gfx_select!(encoder_id => command_encoder_finish(&*GLOBAL, encoder_id, desc))
}
pub fn command_encoder_begin_render_pass<B: GfxBackend>(
global: &Global,
encoder_id: CommandEncoderId,
desc: &RenderPassDescriptor,
id_in: Input<RenderPassId>,
) -> Output<RenderPassId> {
let hub = B::hub(global);
let mut token = Token::root();
let (adapter_guard, mut token) = hub.adapters.read(&mut token);
let (device_guard, mut token) = hub.devices.read(&mut token);
let (mut cmb_guard, mut token) = hub.command_buffers.write(&mut token);
let cmb = &mut cmb_guard[encoder_id];
let device = &device_guard[cmb.device_id.value];
let limits = adapter_guard[device.adapter_id]
.raw
.physical_device
.limits();
let samples_count_limit = limits.framebuffer_color_sample_counts;
let mut current_comb = device.com_allocator.extend(cmb);
unsafe {
current_comb.begin(
hal::command::CommandBufferFlags::ONE_TIME_SUBMIT,
hal::command::CommandBufferInheritanceInfo::default(),
);
}
let pass = {
let (_, mut token) = hub.buffers.read(&mut token); //skip token
let (texture_guard, mut token) = hub.textures.read(&mut token);
let (view_guard, _) = hub.texture_views.read(&mut token);
let mut extent = None;
let mut barriers = Vec::new();
let mut used_swap_chain_image = None::<Stored<TextureViewId>>;
let color_attachments =
unsafe { slice::from_raw_parts(desc.color_attachments, desc.color_attachments_length) };
let depth_stencil_attachment = unsafe { desc.depth_stencil_attachment.as_ref() };
let sample_count = color_attachments
.get(0)
.map(|at| view_guard[at.attachment].samples)
.unwrap_or(1);
assert!(
sample_count & samples_count_limit != 0,
"Attachment sample_count must be supported by physical device limits"
);
log::trace!(
"Encoding render pass begin in command buffer {:?}",
encoder_id
);
let rp_key = {
let trackers = &mut cmb.trackers;
let depth_stencil = depth_stencil_attachment.map(|at| {
let view = trackers
.views
.use_extend(&*view_guard, at.attachment, (), ())
.unwrap();
if let Some(ex) = extent {
assert_eq!(ex, view.extent);
} else {
extent = Some(view.extent);
}
let texture_id = match view.inner {
TextureViewInner::Native { ref source_id, .. } => source_id.value,
TextureViewInner::SwapChain { .. } => {
panic!("Unexpected depth/stencil use of swapchain image!")
}
};
let texture = &texture_guard[texture_id];
assert!(texture.usage.contains(TextureUsage::OUTPUT_ATTACHMENT));
let old_layout = match trackers.textures.query(texture_id, view.range.clone()) {
Some(usage) => {
conv::map_texture_state(
usage,
hal::format::Aspects::DEPTH | hal::format::Aspects::STENCIL,
)
.1
}
None => {
// Required sub-resources have inconsistent states, we need to
// issue individual barriers instead of relying on the render pass.
let pending = trackers.textures.change_replace(
texture_id,
&texture.life_guard.ref_count,
view.range.clone(),
TextureUsage::OUTPUT_ATTACHMENT,
);
barriers.extend(pending.map(|pending| {
log::trace!("\tdepth-stencil {:?}", pending);
hal::memory::Barrier::Image {
states: pending.to_states(),
target: &texture.raw,
families: None,
range: pending.selector,
}
}));
hal::image::Layout::DepthStencilAttachmentOptimal
}
};
hal::pass::Attachment {
format: Some(conv::map_texture_format(view.format, device.features)),
samples: view.samples,
ops: conv::map_load_store_ops(at.depth_load_op, at.depth_store_op),
stencil_ops: conv::map_load_store_ops(at.stencil_load_op, at.stencil_store_op),
layouts: old_layout .. hal::image::Layout::DepthStencilAttachmentOptimal,
}
});
let mut colors = ArrayVec::new();
let mut resolves = ArrayVec::new();
for at in color_attachments {
let view = &view_guard[at.attachment];
if let Some(ex) = extent {
assert_eq!(ex, view.extent);
} else {
extent = Some(view.extent);
}
assert_eq!(
view.samples, sample_count,
"All attachments must have the same sample_count"
);
let first_use =
trackers
.views
.init(at.attachment, &view.life_guard.ref_count, (), ());
let layouts = match view.inner {
TextureViewInner::Native { ref source_id, .. } => {
let texture = &texture_guard[source_id.value];
assert!(texture.usage.contains(TextureUsage::OUTPUT_ATTACHMENT));
let old_layout =
match trackers.textures.query(source_id.value, view.range.clone()) {
Some(usage) => {
conv::map_texture_state(usage, hal::format::Aspects::COLOR).1
}
None => {
// Required sub-resources have inconsistent states, we need to
// issue individual barriers instead of relying on the render pass.
let pending = trackers.textures.change_replace(
source_id.value,
&texture.life_guard.ref_count,
view.range.clone(),
TextureUsage::OUTPUT_ATTACHMENT,
);
barriers.extend(pending.map(|pending| {
log::trace!("\tcolor {:?}", pending);
hal::memory::Barrier::Image {
states: pending.to_states(),
target: &texture.raw,
families: None,
range: pending.selector,
}
}));
hal::image::Layout::ColorAttachmentOptimal
}
};
old_layout .. hal::image::Layout::ColorAttachmentOptimal
}
TextureViewInner::SwapChain { .. } => {
if let Some((ref view_id, _)) = cmb.used_swap_chain {
assert_eq!(view_id.value, at.attachment);
} else {
assert!(used_swap_chain_image.is_none());
used_swap_chain_image = Some(Stored {
value: at.attachment,
ref_count: view.life_guard.ref_count.clone(),
});
}
let end = hal::image::Layout::Present;
let start = if first_use {
hal::image::Layout::Undefined
} else {
end
};
start .. end
}
};
colors.push(hal::pass::Attachment {
format: Some(conv::map_texture_format(view.format, device.features)),
samples: view.samples,
ops: conv::map_load_store_ops(at.load_op, at.store_op),
stencil_ops: hal::pass::AttachmentOps::DONT_CARE,
layouts,
});
}
for &resolve_target in color_attachments
.iter()
.flat_map(|at| unsafe { at.resolve_target.as_ref() })
{
let view = &view_guard[resolve_target];
assert_eq!(extent, Some(view.extent));
assert_eq!(
view.samples, 1,
"All resolve_targets must have a sample_count of 1"
);
let first_use =
trackers
.views
.init(resolve_target, &view.life_guard.ref_count, (), ());
let layouts = match view.inner {
TextureViewInner::Native { ref source_id, .. } => {
let texture = &texture_guard[source_id.value];
assert!(texture.usage.contains(TextureUsage::OUTPUT_ATTACHMENT));
let old_layout =
match trackers.textures.query(source_id.value, view.range.clone()) {
Some(usage) => {
conv::map_texture_state(usage, hal::format::Aspects::COLOR).1
}
None => {
// Required sub-resources have inconsistent states, we need to
// issue individual barriers instead of relying on the render pass.
let pending = trackers.textures.change_replace(
source_id.value,
&texture.life_guard.ref_count,
view.range.clone(),
TextureUsage::OUTPUT_ATTACHMENT,
);
barriers.extend(pending.map(|pending| {
log::trace!("\tresolve {:?}", pending);
hal::memory::Barrier::Image {
states: pending.to_states(),
target: &texture.raw,
families: None,
range: pending.selector,
}
}));
hal::image::Layout::ColorAttachmentOptimal
}
};
old_layout .. hal::image::Layout::ColorAttachmentOptimal
}
TextureViewInner::SwapChain { .. } => {
if let Some((ref view_id, _)) = cmb.used_swap_chain {
assert_eq!(view_id.value, resolve_target);
} else {
assert!(used_swap_chain_image.is_none());
used_swap_chain_image = Some(Stored {
value: resolve_target,
ref_count: view.life_guard.ref_count.clone(),
});
}
let end = hal::image::Layout::Present;
let start = if first_use {
hal::image::Layout::Undefined
} else {
end
};
start .. end
}
};
resolves.push(hal::pass::Attachment {
format: Some(conv::map_texture_format(view.format, device.features)),
samples: view.samples,
ops: hal::pass::AttachmentOps::new(
hal::pass::AttachmentLoadOp::DontCare,
hal::pass::AttachmentStoreOp::Store,
),
stencil_ops: hal::pass::AttachmentOps::DONT_CARE,
layouts,
});
}
RenderPassKey {
colors,
resolves,
depth_stencil,
}
};
if !barriers.is_empty() {
unsafe {
current_comb.pipeline_barrier(
all_image_stages() .. all_image_stages(),
hal::memory::Dependencies::empty(),
barriers,
);
}
}
let mut render_pass_cache = device.render_passes.lock();
let render_pass = match render_pass_cache.entry(rp_key.clone()) {
Entry::Occupied(e) => e.into_mut(),
Entry::Vacant(e) => {
let color_ids = [
(0, hal::image::Layout::ColorAttachmentOptimal),
(1, hal::image::Layout::ColorAttachmentOptimal),
(2, hal::image::Layout::ColorAttachmentOptimal),
(3, hal::image::Layout::ColorAttachmentOptimal),
];
let mut resolve_ids = ArrayVec::<[_; crate::device::MAX_COLOR_TARGETS]>::new();
let mut attachment_index = color_attachments.len();
if color_attachments
.iter()
.any(|at| at.resolve_target != ptr::null())
{
for (i, at) in color_attachments.iter().enumerate() {
if at.resolve_target == ptr::null() {
resolve_ids.push((
hal::pass::ATTACHMENT_UNUSED,
hal::image::Layout::ColorAttachmentOptimal,
));
} else {
let sample_count_check =
view_guard[color_attachments[i].attachment].samples;
assert!(sample_count_check > 1, "RenderPassColorAttachmentDescriptor with a resolve_target must have an attachment with sample_count > 1");
resolve_ids.push((
attachment_index,
hal::image::Layout::ColorAttachmentOptimal,
));
attachment_index += 1;
}
}
}
let depth_id = (
attachment_index,
hal::image::Layout::DepthStencilAttachmentOptimal,
);
let subpass = hal::pass::SubpassDesc {
colors: &color_ids[.. color_attachments.len()],
resolves: &resolve_ids,
depth_stencil: depth_stencil_attachment.map(|_| &depth_id),
inputs: &[],
preserves: &[],
};
let pass = unsafe {
device
.raw
.create_render_pass(e.key().all(), &[subpass], &[])
}
.unwrap();
e.insert(pass)
}
};
let mut framebuffer_cache;
let fb_key = FramebufferKey {
colors: color_attachments.iter().map(|at| at.attachment).collect(),
resolves: color_attachments
.iter()
.filter_map(|at| unsafe { at.resolve_target.as_ref() }.cloned())
.collect(),
depth_stencil: depth_stencil_attachment.map(|at| at.attachment),
};
let framebuffer = match used_swap_chain_image.take() {
Some(view_id) => {
assert!(cmb.used_swap_chain.is_none());
// Always create a new framebuffer and delete it after presentation.
let attachments = fb_key.all().map(|&id| match view_guard[id].inner {
TextureViewInner::Native { ref raw, .. } => raw,
TextureViewInner::SwapChain { ref image, .. } => Borrow::borrow(image),
});
let framebuffer = unsafe {
device
.raw
.create_framebuffer(&render_pass, attachments, extent.unwrap())
.unwrap()
};
cmb.used_swap_chain = Some((view_id, framebuffer));
&mut cmb.used_swap_chain.as_mut().unwrap().1
}
None => {
// Cache framebuffers by the device.
framebuffer_cache = device.framebuffers.lock();
match framebuffer_cache.entry(fb_key) {
Entry::Occupied(e) => e.into_mut(),
Entry::Vacant(e) => {
let fb = {
let attachments = e.key().all().map(|&id| match view_guard[id].inner {
TextureViewInner::Native { ref raw, .. } => raw,
TextureViewInner::SwapChain { ref image, .. } => {
Borrow::borrow(image)
}
});
unsafe {
device.raw.create_framebuffer(
&render_pass,
attachments,
extent.unwrap(),
)
}
.unwrap()
};
e.insert(fb)
}
}
}
};
let rect = {
let ex = extent.unwrap();
hal::pso::Rect {
x: 0,
y: 0,
w: ex.width as _,
h: ex.height as _,
}
};
let clear_values = color_attachments
.iter()
.zip(&rp_key.colors)
.flat_map(|(at, key)| {
match at.load_op {
LoadOp::Load => None,
LoadOp::Clear => {
use hal::format::ChannelType;
//TODO: validate sign/unsign and normalized ranges of the color values
let value = match key.format.unwrap().base_format().1 {
ChannelType::Unorm
| ChannelType::Snorm
| ChannelType::Ufloat
| ChannelType::Sfloat
| ChannelType::Uscaled
| ChannelType::Sscaled
| ChannelType::Srgb => hal::command::ClearColor {
float32: conv::map_color_f32(&at.clear_color),
},
ChannelType::Sint => hal::command::ClearColor {
sint32: conv::map_color_i32(&at.clear_color),
},
ChannelType::Uint => hal::command::ClearColor {
uint32: conv::map_color_u32(&at.clear_color),
},
};
Some(hal::command::ClearValue { color: value })
}
}
})
.chain(depth_stencil_attachment.and_then(|at| {
match (at.depth_load_op, at.stencil_load_op) {
(LoadOp::Load, LoadOp::Load) => None,
(LoadOp::Clear, _) | (_, LoadOp::Clear) => {
let value = hal::command::ClearDepthStencil {
depth: at.clear_depth,
stencil: at.clear_stencil,
};
Some(hal::command::ClearValue {
depth_stencil: value,
})
}
}
}));
unsafe {
current_comb.begin_render_pass(
render_pass,
framebuffer,
rect,
clear_values,
hal::command::SubpassContents::Inline,
);
current_comb.set_scissors(0, iter::once(&rect));
current_comb.set_viewports(
0,
iter::once(hal::pso::Viewport {
rect,
depth: 0.0 .. 1.0,
}),
);
}
let context = RenderPassContext {
colors: color_attachments
.iter()
.map(|at| view_guard[at.attachment].format)
.collect(),
resolves: color_attachments
.iter()
.filter_map(|at| unsafe { at.resolve_target.as_ref() })
.map(|resolve| view_guard[*resolve].format)
.collect(),
depth_stencil: depth_stencil_attachment.map(|at| view_guard[at.attachment].format),
};
RenderPass::new(
current_comb,
Stored {
value: encoder_id,
ref_count: cmb.life_guard.ref_count.clone(),
},
context,
sample_count,
cmb.features.max_bind_groups,
)
};
hub.render_passes.register_identity(id_in, pass, &mut token)
}
#[cfg(feature = "local")]
#[no_mangle]
pub extern "C" fn wgpu_command_encoder_begin_render_pass(
encoder_id: CommandEncoderId,
desc: &RenderPassDescriptor,
) -> RenderPassId {
gfx_select!(encoder_id => command_encoder_begin_render_pass(&*GLOBAL, encoder_id, desc, PhantomData))
}
pub fn command_encoder_begin_compute_pass<B: GfxBackend>(
global: &Global,
encoder_id: CommandEncoderId,
_desc: &ComputePassDescriptor,
id_in: Input<ComputePassId>,
) -> Output<ComputePassId> {
let hub = B::hub(global);
let mut token = Token::root();
let (mut cmb_guard, mut token) = hub.command_buffers.write(&mut token);
let cmb = &mut cmb_guard[encoder_id];
let raw = cmb.raw.pop().unwrap();
let trackers = mem::replace(&mut cmb.trackers, TrackerSet::new(encoder_id.backend()));
let stored = Stored {
value: encoder_id,
ref_count: cmb.life_guard.ref_count.clone(),
};
let pass = ComputePass::new(raw, stored, trackers, cmb.features.max_bind_groups);
hub.compute_passes
.register_identity(id_in, pass, &mut token)
}
#[cfg(feature = "local")]
#[no_mangle]
pub extern "C" fn wgpu_command_encoder_begin_compute_pass(
encoder_id: CommandEncoderId,
desc: Option<&ComputePassDescriptor>,
) -> ComputePassId {
let desc = &desc.cloned().unwrap_or_default();
gfx_select!(encoder_id => command_encoder_begin_compute_pass(&*GLOBAL, encoder_id, desc, PhantomData))
}

View File

@ -1,848 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use crate::{
command::bind::{Binder, LayoutChange},
conv,
device::{RenderPassContext, BIND_BUFFER_ALIGNMENT, MAX_VERTEX_BUFFERS},
hub::{GfxBackend, Global, Token},
pipeline::{IndexFormat, InputStepMode, PipelineFlags},
resource::BufferUsage,
track::{Stitch, TrackerSet},
BindGroupId,
BufferAddress,
BufferId,
Color,
CommandBuffer,
CommandBufferId,
RenderPassId,
RenderPipelineId,
Stored,
};
#[cfg(feature = "local")]
use crate::{gfx_select, hub::GLOBAL, RawString, RenderBundleId};
use hal::command::CommandBuffer as _;
#[cfg(feature = "local")]
use std::slice;
use std::{iter, ops::Range};
#[derive(Debug, PartialEq)]
enum OptionalState {
Unused,
Required,
Set,
}
impl OptionalState {
fn require(&mut self, require: bool) {
if require && *self == OptionalState::Unused {
*self = OptionalState::Required;
}
}
}
#[derive(Debug, PartialEq)]
enum DrawError {
MissingBlendColor,
MissingStencilReference,
IncompatibleBindGroup {
index: u32,
//expected: BindGroupLayoutId,
//provided: Option<(BindGroupLayoutId, BindGroupId)>,
},
}
#[derive(Debug)]
pub struct IndexState {
bound_buffer_view: Option<(BufferId, Range<BufferAddress>)>,
format: IndexFormat,
limit: u32,
}
impl IndexState {
fn update_limit(&mut self) {
self.limit = match self.bound_buffer_view {
Some((_, ref range)) => {
let shift = match self.format {
IndexFormat::Uint16 => 1,
IndexFormat::Uint32 => 2,
};
((range.end - range.start) >> shift) as u32
}
None => 0,
}
}
}
#[derive(Clone, Copy, Debug)]
pub struct VertexBufferState {
total_size: BufferAddress,
stride: BufferAddress,
rate: InputStepMode,
}
impl VertexBufferState {
const EMPTY: Self = VertexBufferState {
total_size: 0,
stride: 0,
rate: InputStepMode::Vertex,
};
}
#[derive(Debug)]
pub struct VertexState {
inputs: [VertexBufferState; MAX_VERTEX_BUFFERS],
vertex_limit: u32,
instance_limit: u32,
}
impl VertexState {
fn update_limits(&mut self) {
self.vertex_limit = !0;
self.instance_limit = !0;
for vbs in &self.inputs {
if vbs.stride == 0 {
continue;
}
let limit = (vbs.total_size / vbs.stride) as u32;
match vbs.rate {
InputStepMode::Vertex => self.vertex_limit = self.vertex_limit.min(limit),
InputStepMode::Instance => self.instance_limit = self.instance_limit.min(limit),
}
}
}
}
#[derive(Debug)]
pub struct RenderPass<B: hal::Backend> {
raw: B::CommandBuffer,
cmb_id: Stored<CommandBufferId>,
context: RenderPassContext,
binder: Binder,
trackers: TrackerSet,
blend_color_status: OptionalState,
stencil_reference_status: OptionalState,
index_state: IndexState,
vertex_state: VertexState,
sample_count: u8,
}
impl<B: GfxBackend> RenderPass<B> {
pub(crate) fn new(
raw: B::CommandBuffer,
cmb_id: Stored<CommandBufferId>,
context: RenderPassContext,
sample_count: u8,
max_bind_groups: u32,
) -> Self {
RenderPass {
raw,
cmb_id,
context,
binder: Binder::new(max_bind_groups),
trackers: TrackerSet::new(B::VARIANT),
blend_color_status: OptionalState::Unused,
stencil_reference_status: OptionalState::Unused,
index_state: IndexState {
bound_buffer_view: None,
format: IndexFormat::Uint16,
limit: 0,
},
vertex_state: VertexState {
inputs: [VertexBufferState::EMPTY; MAX_VERTEX_BUFFERS],
vertex_limit: 0,
instance_limit: 0,
},
sample_count,
}
}
fn is_ready(&self) -> Result<(), DrawError> {
//TODO: vertex buffers
let bind_mask = self.binder.invalid_mask();
if bind_mask != 0 {
//let (expected, provided) = self.binder.entries[index as usize].info();
return Err(DrawError::IncompatibleBindGroup {
index: bind_mask.trailing_zeros() as u32,
});
}
if self.blend_color_status == OptionalState::Required {
return Err(DrawError::MissingBlendColor);
}
if self.stencil_reference_status == OptionalState::Required {
return Err(DrawError::MissingStencilReference);
}
Ok(())
}
}
// Common routines between render/compute
pub fn render_pass_end_pass<B: GfxBackend>(global: &Global, pass_id: RenderPassId) {
let hub = B::hub(global);
let mut token = Token::root();
let (mut cmb_guard, mut token) = hub.command_buffers.write(&mut token);
let (mut pass, mut token) = hub.render_passes.unregister(pass_id, &mut token);
unsafe {
pass.raw.end_render_pass();
}
pass.trackers.optimize();
let cmb = &mut cmb_guard[pass.cmb_id.value];
let (buffer_guard, mut token) = hub.buffers.read(&mut token);
let (texture_guard, _) = hub.textures.read(&mut token);
match cmb.raw.last_mut() {
Some(last) => {
log::trace!("Encoding barriers before pass {:?}", pass_id);
CommandBuffer::insert_barriers(
last,
&mut cmb.trackers,
&pass.trackers,
Stitch::Last,
&*buffer_guard,
&*texture_guard,
);
unsafe { last.finish() };
}
None => {
cmb.trackers.merge_extend(&pass.trackers);
}
}
cmb.raw.push(pass.raw);
}
#[cfg(feature = "local")]
#[no_mangle]
pub extern "C" fn wgpu_render_pass_end_pass(pass_id: RenderPassId) {
gfx_select!(pass_id => render_pass_end_pass(&*GLOBAL, pass_id))
}
pub fn render_pass_set_bind_group<B: GfxBackend>(
global: &Global,
pass_id: RenderPassId,
index: u32,
bind_group_id: BindGroupId,
offsets: &[BufferAddress],
) {
let hub = B::hub(global);
let mut token = Token::root();
let (pipeline_layout_guard, mut token) = hub.pipeline_layouts.read(&mut token);
let (bind_group_guard, mut token) = hub.bind_groups.read(&mut token);
let (mut pass_guard, _) = hub.render_passes.write(&mut token);
let pass = &mut pass_guard[pass_id];
let bind_group = pass
.trackers
.bind_groups
.use_extend(&*bind_group_guard, bind_group_id, (), ())
.unwrap();
assert_eq!(bind_group.dynamic_count, offsets.len());
if cfg!(debug_assertions) {
for off in offsets {
assert_eq!(
*off % BIND_BUFFER_ALIGNMENT,
0,
"Misaligned dynamic buffer offset: {} does not align with {}",
off,
BIND_BUFFER_ALIGNMENT
);
}
}
pass.trackers.merge_extend(&bind_group.used);
if let Some((pipeline_layout_id, follow_up_sets, follow_up_offsets)) = pass
.binder
.provide_entry(index as usize, bind_group_id, bind_group, offsets)
{
let bind_groups = iter::once(bind_group.raw.raw())
.chain(follow_up_sets.map(|bg_id| bind_group_guard[bg_id].raw.raw()));
unsafe {
pass.raw.bind_graphics_descriptor_sets(
&&pipeline_layout_guard[pipeline_layout_id].raw,
index as usize,
bind_groups,
offsets
.iter()
.chain(follow_up_offsets)
.map(|&off| off as hal::command::DescriptorSetOffset),
);
}
};
}
#[cfg(feature = "local")]
#[no_mangle]
pub extern "C" fn wgpu_render_pass_set_bind_group(
pass_id: RenderPassId,
index: u32,
bind_group_id: BindGroupId,
offsets: *const BufferAddress,
offsets_length: usize,
) {
let offsets = if offsets_length != 0 {
unsafe { slice::from_raw_parts(offsets, offsets_length) }
} else {
&[]
};
gfx_select!(pass_id => render_pass_set_bind_group(&*GLOBAL, pass_id, index, bind_group_id, offsets))
}
#[cfg(feature = "local")]
#[no_mangle]
pub extern "C" fn wgpu_render_pass_push_debug_group(_pass_id: RenderPassId, _label: RawString) {
//TODO
}
#[cfg(feature = "local")]
#[no_mangle]
pub extern "C" fn wgpu_render_pass_pop_debug_group(_pass_id: RenderPassId) {
//TODO
}
#[cfg(feature = "local")]
#[no_mangle]
pub extern "C" fn wgpu_render_pass_insert_debug_marker(_pass_id: RenderPassId, _label: RawString) {
//TODO
}
// Render-specific routines
pub fn render_pass_set_index_buffer<B: GfxBackend>(
global: &Global,
pass_id: RenderPassId,
buffer_id: BufferId,
offset: BufferAddress,
) {
let hub = B::hub(global);
let mut token = Token::root();
let (mut pass_guard, mut token) = hub.render_passes.write(&mut token);
let (buffer_guard, _) = hub.buffers.read(&mut token);
let pass = &mut pass_guard[pass_id];
let buffer = pass
.trackers
.buffers
.use_extend(&*buffer_guard, buffer_id, (), BufferUsage::INDEX)
.unwrap();
assert!(buffer.usage.contains(BufferUsage::INDEX));
let range = offset .. buffer.size;
pass.index_state.bound_buffer_view = Some((buffer_id, range));
pass.index_state.update_limit();
let view = hal::buffer::IndexBufferView {
buffer: &buffer.raw,
offset,
index_type: conv::map_index_format(pass.index_state.format),
};
unsafe {
pass.raw.bind_index_buffer(view);
}
}
#[cfg(feature = "local")]
#[no_mangle]
pub extern "C" fn wgpu_render_pass_set_index_buffer(
pass_id: RenderPassId,
buffer_id: BufferId,
offset: BufferAddress,
) {
gfx_select!(pass_id => render_pass_set_index_buffer(&*GLOBAL, pass_id, buffer_id, offset))
}
pub fn render_pass_set_vertex_buffers<B: GfxBackend>(
global: &Global,
pass_id: RenderPassId,
start_slot: u32,
buffers: &[BufferId],
offsets: &[BufferAddress],
) {
let hub = B::hub(global);
let mut token = Token::root();
assert_eq!(buffers.len(), offsets.len());
let (mut pass_guard, mut token) = hub.render_passes.write(&mut token);
let (buffer_guard, _) = hub.buffers.read(&mut token);
let pass = &mut pass_guard[pass_id];
for (vbs, (&id, &offset)) in pass.vertex_state.inputs[start_slot as usize ..]
.iter_mut()
.zip(buffers.iter().zip(offsets))
{
let buffer = pass
.trackers
.buffers
.use_extend(&*buffer_guard, id, (), BufferUsage::VERTEX)
.unwrap();
assert!(buffer.usage.contains(BufferUsage::VERTEX));
vbs.total_size = buffer.size - offset;
}
pass.vertex_state.update_limits();
let buffers = buffers
.iter()
.map(|&id| &buffer_guard[id].raw)
.zip(offsets.iter().cloned());
unsafe {
pass.raw.bind_vertex_buffers(start_slot, buffers);
}
}
#[cfg(feature = "local")]
#[no_mangle]
pub extern "C" fn wgpu_render_pass_set_vertex_buffers(
pass_id: RenderPassId,
start_slot: u32,
buffers: *const BufferId,
offsets: *const BufferAddress,
length: usize,
) {
let buffers = unsafe { slice::from_raw_parts(buffers, length) };
let offsets = unsafe { slice::from_raw_parts(offsets, length) };
gfx_select!(pass_id => render_pass_set_vertex_buffers(&*GLOBAL, pass_id, start_slot, buffers, offsets))
}
pub fn render_pass_draw<B: GfxBackend>(
global: &Global,
pass_id: RenderPassId,
vertex_count: u32,
instance_count: u32,
first_vertex: u32,
first_instance: u32,
) {
let hub = B::hub(global);
let mut token = Token::root();
let (mut pass_guard, _) = hub.render_passes.write(&mut token);
let pass = &mut pass_guard[pass_id];
pass.is_ready().unwrap();
assert!(
first_vertex + vertex_count <= pass.vertex_state.vertex_limit,
"Vertex out of range!"
);
assert!(
first_instance + instance_count <= pass.vertex_state.instance_limit,
"Instance out of range!"
);
unsafe {
pass.raw.draw(
first_vertex .. first_vertex + vertex_count,
first_instance .. first_instance + instance_count,
);
}
}
#[cfg(feature = "local")]
#[no_mangle]
pub extern "C" fn wgpu_render_pass_draw(
pass_id: RenderPassId,
vertex_count: u32,
instance_count: u32,
first_vertex: u32,
first_instance: u32,
) {
gfx_select!(pass_id => render_pass_draw(&*GLOBAL, pass_id, vertex_count, instance_count, first_vertex, first_instance))
}
pub fn render_pass_draw_indirect<B: GfxBackend>(
global: &Global,
pass_id: RenderPassId,
indirect_buffer_id: BufferId,
indirect_offset: BufferAddress,
) {
let hub = B::hub(global);
let mut token = Token::root();
let (mut pass_guard, _) = hub.render_passes.write(&mut token);
let (buffer_guard, _) = hub.buffers.read(&mut token);
let pass = &mut pass_guard[pass_id];
pass.is_ready().unwrap();
let buffer = pass
.trackers
.buffers
.use_extend(
&*buffer_guard,
indirect_buffer_id,
(),
BufferUsage::INDIRECT,
)
.unwrap();
assert!(buffer.usage.contains(BufferUsage::INDIRECT));
unsafe {
pass.raw.draw_indirect(&buffer.raw, indirect_offset, 1, 0);
}
}
#[cfg(feature = "local")]
#[no_mangle]
pub extern "C" fn wgpu_render_pass_draw_indirect(
pass_id: RenderPassId,
indirect_buffer_id: BufferId,
indirect_offset: BufferAddress,
) {
gfx_select!(pass_id => render_pass_draw_indirect(&*GLOBAL, pass_id, indirect_buffer_id, indirect_offset))
}
pub fn render_pass_draw_indexed<B: GfxBackend>(
global: &Global,
pass_id: RenderPassId,
index_count: u32,
instance_count: u32,
first_index: u32,
base_vertex: i32,
first_instance: u32,
) {
let hub = B::hub(global);
let mut token = Token::root();
let (mut pass_guard, _) = hub.render_passes.write(&mut token);
let pass = &mut pass_guard[pass_id];
pass.is_ready().unwrap();
//TODO: validate that base_vertex + max_index() is within the provided range
assert!(
first_index + index_count <= pass.index_state.limit,
"Index out of range!"
);
assert!(
first_instance + instance_count <= pass.vertex_state.instance_limit,
"Instance out of range!"
);
unsafe {
pass.raw.draw_indexed(
first_index .. first_index + index_count,
base_vertex,
first_instance .. first_instance + instance_count,
);
}
}
#[cfg(feature = "local")]
#[no_mangle]
pub extern "C" fn wgpu_render_pass_draw_indexed(
pass_id: RenderPassId,
index_count: u32,
instance_count: u32,
first_index: u32,
base_vertex: i32,
first_instance: u32,
) {
gfx_select!(pass_id => render_pass_draw_indexed(&*GLOBAL, pass_id, index_count, instance_count, first_index, base_vertex, first_instance))
}
pub fn render_pass_draw_indexed_indirect<B: GfxBackend>(
global: &Global,
pass_id: RenderPassId,
indirect_buffer_id: BufferId,
indirect_offset: BufferAddress,
) {
let hub = B::hub(global);
let mut token = Token::root();
let (mut pass_guard, _) = hub.render_passes.write(&mut token);
let (buffer_guard, _) = hub.buffers.read(&mut token);
let pass = &mut pass_guard[pass_id];
pass.is_ready().unwrap();
let buffer = pass
.trackers
.buffers
.use_extend(
&*buffer_guard,
indirect_buffer_id,
(),
BufferUsage::INDIRECT,
)
.unwrap();
assert!(buffer.usage.contains(BufferUsage::INDIRECT));
unsafe {
pass.raw
.draw_indexed_indirect(&buffer.raw, indirect_offset, 1, 0);
}
}
#[cfg(feature = "local")]
#[no_mangle]
pub extern "C" fn wgpu_render_pass_draw_indexed_indirect(
pass_id: RenderPassId,
indirect_buffer_id: BufferId,
indirect_offset: BufferAddress,
) {
gfx_select!(pass_id => render_pass_draw_indexed_indirect(&*GLOBAL, pass_id, indirect_buffer_id, indirect_offset))
}
pub fn render_pass_set_pipeline<B: GfxBackend>(
global: &Global,
pass_id: RenderPassId,
pipeline_id: RenderPipelineId,
) {
let hub = B::hub(global);
let mut token = Token::root();
let (pipeline_layout_guard, mut token) = hub.pipeline_layouts.read(&mut token);
let (bind_group_guard, mut token) = hub.bind_groups.read(&mut token);
let (mut pass_guard, mut token) = hub.render_passes.write(&mut token);
let pass = &mut pass_guard[pass_id];
let (pipeline_guard, mut token) = hub.render_pipelines.read(&mut token);
let pipeline = &pipeline_guard[pipeline_id];
assert!(
pass.context.compatible(&pipeline.pass_context),
"The render pipeline is not compatible with the pass!"
);
assert_eq!(
pipeline.sample_count, pass.sample_count,
"The render pipeline and renderpass have mismatching sample_count"
);
pass.blend_color_status
.require(pipeline.flags.contains(PipelineFlags::BLEND_COLOR));
pass.stencil_reference_status
.require(pipeline.flags.contains(PipelineFlags::STENCIL_REFERENCE));
unsafe {
pass.raw.bind_graphics_pipeline(&pipeline.raw);
}
// Rebind resource
if pass.binder.pipeline_layout_id != Some(pipeline.layout_id.clone()) {
let pipeline_layout = &pipeline_layout_guard[pipeline.layout_id];
pass.binder.pipeline_layout_id = Some(pipeline.layout_id.clone());
pass.binder
.reset_expectations(pipeline_layout.bind_group_layout_ids.len());
let mut is_compatible = true;
for (index, (entry, &bgl_id)) in pass
.binder
.entries
.iter_mut()
.zip(&pipeline_layout.bind_group_layout_ids)
.enumerate()
{
match entry.expect_layout(bgl_id) {
LayoutChange::Match(bg_id, offsets) if is_compatible => {
let desc_set = bind_group_guard[bg_id].raw.raw();
unsafe {
pass.raw.bind_graphics_descriptor_sets(
&pipeline_layout.raw,
index,
iter::once(desc_set),
offsets.iter().map(|offset| *offset as u32),
);
}
}
LayoutChange::Match(..) | LayoutChange::Unchanged => {}
LayoutChange::Mismatch => {
is_compatible = false;
}
}
}
}
// Rebind index buffer if the index format has changed with the pipeline switch
if pass.index_state.format != pipeline.index_format {
pass.index_state.format = pipeline.index_format;
pass.index_state.update_limit();
if let Some((buffer_id, ref range)) = pass.index_state.bound_buffer_view {
let (buffer_guard, _) = hub.buffers.read(&mut token);
let buffer = pass
.trackers
.buffers
.use_extend(&*buffer_guard, buffer_id, (), BufferUsage::INDEX)
.unwrap();
let view = hal::buffer::IndexBufferView {
buffer: &buffer.raw,
offset: range.start,
index_type: conv::map_index_format(pass.index_state.format),
};
unsafe {
pass.raw.bind_index_buffer(view);
}
}
}
// Update vertex buffer limits
for (vbs, &(stride, rate)) in pass
.vertex_state
.inputs
.iter_mut()
.zip(&pipeline.vertex_strides)
{
vbs.stride = stride;
vbs.rate = rate;
}
for vbs in pass.vertex_state.inputs[pipeline.vertex_strides.len() ..].iter_mut() {
vbs.stride = 0;
vbs.rate = InputStepMode::Vertex;
}
pass.vertex_state.update_limits();
}
#[cfg(feature = "local")]
#[no_mangle]
pub extern "C" fn wgpu_render_pass_set_pipeline(
pass_id: RenderPassId,
pipeline_id: RenderPipelineId,
) {
gfx_select!(pass_id => render_pass_set_pipeline(&*GLOBAL, pass_id, pipeline_id))
}
pub fn render_pass_set_blend_color<B: GfxBackend>(
global: &Global,
pass_id: RenderPassId,
color: &Color,
) {
let hub = B::hub(global);
let mut token = Token::root();
let (mut pass_guard, _) = hub.render_passes.write(&mut token);
let pass = &mut pass_guard[pass_id];
pass.blend_color_status = OptionalState::Set;
unsafe {
pass.raw.set_blend_constants(conv::map_color_f32(color));
}
}
#[cfg(feature = "local")]
#[no_mangle]
pub extern "C" fn wgpu_render_pass_set_blend_color(pass_id: RenderPassId, color: &Color) {
gfx_select!(pass_id => render_pass_set_blend_color(&*GLOBAL, pass_id, color))
}
pub fn render_pass_set_stencil_reference<B: GfxBackend>(
global: &Global,
pass_id: RenderPassId,
value: u32,
) {
let hub = B::hub(global);
let mut token = Token::root();
let (mut pass_guard, _) = hub.render_passes.write(&mut token);
let pass = &mut pass_guard[pass_id];
pass.stencil_reference_status = OptionalState::Set;
unsafe {
pass.raw.set_stencil_reference(hal::pso::Face::all(), value);
}
}
#[cfg(feature = "local")]
#[no_mangle]
pub extern "C" fn wgpu_render_pass_set_stencil_reference(pass_id: RenderPassId, value: u32) {
gfx_select!(pass_id => render_pass_set_stencil_reference(&*GLOBAL, pass_id, value))
}
pub fn render_pass_set_viewport<B: GfxBackend>(
global: &Global,
pass_id: RenderPassId,
x: f32,
y: f32,
w: f32,
h: f32,
min_depth: f32,
max_depth: f32,
) {
let hub = B::hub(global);
let mut token = Token::root();
let (mut pass_guard, _) = hub.render_passes.write(&mut token);
let pass = &mut pass_guard[pass_id];
unsafe {
use std::convert::TryFrom;
use std::i16;
pass.raw.set_viewports(
0,
&[hal::pso::Viewport {
rect: hal::pso::Rect {
x: i16::try_from(x.round() as i64).unwrap_or(0),
y: i16::try_from(y.round() as i64).unwrap_or(0),
w: i16::try_from(w.round() as i64).unwrap_or(i16::MAX),
h: i16::try_from(h.round() as i64).unwrap_or(i16::MAX),
},
depth: min_depth .. max_depth,
}],
);
}
}
#[cfg(feature = "local")]
#[no_mangle]
pub extern "C" fn wgpu_render_pass_set_viewport(
pass_id: RenderPassId,
x: f32,
y: f32,
w: f32,
h: f32,
min_depth: f32,
max_depth: f32,
) {
gfx_select!(pass_id => render_pass_set_viewport(&*GLOBAL, pass_id, x, y, w, h, min_depth, max_depth))
}
pub fn render_pass_set_scissor_rect<B: GfxBackend>(
global: &Global,
pass_id: RenderPassId,
x: u32,
y: u32,
w: u32,
h: u32,
) {
let hub = B::hub(global);
let mut token = Token::root();
let (mut pass_guard, _) = hub.render_passes.write(&mut token);
let pass = &mut pass_guard[pass_id];
unsafe {
use std::convert::TryFrom;
use std::i16;
pass.raw.set_scissors(
0,
&[hal::pso::Rect {
x: i16::try_from(x).unwrap_or(0),
y: i16::try_from(y).unwrap_or(0),
w: i16::try_from(w).unwrap_or(i16::MAX),
h: i16::try_from(h).unwrap_or(i16::MAX),
}],
);
}
}
#[cfg(feature = "local")]
#[no_mangle]
pub extern "C" fn wgpu_render_pass_set_scissor_rect(
pass_id: RenderPassId,
x: u32,
y: u32,
w: u32,
h: u32,
) {
gfx_select!(pass_id => render_pass_set_scissor_rect(&*GLOBAL, pass_id, x, y, w, h))
}
#[cfg(feature = "local")]
#[no_mangle]
pub extern "C" fn wgpu_render_pass_execute_bundles(
_pass_id: RenderPassId,
_bundles: *const RenderBundleId,
_bundles_length: usize,
) {
unimplemented!()
}

View File

@ -1,421 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use crate::{
conv,
device::{all_buffer_stages, all_image_stages},
hub::{GfxBackend, Global, Token},
BufferAddress,
BufferId,
BufferUsage,
CommandEncoderId,
Extent3d,
Origin3d,
TextureId,
TextureUsage,
};
#[cfg(feature = "local")]
use crate::{gfx_select, hub::GLOBAL};
use hal::command::CommandBuffer as _;
use std::iter;
const BITS_PER_BYTE: u32 = 8;
#[repr(C)]
#[derive(Debug)]
pub struct BufferCopyView {
pub buffer: BufferId,
pub offset: BufferAddress,
pub row_pitch: u32,
pub image_height: u32,
}
#[repr(C)]
#[derive(Debug)]
pub struct TextureCopyView {
pub texture: TextureId,
pub mip_level: u32,
pub array_layer: u32,
pub origin: Origin3d,
}
impl TextureCopyView {
//TODO: we currently access each texture twice for a transfer,
// once only to get the aspect flags, which is unfortunate.
fn to_selector(&self, aspects: hal::format::Aspects) -> hal::image::SubresourceRange {
let level = self.mip_level as hal::image::Level;
let layer = self.array_layer as hal::image::Layer;
hal::image::SubresourceRange {
aspects,
levels: level .. level + 1,
layers: layer .. layer + 1,
}
}
fn to_sub_layers(&self, aspects: hal::format::Aspects) -> hal::image::SubresourceLayers {
let layer = self.array_layer as hal::image::Layer;
hal::image::SubresourceLayers {
aspects,
level: self.mip_level as hal::image::Level,
layers: layer .. layer + 1,
}
}
}
pub fn command_encoder_copy_buffer_to_buffer<B: GfxBackend>(
global: &Global,
command_encoder_id: CommandEncoderId,
source: BufferId,
source_offset: BufferAddress,
destination: BufferId,
destination_offset: BufferAddress,
size: BufferAddress,
) {
let hub = B::hub(global);
let mut token = Token::root();
let (mut cmb_guard, mut token) = hub.command_buffers.write(&mut token);
let cmb = &mut cmb_guard[command_encoder_id];
let (buffer_guard, _) = hub.buffers.read(&mut token);
// we can't hold both src_pending and dst_pending in scope because they
// borrow the buffer tracker mutably...
let mut barriers = Vec::new();
let (src_buffer, src_pending) =
cmb.trackers
.buffers
.use_replace(&*buffer_guard, source, (), BufferUsage::COPY_SRC);
assert!(src_buffer.usage.contains(BufferUsage::COPY_SRC));
barriers.extend(src_pending.map(|pending| hal::memory::Barrier::Buffer {
states: pending.to_states(),
target: &src_buffer.raw,
families: None,
range: None .. None,
}));
let (dst_buffer, dst_pending) =
cmb.trackers
.buffers
.use_replace(&*buffer_guard, destination, (), BufferUsage::COPY_DST);
assert!(dst_buffer.usage.contains(BufferUsage::COPY_DST));
barriers.extend(dst_pending.map(|pending| hal::memory::Barrier::Buffer {
states: pending.to_states(),
target: &dst_buffer.raw,
families: None,
range: None .. None,
}));
let region = hal::command::BufferCopy {
src: source_offset,
dst: destination_offset,
size,
};
let cmb_raw = cmb.raw.last_mut().unwrap();
unsafe {
cmb_raw.pipeline_barrier(
all_buffer_stages() .. all_buffer_stages(),
hal::memory::Dependencies::empty(),
barriers,
);
cmb_raw.copy_buffer(&src_buffer.raw, &dst_buffer.raw, iter::once(region));
}
}
#[cfg(feature = "local")]
#[no_mangle]
pub extern "C" fn wgpu_command_encoder_copy_buffer_to_buffer(
command_encoder_id: CommandEncoderId,
source: BufferId,
source_offset: BufferAddress,
destination: BufferId,
destination_offset: BufferAddress,
size: BufferAddress,
) {
gfx_select!(command_encoder_id => command_encoder_copy_buffer_to_buffer(
&*GLOBAL,
command_encoder_id,
source, source_offset,
destination,
destination_offset,
size))
}
pub fn command_encoder_copy_buffer_to_texture<B: GfxBackend>(
global: &Global,
command_encoder_id: CommandEncoderId,
source: &BufferCopyView,
destination: &TextureCopyView,
copy_size: Extent3d,
) {
let hub = B::hub(global);
let mut token = Token::root();
let (mut cmb_guard, mut token) = hub.command_buffers.write(&mut token);
let cmb = &mut cmb_guard[command_encoder_id];
let (buffer_guard, mut token) = hub.buffers.read(&mut token);
let (texture_guard, _) = hub.textures.read(&mut token);
let aspects = texture_guard[destination.texture].full_range.aspects;
let (src_buffer, src_pending) =
cmb.trackers
.buffers
.use_replace(&*buffer_guard, source.buffer, (), BufferUsage::COPY_SRC);
assert!(src_buffer.usage.contains(BufferUsage::COPY_SRC));
let src_barriers = src_pending.map(|pending| hal::memory::Barrier::Buffer {
states: pending.to_states(),
target: &src_buffer.raw,
families: None,
range: None .. None,
});
let (dst_texture, dst_pending) = cmb.trackers.textures.use_replace(
&*texture_guard,
destination.texture,
destination.to_selector(aspects),
TextureUsage::COPY_DST,
);
assert!(dst_texture.usage.contains(TextureUsage::COPY_DST));
let dst_barriers = dst_pending.map(|pending| hal::memory::Barrier::Image {
states: pending.to_states(),
target: &dst_texture.raw,
families: None,
range: pending.selector,
});
let aspects = dst_texture.full_range.aspects;
let bytes_per_texel = conv::map_texture_format(dst_texture.format, cmb.features)
.surface_desc()
.bits as u32
/ BITS_PER_BYTE;
let buffer_width = source.row_pitch / bytes_per_texel;
assert_eq!(source.row_pitch % bytes_per_texel, 0);
let region = hal::command::BufferImageCopy {
buffer_offset: source.offset,
buffer_width,
buffer_height: source.image_height,
image_layers: destination.to_sub_layers(aspects),
image_offset: conv::map_origin(destination.origin),
image_extent: conv::map_extent(copy_size),
};
let cmb_raw = cmb.raw.last_mut().unwrap();
let stages = all_buffer_stages() | all_image_stages();
unsafe {
cmb_raw.pipeline_barrier(
stages .. stages,
hal::memory::Dependencies::empty(),
src_barriers.chain(dst_barriers),
);
cmb_raw.copy_buffer_to_image(
&src_buffer.raw,
&dst_texture.raw,
hal::image::Layout::TransferDstOptimal,
iter::once(region),
);
}
}
#[cfg(feature = "local")]
#[no_mangle]
pub extern "C" fn wgpu_command_encoder_copy_buffer_to_texture(
command_encoder_id: CommandEncoderId,
source: &BufferCopyView,
destination: &TextureCopyView,
copy_size: Extent3d,
) {
gfx_select!(command_encoder_id => command_encoder_copy_buffer_to_texture(
&*GLOBAL,
command_encoder_id,
source,
destination,
copy_size))
}
pub fn command_encoder_copy_texture_to_buffer<B: GfxBackend>(
global: &Global,
command_encoder_id: CommandEncoderId,
source: &TextureCopyView,
destination: &BufferCopyView,
copy_size: Extent3d,
) {
let hub = B::hub(global);
let mut token = Token::root();
let (mut cmb_guard, mut token) = hub.command_buffers.write(&mut token);
let cmb = &mut cmb_guard[command_encoder_id];
let (buffer_guard, mut token) = hub.buffers.read(&mut token);
let (texture_guard, _) = hub.textures.read(&mut token);
let aspects = texture_guard[source.texture].full_range.aspects;
let (src_texture, src_pending) = cmb.trackers.textures.use_replace(
&*texture_guard,
source.texture,
source.to_selector(aspects),
TextureUsage::COPY_SRC,
);
assert!(src_texture.usage.contains(TextureUsage::COPY_SRC));
let src_barriers = src_pending.map(|pending| hal::memory::Barrier::Image {
states: pending.to_states(),
target: &src_texture.raw,
families: None,
range: pending.selector,
});
let (dst_buffer, dst_barriers) = cmb.trackers.buffers.use_replace(
&*buffer_guard,
destination.buffer,
(),
BufferUsage::COPY_DST,
);
assert!(dst_buffer.usage.contains(BufferUsage::COPY_DST));
let dst_barrier = dst_barriers.map(|pending| hal::memory::Barrier::Buffer {
states: pending.to_states(),
target: &dst_buffer.raw,
families: None,
range: None .. None,
});
let aspects = src_texture.full_range.aspects;
let bytes_per_texel = conv::map_texture_format(src_texture.format, cmb.features)
.surface_desc()
.bits as u32
/ BITS_PER_BYTE;
let buffer_width = destination.row_pitch / bytes_per_texel;
assert_eq!(destination.row_pitch % bytes_per_texel, 0);
let region = hal::command::BufferImageCopy {
buffer_offset: destination.offset,
buffer_width,
buffer_height: destination.image_height,
image_layers: source.to_sub_layers(aspects),
image_offset: conv::map_origin(source.origin),
image_extent: conv::map_extent(copy_size),
};
let cmb_raw = cmb.raw.last_mut().unwrap();
let stages = all_buffer_stages() | all_image_stages();
unsafe {
cmb_raw.pipeline_barrier(
stages .. stages,
hal::memory::Dependencies::empty(),
src_barriers.chain(dst_barrier),
);
cmb_raw.copy_image_to_buffer(
&src_texture.raw,
hal::image::Layout::TransferSrcOptimal,
&dst_buffer.raw,
iter::once(region),
);
}
}
#[cfg(feature = "local")]
#[no_mangle]
pub extern "C" fn wgpu_command_encoder_copy_texture_to_buffer(
command_encoder_id: CommandEncoderId,
source: &TextureCopyView,
destination: &BufferCopyView,
copy_size: Extent3d,
) {
gfx_select!(command_encoder_id => command_encoder_copy_texture_to_buffer(
&*GLOBAL,
command_encoder_id,
source,
destination,
copy_size))
}
pub fn command_encoder_copy_texture_to_texture<B: GfxBackend>(
global: &Global,
command_encoder_id: CommandEncoderId,
source: &TextureCopyView,
destination: &TextureCopyView,
copy_size: Extent3d,
) {
let hub = B::hub(global);
let mut token = Token::root();
let (mut cmb_guard, mut token) = hub.command_buffers.write(&mut token);
let cmb = &mut cmb_guard[command_encoder_id];
let (_, mut token) = hub.buffers.read(&mut token); // skip token
let (texture_guard, _) = hub.textures.read(&mut token);
// we can't hold both src_pending and dst_pending in scope because they
// borrow the buffer tracker mutably...
let mut barriers = Vec::new();
let aspects = texture_guard[source.texture].full_range.aspects
& texture_guard[destination.texture].full_range.aspects;
let (src_texture, src_pending) = cmb.trackers.textures.use_replace(
&*texture_guard,
source.texture,
source.to_selector(aspects),
TextureUsage::COPY_SRC,
);
assert!(src_texture.usage.contains(TextureUsage::COPY_SRC));
barriers.extend(src_pending.map(|pending| hal::memory::Barrier::Image {
states: pending.to_states(),
target: &src_texture.raw,
families: None,
range: pending.selector,
}));
let (dst_texture, dst_pending) = cmb.trackers.textures.use_replace(
&*texture_guard,
destination.texture,
destination.to_selector(aspects),
TextureUsage::COPY_DST,
);
assert!(dst_texture.usage.contains(TextureUsage::COPY_DST));
barriers.extend(dst_pending.map(|pending| hal::memory::Barrier::Image {
states: pending.to_states(),
target: &dst_texture.raw,
families: None,
range: pending.selector,
}));
let aspects = src_texture.full_range.aspects & dst_texture.full_range.aspects;
let region = hal::command::ImageCopy {
src_subresource: source.to_sub_layers(aspects),
src_offset: conv::map_origin(source.origin),
dst_subresource: destination.to_sub_layers(aspects),
dst_offset: conv::map_origin(destination.origin),
extent: conv::map_extent(copy_size),
};
let cmb_raw = cmb.raw.last_mut().unwrap();
unsafe {
cmb_raw.pipeline_barrier(
all_image_stages() .. all_image_stages(),
hal::memory::Dependencies::empty(),
barriers,
);
cmb_raw.copy_image(
&src_texture.raw,
hal::image::Layout::TransferSrcOptimal,
&dst_texture.raw,
hal::image::Layout::TransferDstOptimal,
iter::once(region),
);
}
}
#[cfg(feature = "local")]
#[no_mangle]
pub extern "C" fn wgpu_command_encoder_copy_texture_to_texture(
command_encoder_id: CommandEncoderId,
source: &TextureCopyView,
destination: &TextureCopyView,
copy_size: Extent3d,
) {
gfx_select!(command_encoder_id => command_encoder_copy_texture_to_texture(
&*GLOBAL,
command_encoder_id,
source,
destination,
copy_size))
}

View File

@ -1,661 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use crate::{binding_model, command, pipeline, resource, Color, Extent3d, Features, Origin3d};
pub fn map_buffer_usage(
usage: resource::BufferUsage,
) -> (hal::buffer::Usage, hal::memory::Properties) {
use crate::resource::BufferUsage as W;
use hal::buffer::Usage as U;
use hal::memory::Properties as P;
let mut hal_memory = P::empty();
if usage.contains(W::MAP_READ) {
hal_memory |= P::CPU_VISIBLE | P::CPU_CACHED;
}
if usage.contains(W::MAP_WRITE) {
hal_memory |= P::CPU_VISIBLE;
}
let mut hal_usage = U::empty();
if usage.contains(W::COPY_SRC) {
hal_usage |= U::TRANSFER_SRC;
}
if usage.contains(W::COPY_DST) {
hal_usage |= U::TRANSFER_DST;
}
if usage.contains(W::INDEX) {
hal_usage |= U::INDEX;
}
if usage.contains(W::VERTEX) {
hal_usage |= U::VERTEX;
}
if usage.contains(W::UNIFORM) {
hal_usage |= U::UNIFORM;
}
if usage.contains(W::STORAGE) {
hal_usage |= U::STORAGE;
}
if usage.contains(W::INDIRECT) {
hal_usage |= U::INDIRECT;
}
(hal_usage, hal_memory)
}
pub fn map_texture_usage(
usage: resource::TextureUsage,
aspects: hal::format::Aspects,
) -> hal::image::Usage {
use crate::resource::TextureUsage as W;
use hal::image::Usage as U;
let mut value = U::empty();
if usage.contains(W::COPY_SRC) {
value |= U::TRANSFER_SRC;
}
if usage.contains(W::COPY_DST) {
value |= U::TRANSFER_DST;
}
if usage.contains(W::SAMPLED) {
value |= U::SAMPLED;
}
if usage.contains(W::STORAGE) {
value |= U::STORAGE;
}
if usage.contains(W::OUTPUT_ATTACHMENT) {
if aspects.intersects(hal::format::Aspects::DEPTH | hal::format::Aspects::STENCIL) {
value |= U::DEPTH_STENCIL_ATTACHMENT;
} else {
value |= U::COLOR_ATTACHMENT;
}
}
// Note: TextureUsage::Present does not need to be handled explicitly
// TODO: HAL Transient Attachment, HAL Input Attachment
value
}
pub fn map_binding_type(
binding: &binding_model::BindGroupLayoutBinding,
) -> hal::pso::DescriptorType {
use crate::binding_model::BindingType as Bt;
use hal::pso::DescriptorType as H;
match binding.ty {
Bt::UniformBuffer => {
if binding.dynamic {
H::UniformBufferDynamic
} else {
H::UniformBuffer
}
}
Bt::StorageBuffer | Bt::ReadonlyStorageBuffer => {
if binding.dynamic {
H::StorageBufferDynamic
} else {
H::StorageBuffer
}
}
Bt::Sampler => H::Sampler,
Bt::SampledTexture => H::SampledImage,
Bt::StorageTexture => H::StorageImage,
}
}
pub fn map_shader_stage_flags(
shader_stage_flags: binding_model::ShaderStage,
) -> hal::pso::ShaderStageFlags {
use crate::binding_model::ShaderStage as Ss;
use hal::pso::ShaderStageFlags as H;
let mut value = H::empty();
if shader_stage_flags.contains(Ss::VERTEX) {
value |= H::VERTEX;
}
if shader_stage_flags.contains(Ss::FRAGMENT) {
value |= H::FRAGMENT;
}
if shader_stage_flags.contains(Ss::COMPUTE) {
value |= H::COMPUTE;
}
value
}
pub fn map_origin(origin: Origin3d) -> hal::image::Offset {
hal::image::Offset {
x: origin.x as i32,
y: origin.y as i32,
z: origin.z as i32,
}
}
pub fn map_extent(extent: Extent3d) -> hal::image::Extent {
hal::image::Extent {
width: extent.width,
height: extent.height,
depth: extent.depth,
}
}
pub fn map_primitive_topology(primitive_topology: pipeline::PrimitiveTopology) -> hal::pso::Primitive {
use crate::pipeline::PrimitiveTopology as Pt;
use hal::pso::Primitive as H;
match primitive_topology {
Pt::PointList => H::PointList,
Pt::LineList => H::LineList,
Pt::LineStrip => H::LineStrip,
Pt::TriangleList => H::TriangleList,
Pt::TriangleStrip => H::TriangleStrip,
}
}
pub fn map_color_state_descriptor(
desc: &pipeline::ColorStateDescriptor,
) -> hal::pso::ColorBlendDesc {
let color_mask = desc.write_mask;
let blend_state = if desc.color_blend != pipeline::BlendDescriptor::REPLACE
|| desc.alpha_blend != pipeline::BlendDescriptor::REPLACE
{
Some(hal::pso::BlendState {
color: map_blend_descriptor(&desc.color_blend),
alpha: map_blend_descriptor(&desc.alpha_blend),
})
} else {
None
};
hal::pso::ColorBlendDesc {
mask: map_color_write_flags(color_mask),
blend: blend_state,
}
}
fn map_color_write_flags(flags: pipeline::ColorWrite) -> hal::pso::ColorMask {
use crate::pipeline::ColorWrite as Cw;
use hal::pso::ColorMask as H;
let mut value = H::empty();
if flags.contains(Cw::RED) {
value |= H::RED;
}
if flags.contains(Cw::GREEN) {
value |= H::GREEN;
}
if flags.contains(Cw::BLUE) {
value |= H::BLUE;
}
if flags.contains(Cw::ALPHA) {
value |= H::ALPHA;
}
value
}
fn map_blend_descriptor(blend_desc: &pipeline::BlendDescriptor) -> hal::pso::BlendOp {
use crate::pipeline::BlendOperation as Bo;
use hal::pso::BlendOp as H;
match blend_desc.operation {
Bo::Add => H::Add {
src: map_blend_factor(blend_desc.src_factor),
dst: map_blend_factor(blend_desc.dst_factor),
},
Bo::Subtract => H::Sub {
src: map_blend_factor(blend_desc.src_factor),
dst: map_blend_factor(blend_desc.dst_factor),
},
Bo::ReverseSubtract => H::RevSub {
src: map_blend_factor(blend_desc.src_factor),
dst: map_blend_factor(blend_desc.dst_factor),
},
Bo::Min => H::Min,
Bo::Max => H::Max,
}
}
fn map_blend_factor(blend_factor: pipeline::BlendFactor) -> hal::pso::Factor {
use crate::pipeline::BlendFactor as Bf;
use hal::pso::Factor as H;
match blend_factor {
Bf::Zero => H::Zero,
Bf::One => H::One,
Bf::SrcColor => H::SrcColor,
Bf::OneMinusSrcColor => H::OneMinusSrcColor,
Bf::SrcAlpha => H::SrcAlpha,
Bf::OneMinusSrcAlpha => H::OneMinusSrcAlpha,
Bf::DstColor => H::DstColor,
Bf::OneMinusDstColor => H::OneMinusDstColor,
Bf::DstAlpha => H::DstAlpha,
Bf::OneMinusDstAlpha => H::OneMinusDstAlpha,
Bf::SrcAlphaSaturated => H::SrcAlphaSaturate,
Bf::BlendColor => H::ConstColor,
Bf::OneMinusBlendColor => H::OneMinusConstColor,
}
}
pub fn map_depth_stencil_state_descriptor(
desc: &pipeline::DepthStencilStateDescriptor,
) -> hal::pso::DepthStencilDesc {
hal::pso::DepthStencilDesc {
depth: if desc.depth_write_enabled
|| desc.depth_compare != resource::CompareFunction::Always
{
Some(hal::pso::DepthTest {
fun: map_compare_function(desc.depth_compare),
write: desc.depth_write_enabled,
})
} else {
None
},
depth_bounds: false, // TODO
stencil: if desc.stencil_read_mask != !0
|| desc.stencil_write_mask != !0
|| desc.stencil_front != pipeline::StencilStateFaceDescriptor::IGNORE
|| desc.stencil_back != pipeline::StencilStateFaceDescriptor::IGNORE
{
Some(hal::pso::StencilTest {
faces: hal::pso::Sided {
front: map_stencil_face(&desc.stencil_front),
back: map_stencil_face(&desc.stencil_back),
},
read_masks: hal::pso::State::Static(hal::pso::Sided::new(desc.stencil_read_mask)),
write_masks: hal::pso::State::Static(hal::pso::Sided::new(desc.stencil_write_mask)),
reference_values: if desc.needs_stencil_reference() {
hal::pso::State::Dynamic
} else {
hal::pso::State::Static(hal::pso::Sided::new(0))
},
})
} else {
None
},
}
}
fn map_stencil_face(
stencil_state_face_desc: &pipeline::StencilStateFaceDescriptor,
) -> hal::pso::StencilFace {
hal::pso::StencilFace {
fun: map_compare_function(stencil_state_face_desc.compare),
op_fail: map_stencil_operation(stencil_state_face_desc.fail_op),
op_depth_fail: map_stencil_operation(stencil_state_face_desc.depth_fail_op),
op_pass: map_stencil_operation(stencil_state_face_desc.pass_op),
}
}
pub fn map_compare_function(compare_function: resource::CompareFunction) -> hal::pso::Comparison {
use crate::resource::CompareFunction as Cf;
use hal::pso::Comparison as H;
match compare_function {
Cf::Never => H::Never,
Cf::Less => H::Less,
Cf::Equal => H::Equal,
Cf::LessEqual => H::LessEqual,
Cf::Greater => H::Greater,
Cf::NotEqual => H::NotEqual,
Cf::GreaterEqual => H::GreaterEqual,
Cf::Always => H::Always,
}
}
fn map_stencil_operation(stencil_operation: pipeline::StencilOperation) -> hal::pso::StencilOp {
use crate::pipeline::StencilOperation as So;
use hal::pso::StencilOp as H;
match stencil_operation {
So::Keep => H::Keep,
So::Zero => H::Zero,
So::Replace => H::Replace,
So::Invert => H::Invert,
So::IncrementClamp => H::IncrementClamp,
So::DecrementClamp => H::DecrementClamp,
So::IncrementWrap => H::IncrementWrap,
So::DecrementWrap => H::DecrementWrap,
}
}
pub(crate) fn map_texture_format(
texture_format: resource::TextureFormat,
features: Features,
) -> hal::format::Format {
use crate::resource::TextureFormat as Tf;
use hal::format::Format as H;
match texture_format {
// Normal 8 bit formats
Tf::R8Unorm => H::R8Unorm,
Tf::R8Snorm => H::R8Snorm,
Tf::R8Uint => H::R8Uint,
Tf::R8Sint => H::R8Sint,
// Normal 16 bit formats
Tf::R16Unorm => H::R16Unorm,
Tf::R16Snorm => H::R16Snorm,
Tf::R16Uint => H::R16Uint,
Tf::R16Sint => H::R16Sint,
Tf::R16Float => H::R16Sfloat,
Tf::Rg8Unorm => H::Rg8Unorm,
Tf::Rg8Snorm => H::Rg8Snorm,
Tf::Rg8Uint => H::Rg8Uint,
Tf::Rg8Sint => H::Rg8Sint,
// Normal 32 bit formats
Tf::R32Uint => H::R32Uint,
Tf::R32Sint => H::R32Sint,
Tf::R32Float => H::R32Sfloat,
Tf::Rg16Unorm => H::Rg16Unorm,
Tf::Rg16Snorm => H::Rg16Snorm,
Tf::Rg16Uint => H::Rg16Uint,
Tf::Rg16Sint => H::Rg16Sint,
Tf::Rg16Float => H::Rg16Sfloat,
Tf::Rgba8Unorm => H::Rgba8Unorm,
Tf::Rgba8UnormSrgb => H::Rgba8Srgb,
Tf::Rgba8Snorm => H::Rgba8Snorm,
Tf::Rgba8Uint => H::Rgba8Uint,
Tf::Rgba8Sint => H::Rgba8Sint,
Tf::Bgra8Unorm => H::Bgra8Unorm,
Tf::Bgra8UnormSrgb => H::Bgra8Srgb,
// Packed 32 bit formats
Tf::Rgb10a2Unorm => H::A2r10g10b10Unorm,
Tf::Rg11b10Float => H::B10g11r11Ufloat,
// Normal 64 bit formats
Tf::Rg32Uint => H::Rg32Uint,
Tf::Rg32Sint => H::Rg32Sint,
Tf::Rg32Float => H::Rg32Sfloat,
Tf::Rgba16Unorm => H::Rgba16Unorm,
Tf::Rgba16Snorm => H::Rgba16Snorm,
Tf::Rgba16Uint => H::Rgba16Uint,
Tf::Rgba16Sint => H::Rgba16Sint,
Tf::Rgba16Float => H::Rgba16Sfloat,
// Normal 128 bit formats
Tf::Rgba32Uint => H::Rgba32Uint,
Tf::Rgba32Sint => H::Rgba32Sint,
Tf::Rgba32Float => H::Rgba32Sfloat,
// Depth and stencil formats
Tf::Depth32Float => H::D32Sfloat,
Tf::Depth24Plus => {
if features.supports_texture_d24_s8 {
H::D24UnormS8Uint
} else {
H::D32Sfloat
}
}
Tf::Depth24PlusStencil8 => {
if features.supports_texture_d24_s8 {
H::D24UnormS8Uint
} else {
H::D32SfloatS8Uint
}
}
}
}
pub fn map_vertex_format(vertex_format: pipeline::VertexFormat) -> hal::format::Format {
use crate::pipeline::VertexFormat as Vf;
use hal::format::Format as H;
match vertex_format {
Vf::Uchar2 => H::Rg8Uint,
Vf::Uchar4 => H::Rgba8Uint,
Vf::Char2 => H::Rg8Sint,
Vf::Char4 => H::Rgba8Sint,
Vf::Uchar2Norm => H::Rg8Unorm,
Vf::Uchar4Norm => H::Rgba8Unorm,
Vf::Char2Norm => H::Rg8Snorm,
Vf::Char4Norm => H::Rgba8Snorm,
Vf::Ushort2 => H::Rg16Uint,
Vf::Ushort4 => H::Rgba16Uint,
Vf::Short2 => H::Rg16Sint,
Vf::Short4 => H::Rgba16Sint,
Vf::Ushort2Norm => H::Rg16Unorm,
Vf::Ushort4Norm => H::Rgba16Unorm,
Vf::Short2Norm => H::Rg16Snorm,
Vf::Short4Norm => H::Rgba16Snorm,
Vf::Half2 => H::Rg16Sfloat,
Vf::Half4 => H::Rgba16Sfloat,
Vf::Float => H::R32Sfloat,
Vf::Float2 => H::Rg32Sfloat,
Vf::Float3 => H::Rgb32Sfloat,
Vf::Float4 => H::Rgba32Sfloat,
Vf::Uint => H::R32Uint,
Vf::Uint2 => H::Rg32Uint,
Vf::Uint3 => H::Rgb32Uint,
Vf::Uint4 => H::Rgba32Uint,
Vf::Int => H::R32Sint,
Vf::Int2 => H::Rg32Sint,
Vf::Int3 => H::Rgb32Sint,
Vf::Int4 => H::Rgba32Sint,
}
}
fn checked_u32_as_u16(value: u32) -> u16 {
assert!(value <= ::std::u16::MAX as u32);
value as u16
}
pub fn map_texture_dimension_size(
dimension: resource::TextureDimension,
Extent3d {
width,
height,
depth,
}: Extent3d,
array_size: u32,
sample_size: u32,
) -> hal::image::Kind {
use crate::resource::TextureDimension::*;
use hal::image::Kind as H;
match dimension {
D1 => {
assert_eq!(height, 1);
assert_eq!(depth, 1);
assert_eq!(sample_size, 1);
H::D1(width, checked_u32_as_u16(array_size))
}
D2 => {
assert_eq!(depth, 1);
assert!(
sample_size == 1
|| sample_size == 2
|| sample_size == 4
|| sample_size == 8
|| sample_size == 16
|| sample_size == 32,
"Invalid sample_count of {}",
sample_size
);
H::D2(
width,
height,
checked_u32_as_u16(array_size),
sample_size as u8,
)
}
D3 => {
assert_eq!(array_size, 1);
assert_eq!(sample_size, 1);
H::D3(width, height, depth)
}
}
}
pub fn map_texture_view_dimension(
dimension: resource::TextureViewDimension,
) -> hal::image::ViewKind {
use crate::resource::TextureViewDimension::*;
use hal::image::ViewKind as H;
match dimension {
D1 => H::D1,
D2 => H::D2,
D2Array => H::D2Array,
Cube => H::Cube,
CubeArray => H::CubeArray,
D3 => H::D3,
}
}
pub fn map_buffer_state(usage: resource::BufferUsage) -> hal::buffer::State {
use crate::resource::BufferUsage as W;
use hal::buffer::Access as A;
let mut access = A::empty();
if usage.contains(W::COPY_SRC) {
access |= A::TRANSFER_READ;
}
if usage.contains(W::COPY_DST) {
access |= A::TRANSFER_WRITE;
}
if usage.contains(W::INDEX) {
access |= A::INDEX_BUFFER_READ;
}
if usage.contains(W::VERTEX) {
access |= A::VERTEX_BUFFER_READ;
}
if usage.contains(W::UNIFORM) {
access |= A::UNIFORM_READ | A::SHADER_READ;
}
if usage.contains(W::STORAGE) {
access |= A::SHADER_WRITE;
}
access
}
pub fn map_texture_state(
usage: resource::TextureUsage,
aspects: hal::format::Aspects,
) -> hal::image::State {
use crate::resource::TextureUsage as W;
use hal::image::{Access as A, Layout as L};
let is_color = aspects.contains(hal::format::Aspects::COLOR);
let layout = match usage {
W::UNINITIALIZED => return (A::empty(), L::Undefined),
W::COPY_SRC => L::TransferSrcOptimal,
W::COPY_DST => L::TransferDstOptimal,
W::SAMPLED => L::ShaderReadOnlyOptimal,
W::OUTPUT_ATTACHMENT if is_color => L::ColorAttachmentOptimal,
W::OUTPUT_ATTACHMENT => L::DepthStencilAttachmentOptimal, //TODO: read-only depth/stencil
_ => L::General,
};
let mut access = A::empty();
if usage.contains(W::COPY_SRC) {
access |= A::TRANSFER_READ;
}
if usage.contains(W::COPY_DST) {
access |= A::TRANSFER_WRITE;
}
if usage.contains(W::SAMPLED) {
access |= A::SHADER_READ;
}
if usage.contains(W::STORAGE) {
access |= A::SHADER_WRITE;
}
if usage.contains(W::OUTPUT_ATTACHMENT) {
//TODO: read-only attachments
access |= if is_color {
A::COLOR_ATTACHMENT_WRITE
} else {
A::DEPTH_STENCIL_ATTACHMENT_WRITE
};
}
(access, layout)
}
pub fn map_load_store_ops(
load: command::LoadOp,
store: command::StoreOp,
) -> hal::pass::AttachmentOps {
hal::pass::AttachmentOps {
load: match load {
command::LoadOp::Clear => hal::pass::AttachmentLoadOp::Clear,
command::LoadOp::Load => hal::pass::AttachmentLoadOp::Load,
},
store: match store {
command::StoreOp::Clear => hal::pass::AttachmentStoreOp::DontCare, //TODO!
command::StoreOp::Store => hal::pass::AttachmentStoreOp::Store,
},
}
}
pub fn map_color_f32(color: &Color) -> hal::pso::ColorValue {
[
color.r as f32,
color.g as f32,
color.b as f32,
color.a as f32,
]
}
pub fn map_color_i32(color: &Color) -> [i32; 4] {
[
color.r as i32,
color.g as i32,
color.b as i32,
color.a as i32,
]
}
pub fn map_color_u32(color: &Color) -> [u32; 4] {
[
color.r as u32,
color.g as u32,
color.b as u32,
color.a as u32,
]
}
pub fn map_filter(filter: resource::FilterMode) -> hal::image::Filter {
match filter {
resource::FilterMode::Nearest => hal::image::Filter::Nearest,
resource::FilterMode::Linear => hal::image::Filter::Linear,
}
}
pub fn map_wrap(address: resource::AddressMode) -> hal::image::WrapMode {
use crate::resource::AddressMode as Am;
use hal::image::WrapMode as W;
match address {
Am::ClampToEdge => W::Clamp,
Am::Repeat => W::Tile,
Am::MirrorRepeat => W::Mirror,
}
}
pub fn map_rasterization_state_descriptor(
desc: &pipeline::RasterizationStateDescriptor,
) -> hal::pso::Rasterizer {
hal::pso::Rasterizer {
depth_clamping: false,
polygon_mode: hal::pso::PolygonMode::Fill,
cull_face: match desc.cull_mode {
pipeline::CullMode::None => hal::pso::Face::empty(),
pipeline::CullMode::Front => hal::pso::Face::FRONT,
pipeline::CullMode::Back => hal::pso::Face::BACK,
},
front_face: match desc.front_face {
pipeline::FrontFace::Ccw => hal::pso::FrontFace::CounterClockwise,
pipeline::FrontFace::Cw => hal::pso::FrontFace::Clockwise,
},
depth_bias: if desc.depth_bias != 0
|| desc.depth_bias_slope_scale != 0.0
|| desc.depth_bias_clamp != 0.0
{
Some(hal::pso::State::Static(hal::pso::DepthBias {
const_factor: desc.depth_bias as f32,
slope_factor: desc.depth_bias_slope_scale,
clamp: desc.depth_bias_clamp,
}))
} else {
None
},
conservative: false,
}
}
pub fn map_index_format(index_format: pipeline::IndexFormat) -> hal::IndexType {
match index_format {
pipeline::IndexFormat::Uint16 => hal::IndexType::U16,
pipeline::IndexFormat::Uint32 => hal::IndexType::U32,
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,556 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use crate::{
backend,
id::{Input, Output},
Adapter,
AdapterId,
Backend,
BindGroup,
BindGroupId,
BindGroupLayout,
BindGroupLayoutId,
Buffer,
BufferId,
CommandBuffer,
CommandBufferId,
ComputePass,
ComputePassId,
ComputePipeline,
ComputePipelineId,
Device,
DeviceId,
Epoch,
Index,
Instance,
PipelineLayout,
PipelineLayoutId,
RenderPass,
RenderPassId,
RenderPipeline,
RenderPipelineId,
Sampler,
SamplerId,
ShaderModule,
ShaderModuleId,
Surface,
SurfaceId,
SwapChain,
SwapChainId,
Texture,
TextureId,
TextureView,
TextureViewId,
TypedId,
};
#[cfg(feature = "local")]
use parking_lot::Mutex;
use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use vec_map::VecMap;
#[cfg(debug_assertions)]
use std::cell::Cell;
#[cfg(feature = "local")]
use std::sync::Arc;
use std::{marker::PhantomData, ops};
/// A simple structure to manage identities of objects.
#[derive(Debug)]
pub struct IdentityManager<I: TypedId> {
free: Vec<Index>,
epochs: Vec<Epoch>,
backend: Backend,
phantom: PhantomData<I>,
}
impl<I: TypedId> IdentityManager<I> {
pub fn new(backend: Backend) -> Self {
IdentityManager {
free: Default::default(),
epochs: Default::default(),
backend,
phantom: PhantomData,
}
}
}
impl<I: TypedId> IdentityManager<I> {
pub fn alloc(&mut self) -> I {
match self.free.pop() {
Some(index) => I::zip(index, self.epochs[index as usize], self.backend),
None => {
let epoch = 1;
let id = I::zip(self.epochs.len() as Index, epoch, self.backend);
self.epochs.push(epoch);
id
}
}
}
pub fn free(&mut self, id: I) {
let (index, epoch, backend) = id.unzip();
debug_assert_eq!(backend, self.backend);
// avoid doing this check in release
if cfg!(debug_assertions) {
assert!(!self.free.contains(&index));
}
let pe = &mut self.epochs[index as usize];
assert_eq!(*pe, epoch);
*pe += 1;
self.free.push(index);
}
}
#[derive(Debug)]
pub struct Storage<T, I: TypedId> {
//TODO: consider concurrent hashmap?
map: VecMap<(T, Epoch)>,
_phantom: PhantomData<I>,
}
impl<T, I: TypedId> ops::Index<I> for Storage<T, I> {
type Output = T;
fn index(&self, id: I) -> &T {
let (index, epoch, _) = id.unzip();
let (ref value, storage_epoch) = self.map[index as usize];
assert_eq!(epoch, storage_epoch);
value
}
}
impl<T, I: TypedId> ops::IndexMut<I> for Storage<T, I> {
fn index_mut(&mut self, id: I) -> &mut T {
let (index, epoch, _) = id.unzip();
let (ref mut value, storage_epoch) = self.map[index as usize];
assert_eq!(epoch, storage_epoch);
value
}
}
impl<T, I: TypedId> Storage<T, I> {
pub fn contains(&self, id: I) -> bool {
let (index, epoch, _) = id.unzip();
match self.map.get(index as usize) {
Some(&(_, storage_epoch)) => epoch == storage_epoch,
None => false,
}
}
pub fn insert(&mut self, id: I, value: T) -> Option<T> {
let (index, epoch, _) = id.unzip();
let old = self.map.insert(index as usize, (value, epoch));
old.map(|(v, _storage_epoch)| v)
}
pub fn remove(&mut self, id: I) -> Option<T> {
let (index, epoch, _) = id.unzip();
self.map
.remove(index as usize)
.map(|(value, storage_epoch)| {
assert_eq!(epoch, storage_epoch);
value
})
}
}
/// Type system for enforcing the lock order on shared HUB structures.
/// If type A implements `Access<B>`, that means we are allowed to proceed
/// with locking resource `B` after we lock `A`.
///
/// The implenentations basically describe the edges in a directed graph
/// of lock transitions. As long as it doesn't have loops, we can have
/// multiple concurrent paths on this graph (from multiple threads) without
/// deadlocks, i.e. there is always a path whose next resource is not locked
/// by some other path, at any time.
pub trait Access<B> {}
pub enum Root {}
//TODO: establish an order instead of declaring all the pairs.
impl Access<Instance> for Root {}
impl Access<Surface> for Root {}
impl Access<Surface> for Instance {}
impl<B: hal::Backend> Access<Adapter<B>> for Root {}
impl<B: hal::Backend> Access<Adapter<B>> for Surface {}
impl<B: hal::Backend> Access<Device<B>> for Root {}
impl<B: hal::Backend> Access<Device<B>> for Surface {}
impl<B: hal::Backend> Access<Device<B>> for Adapter<B> {}
impl<B: hal::Backend> Access<SwapChain<B>> for Device<B> {}
impl<B: hal::Backend> Access<PipelineLayout<B>> for Root {}
impl<B: hal::Backend> Access<PipelineLayout<B>> for Device<B> {}
impl<B: hal::Backend> Access<BindGroupLayout<B>> for Root {}
impl<B: hal::Backend> Access<BindGroupLayout<B>> for Device<B> {}
impl<B: hal::Backend> Access<BindGroup<B>> for Root {}
impl<B: hal::Backend> Access<BindGroup<B>> for Device<B> {}
impl<B: hal::Backend> Access<BindGroup<B>> for PipelineLayout<B> {}
impl<B: hal::Backend> Access<BindGroup<B>> for CommandBuffer<B> {}
impl<B: hal::Backend> Access<CommandBuffer<B>> for Root {}
impl<B: hal::Backend> Access<CommandBuffer<B>> for Device<B> {}
impl<B: hal::Backend> Access<CommandBuffer<B>> for SwapChain<B> {}
impl<B: hal::Backend> Access<ComputePass<B>> for Root {}
impl<B: hal::Backend> Access<ComputePass<B>> for BindGroup<B> {}
impl<B: hal::Backend> Access<ComputePass<B>> for CommandBuffer<B> {}
impl<B: hal::Backend> Access<RenderPass<B>> for Root {}
impl<B: hal::Backend> Access<RenderPass<B>> for BindGroup<B> {}
impl<B: hal::Backend> Access<RenderPass<B>> for CommandBuffer<B> {}
impl<B: hal::Backend> Access<ComputePipeline<B>> for Root {}
impl<B: hal::Backend> Access<ComputePipeline<B>> for ComputePass<B> {}
impl<B: hal::Backend> Access<RenderPipeline<B>> for Root {}
impl<B: hal::Backend> Access<RenderPipeline<B>> for RenderPass<B> {}
impl<B: hal::Backend> Access<ShaderModule<B>> for Root {}
impl<B: hal::Backend> Access<ShaderModule<B>> for PipelineLayout<B> {}
impl<B: hal::Backend> Access<Buffer<B>> for Root {}
impl<B: hal::Backend> Access<Buffer<B>> for Device<B> {}
impl<B: hal::Backend> Access<Buffer<B>> for BindGroupLayout<B> {}
impl<B: hal::Backend> Access<Buffer<B>> for BindGroup<B> {}
impl<B: hal::Backend> Access<Buffer<B>> for CommandBuffer<B> {}
impl<B: hal::Backend> Access<Buffer<B>> for ComputePass<B> {}
impl<B: hal::Backend> Access<Buffer<B>> for ComputePipeline<B> {}
impl<B: hal::Backend> Access<Buffer<B>> for RenderPass<B> {}
impl<B: hal::Backend> Access<Buffer<B>> for RenderPipeline<B> {}
impl<B: hal::Backend> Access<Texture<B>> for Root {}
impl<B: hal::Backend> Access<Texture<B>> for Device<B> {}
impl<B: hal::Backend> Access<Texture<B>> for Buffer<B> {}
impl<B: hal::Backend> Access<TextureView<B>> for Root {}
impl<B: hal::Backend> Access<TextureView<B>> for SwapChain<B> {}
impl<B: hal::Backend> Access<TextureView<B>> for Device<B> {}
impl<B: hal::Backend> Access<TextureView<B>> for Texture<B> {}
impl<B: hal::Backend> Access<Sampler<B>> for Root {}
impl<B: hal::Backend> Access<Sampler<B>> for Device<B> {}
impl<B: hal::Backend> Access<Sampler<B>> for TextureView<B> {}
#[cfg(debug_assertions)]
thread_local! {
static ACTIVE_TOKEN: Cell<u8> = Cell::new(0);
}
/// A permission token to lock resource `T` or anything after it,
/// as defined by the `Access` implementations.
///
/// Note: there can only be one non-borrowed `Token` alive on a thread
/// at a time, which is enforced by `ACTIVE_TOKEN`.
pub struct Token<'a, T: 'a> {
level: PhantomData<&'a T>,
}
impl<'a, T> Token<'a, T> {
fn new() -> Self {
#[cfg(debug_assertions)]
ACTIVE_TOKEN.with(|active| {
let old = active.get();
assert_ne!(old, 0, "Root token was dropped");
active.set(old + 1);
});
Token { level: PhantomData }
}
}
impl Token<'static, Root> {
pub fn root() -> Self {
#[cfg(debug_assertions)]
ACTIVE_TOKEN.with(|active| {
assert_eq!(0, active.replace(1), "Root token is already active");
});
Token { level: PhantomData }
}
}
impl<'a, T> Drop for Token<'a, T> {
fn drop(&mut self) {
#[cfg(debug_assertions)]
ACTIVE_TOKEN.with(|active| {
let old = active.get();
active.set(old - 1);
});
}
}
#[derive(Debug)]
pub struct Registry<T, I: TypedId> {
#[cfg(feature = "local")]
pub identity: Mutex<IdentityManager<I>>,
data: RwLock<Storage<T, I>>,
backend: Backend,
}
impl<T, I: TypedId> Registry<T, I> {
fn new(backend: Backend) -> Self {
Registry {
#[cfg(feature = "local")]
identity: Mutex::new(IdentityManager::new(backend)),
data: RwLock::new(Storage {
map: VecMap::new(),
_phantom: PhantomData,
}),
backend,
}
}
}
impl<T, I: TypedId + Copy> Registry<T, I> {
pub fn register<A: Access<T>>(&self, id: I, value: T, _token: &mut Token<A>) {
debug_assert_eq!(id.unzip().2, self.backend);
let old = self.data.write().insert(id, value);
assert!(old.is_none());
}
#[cfg(feature = "local")]
pub fn new_identity(&self, _id_in: Input<I>) -> (I, Output<I>) {
let id = self.identity.lock().alloc();
(id, id)
}
#[cfg(not(feature = "local"))]
pub fn new_identity(&self, id_in: Input<I>) -> (I, Output<I>) {
//TODO: debug_assert_eq!(self.backend, id_in.backend());
(id_in, PhantomData)
}
pub fn register_identity<A: Access<T>>(
&self,
id_in: Input<I>,
value: T,
token: &mut Token<A>,
) -> Output<I> {
let (id, output) = self.new_identity(id_in);
self.register(id, value, token);
output
}
pub fn unregister<A: Access<T>>(&self, id: I, _token: &mut Token<A>) -> (T, Token<T>) {
let value = self.data.write().remove(id).unwrap();
//Note: careful about the order here!
#[cfg(feature = "local")]
self.identity.lock().free(id);
(value, Token::new())
}
pub fn read<A: Access<T>>(
&self,
_token: &mut Token<A>,
) -> (RwLockReadGuard<Storage<T, I>>, Token<T>) {
(self.data.read(), Token::new())
}
pub fn write<A: Access<T>>(
&self,
_token: &mut Token<A>,
) -> (RwLockWriteGuard<Storage<T, I>>, Token<T>) {
(self.data.write(), Token::new())
}
}
#[derive(Debug)]
pub struct Hub<B: hal::Backend> {
pub adapters: Registry<Adapter<B>, AdapterId>,
pub devices: Registry<Device<B>, DeviceId>,
pub swap_chains: Registry<SwapChain<B>, SwapChainId>,
pub pipeline_layouts: Registry<PipelineLayout<B>, PipelineLayoutId>,
pub shader_modules: Registry<ShaderModule<B>, ShaderModuleId>,
pub bind_group_layouts: Registry<BindGroupLayout<B>, BindGroupLayoutId>,
pub bind_groups: Registry<BindGroup<B>, BindGroupId>,
pub command_buffers: Registry<CommandBuffer<B>, CommandBufferId>,
pub render_passes: Registry<RenderPass<B>, RenderPassId>,
pub render_pipelines: Registry<RenderPipeline<B>, RenderPipelineId>,
pub compute_passes: Registry<ComputePass<B>, ComputePassId>,
pub compute_pipelines: Registry<ComputePipeline<B>, ComputePipelineId>,
pub buffers: Registry<Buffer<B>, BufferId>,
pub textures: Registry<Texture<B>, TextureId>,
pub texture_views: Registry<TextureView<B>, TextureViewId>,
pub samplers: Registry<Sampler<B>, SamplerId>,
}
impl<B: GfxBackend> Default for Hub<B> {
fn default() -> Self {
Hub {
adapters: Registry::new(B::VARIANT),
devices: Registry::new(B::VARIANT),
swap_chains: Registry::new(B::VARIANT),
pipeline_layouts: Registry::new(B::VARIANT),
shader_modules: Registry::new(B::VARIANT),
bind_group_layouts: Registry::new(B::VARIANT),
bind_groups: Registry::new(B::VARIANT),
command_buffers: Registry::new(B::VARIANT),
render_passes: Registry::new(B::VARIANT),
render_pipelines: Registry::new(B::VARIANT),
compute_passes: Registry::new(B::VARIANT),
compute_pipelines: Registry::new(B::VARIANT),
buffers: Registry::new(B::VARIANT),
textures: Registry::new(B::VARIANT),
texture_views: Registry::new(B::VARIANT),
samplers: Registry::new(B::VARIANT),
}
}
}
impl<B: hal::Backend> Drop for Hub<B> {
fn drop(&mut self) {
use crate::resource::TextureViewInner;
use hal::device::Device as _;
let mut devices = self.devices.data.write();
for (_, (sampler, _)) in self.samplers.data.write().map.drain() {
unsafe {
devices[sampler.device_id.value].raw.destroy_sampler(sampler.raw);
}
}
{
let textures = self.textures.data.read();
for (_, (texture_view, _)) in self.texture_views.data.write().map.drain() {
match texture_view.inner {
TextureViewInner::Native { raw, source_id } => {
let device = &devices[textures[source_id.value].device_id.value];
unsafe {
device.raw.destroy_image_view(raw);
}
}
TextureViewInner::SwapChain { .. } => {} //TODO
}
}
}
for (_, (texture, _)) in self.textures.data.write().map.drain() {
unsafe {
devices[texture.device_id.value].raw.destroy_image(texture.raw);
}
}
for (_, (buffer, _)) in self.buffers.data.write().map.drain() {
unsafe {
devices[buffer.device_id.value].raw.destroy_buffer(buffer.raw);
}
}
for (_, (command_buffer, _)) in self.command_buffers.data.write().map.drain() {
devices[command_buffer.device_id.value].com_allocator.after_submit(command_buffer, 0);
}
for (_, (bind_group, _)) in self.bind_groups.data.write().map.drain() {
let device = &devices[bind_group.device_id.value];
device.destroy_bind_group(bind_group);
}
//TODO:
// self.compute_pipelines
// self.compute_passes
// self.render_pipelines
// self.render_passes
// self.bind_group_layouts
// self.pipeline_layouts
// self.shader_modules
// self.swap_chains
// self.adapters
for (_, (device, _)) in devices.map.drain() {
device.dispose();
}
}
}
#[derive(Debug, Default)]
pub struct Hubs {
#[cfg(any(
not(any(target_os = "ios", target_os = "macos")),
feature = "gfx-backend-vulkan"
))]
vulkan: Hub<backend::Vulkan>,
#[cfg(any(target_os = "ios", target_os = "macos"))]
metal: Hub<backend::Metal>,
#[cfg(windows)]
dx12: Hub<backend::Dx12>,
#[cfg(windows)]
dx11: Hub<backend::Dx11>,
}
#[derive(Debug)]
pub struct Global {
pub instance: Instance,
pub surfaces: Registry<Surface, SurfaceId>,
hubs: Hubs,
}
impl Global {
fn new_impl(name: &str) -> Self {
Global {
instance: Instance::new(name, 1),
surfaces: Registry::new(Backend::Empty),
hubs: Hubs::default(),
}
}
#[cfg(not(feature = "local"))]
pub fn new(name: &str) -> Self {
Self::new_impl(name)
}
#[cfg(not(feature = "local"))]
pub fn delete(self) {
let Global { mut instance, surfaces, hubs } = self;
drop(hubs);
// destroy surfaces
for (_, (surface, _)) in surfaces.data.write().map.drain() {
instance.destroy_surface(surface);
}
}
}
#[cfg(feature = "local")]
lazy_static::lazy_static! {
pub static ref GLOBAL: Arc<Global> = Arc::new(Global::new_impl("wgpu"));
}
pub trait GfxBackend: hal::Backend {
const VARIANT: Backend;
fn hub(global: &Global) -> &Hub<Self>;
fn get_surface_mut(surface: &mut Surface) -> &mut Self::Surface;
}
#[cfg(any(
not(any(target_os = "ios", target_os = "macos")),
feature = "gfx-backend-vulkan"
))]
impl GfxBackend for backend::Vulkan {
const VARIANT: Backend = Backend::Vulkan;
fn hub(global: &Global) -> &Hub<Self> {
&global.hubs.vulkan
}
fn get_surface_mut(surface: &mut Surface) -> &mut Self::Surface {
surface.vulkan.as_mut().unwrap()
}
}
#[cfg(any(target_os = "ios", target_os = "macos"))]
impl GfxBackend for backend::Metal {
const VARIANT: Backend = Backend::Metal;
fn hub(global: &Global) -> &Hub<Self> {
&global.hubs.metal
}
fn get_surface_mut(surface: &mut Surface) -> &mut Self::Surface {
&mut surface.metal
}
}
#[cfg(windows)]
impl GfxBackend for backend::Dx12 {
const VARIANT: Backend = Backend::Dx12;
fn hub(global: &Global) -> &Hub<Self> {
&global.hubs.dx12
}
fn get_surface_mut(surface: &mut Surface) -> &mut Self::Surface {
surface.dx12.as_mut().unwrap()
}
}
#[cfg(windows)]
impl GfxBackend for backend::Dx11 {
const VARIANT: Backend = Backend::Dx11;
fn hub(global: &Global) -> &Hub<Self> {
&global.hubs.dx11
}
fn get_surface_mut(surface: &mut Surface) -> &mut Self::Surface {
&mut surface.dx11
}
}

View File

@ -1,142 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use crate::{Backend, Epoch, Index};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::{fmt, marker::PhantomData};
const BACKEND_BITS: usize = 3;
const EPOCH_MASK: u32 = (1 << (32 - BACKEND_BITS)) - 1;
type Dummy = crate::backend::Empty;
#[repr(transparent)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Id<T>(u64, PhantomData<T>);
impl<T> Id<T> {
pub fn backend(&self) -> Backend {
match self.0 >> (64 - BACKEND_BITS) as u8 {
0 => Backend::Empty,
1 => Backend::Vulkan,
2 => Backend::Metal,
3 => Backend::Dx12,
4 => Backend::Dx11,
5 => Backend::Gl,
_ => unreachable!(),
}
}
}
impl<T> Copy for Id<T> {}
impl<T> Clone for Id<T> {
fn clone(&self) -> Self {
Self(self.0, PhantomData)
}
}
impl<T> fmt::Debug for Id<T> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
self.unzip().fmt(formatter)
}
}
impl<T> std::hash::Hash for Id<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
impl<T> PartialEq for Id<T> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
pub trait TypedId {
fn zip(index: Index, epoch: Epoch, backend: Backend) -> Self;
fn unzip(self) -> (Index, Epoch, Backend);
}
impl<T> TypedId for Id<T> {
fn zip(index: Index, epoch: Epoch, backend: Backend) -> Self {
assert_eq!(0, epoch >> (32 - BACKEND_BITS));
let v = index as u64 | ((epoch as u64) << 32) | ((backend as u64) << (64 - BACKEND_BITS));
Id(v, PhantomData)
}
fn unzip(self) -> (Index, Epoch, Backend) {
(
self.0 as u32,
(self.0 >> 32) as u32 & EPOCH_MASK,
self.backend(),
)
}
}
#[cfg(not(feature = "local"))]
pub type Input<T> = T;
#[cfg(feature = "local")]
pub type Input<T> = PhantomData<T>;
#[cfg(feature = "local")]
pub type Output<T> = T;
#[cfg(not(feature = "local"))]
pub type Output<T> = PhantomData<T>;
pub type AdapterId = Id<crate::Adapter<Dummy>>;
pub type DeviceId = Id<crate::Device<Dummy>>;
pub type QueueId = DeviceId;
// Resource
pub type BufferId = Id<crate::Buffer<Dummy>>;
pub type TextureViewId = Id<crate::TextureView<Dummy>>;
pub type TextureId = Id<crate::Texture<Dummy>>;
pub type SamplerId = Id<crate::Sampler<Dummy>>;
// Binding model
pub type BindGroupLayoutId = Id<crate::BindGroupLayout<Dummy>>;
pub type PipelineLayoutId = Id<crate::PipelineLayout<Dummy>>;
pub type BindGroupId = Id<crate::BindGroup<Dummy>>;
// Pipeline
pub type InputStateId = Id<crate::InputState>;
pub type ShaderModuleId = Id<crate::ShaderModule<Dummy>>;
pub type RenderPipelineId = Id<crate::RenderPipeline<Dummy>>;
pub type ComputePipelineId = Id<crate::ComputePipeline<Dummy>>;
// Command
pub type CommandBufferId = Id<crate::CommandBuffer<Dummy>>;
pub type CommandEncoderId = CommandBufferId;
pub type RenderBundleId = Id<crate::RenderBundle<Dummy>>;
pub type RenderPassId = Id<crate::RenderPass<Dummy>>;
pub type ComputePassId = Id<crate::ComputePass<Dummy>>;
// Swap chain
pub type SurfaceId = Id<crate::Surface>;
pub type SwapChainId = Id<crate::SwapChain<Dummy>>;
impl SurfaceId {
pub(crate) fn to_swap_chain_id(&self, backend: Backend) -> SwapChainId {
let (index, epoch, _) = self.unzip();
Id::zip(index, epoch, backend)
}
}
impl SwapChainId {
pub(crate) fn to_surface_id(&self) -> SurfaceId {
let (index, epoch, _) = self.unzip();
Id::zip(index, epoch, Backend::Empty)
}
}
#[test]
fn test_id_backend() {
for &b in &[
Backend::Empty,
Backend::Vulkan,
Backend::Metal,
Backend::Dx12,
Backend::Dx11,
Backend::Gl,
] {
let id: Id<()> = Id::zip(0, 0, b);
assert_eq!(id.backend(), b);
}
}

View File

@ -1,563 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use crate::{
backend,
binding_model::MAX_BIND_GROUPS,
device::BIND_BUFFER_ALIGNMENT,
hub::{GfxBackend, Global, Token},
id::{Input, Output},
AdapterId,
AdapterInfo,
Backend,
Device,
DeviceId,
};
#[cfg(feature = "local")]
use crate::{gfx_select, hub::GLOBAL, SurfaceId};
#[cfg(feature = "local")]
use bitflags::bitflags;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use hal::{self, adapter::PhysicalDevice as _, queue::QueueFamily as _, Instance as _};
#[cfg(feature = "local")]
use std::marker::PhantomData;
#[derive(Debug)]
pub struct Instance {
#[cfg(any(
not(any(target_os = "ios", target_os = "macos")),
feature = "gfx-backend-vulkan"
))]
vulkan: Option<gfx_backend_vulkan::Instance>,
#[cfg(any(target_os = "ios", target_os = "macos"))]
metal: gfx_backend_metal::Instance,
#[cfg(windows)]
dx12: Option<gfx_backend_dx12::Instance>,
#[cfg(windows)]
dx11: gfx_backend_dx11::Instance,
}
impl Instance {
pub fn new(name: &str, version: u32) -> Self {
Instance {
#[cfg(any(
not(any(target_os = "ios", target_os = "macos")),
feature = "gfx-backend-vulkan"
))]
vulkan: gfx_backend_vulkan::Instance::create(name, version).ok(),
#[cfg(any(target_os = "ios", target_os = "macos"))]
metal: gfx_backend_metal::Instance::create(name, version).unwrap(),
#[cfg(windows)]
dx12: gfx_backend_dx12::Instance::create(name, version).ok(),
#[cfg(windows)]
dx11: gfx_backend_dx11::Instance::create(name, version).unwrap(),
}
}
#[cfg(not(feature = "local"))]
pub(crate) fn destroy_surface(&mut self, surface: Surface) {
//TODO: fill out the proper destruction once we are on gfx-0.4
#[cfg(any(
not(any(target_os = "ios", target_os = "macos")),
feature = "gfx-backend-vulkan"
))]
{
if let Some(_suf) = surface.vulkan {
//self.vulkan.as_mut().unwrap().destroy_surface(suf);
}
}
#[cfg(any(target_os = "ios", target_os = "macos"))]
{
let _ = surface;
//self.metal.destroy_surface(surface.metal);
}
#[cfg(windows)]
{
if let Some(_suf) = surface.dx12 {
//self.dx12.as_mut().unwrap().destroy_surface(suf);
}
//self.dx11.destroy_surface(surface.dx11);
}
}
}
type GfxSurface<B> = <B as hal::Backend>::Surface;
#[derive(Debug)]
pub struct Surface {
#[cfg(any(
not(any(target_os = "ios", target_os = "macos")),
feature = "gfx-backend-vulkan"
))]
pub(crate) vulkan: Option<GfxSurface<backend::Vulkan>>,
#[cfg(any(target_os = "ios", target_os = "macos"))]
pub(crate) metal: GfxSurface<backend::Metal>,
#[cfg(windows)]
pub(crate) dx12: Option<GfxSurface<backend::Dx12>>,
#[cfg(windows)]
pub(crate) dx11: GfxSurface<backend::Dx11>,
}
#[derive(Debug)]
pub struct Adapter<B: hal::Backend> {
pub(crate) raw: hal::adapter::Adapter<B>,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum PowerPreference {
Default = 0,
LowPower = 1,
HighPerformance = 2,
}
#[cfg(feature = "local")]
bitflags! {
#[repr(transparent)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct BackendBit: u32 {
const VULKAN = 1 << Backend::Vulkan as u32;
const GL = 1 << Backend::Gl as u32;
const METAL = 1 << Backend::Metal as u32;
const DX12 = 1 << Backend::Dx12 as u32;
const DX11 = 1 << Backend::Dx11 as u32;
/// Vulkan + METAL + DX12
const PRIMARY = Self::VULKAN.bits | Self::METAL.bits | Self::DX12.bits;
/// OpenGL + DX11
const SECONDARY = Self::GL.bits | Self::DX11.bits;
}
}
#[cfg(feature = "local")]
impl From<Backend> for BackendBit {
fn from(backend: Backend) -> Self {
BackendBit::from_bits(1 << backend as u32).unwrap()
}
}
#[repr(C)]
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct RequestAdapterOptions {
pub power_preference: PowerPreference,
#[cfg(feature = "local")]
pub backends: BackendBit,
}
impl Default for RequestAdapterOptions {
fn default() -> Self {
RequestAdapterOptions {
power_preference: PowerPreference::Default,
#[cfg(feature = "local")]
backends: BackendBit::PRIMARY,
}
}
}
#[repr(C)]
#[derive(Clone, Debug, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Extensions {
pub anisotropic_filtering: bool,
}
#[repr(C)]
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Limits {
pub max_bind_groups: u32,
}
impl Default for Limits {
fn default() -> Self {
Limits {
max_bind_groups: MAX_BIND_GROUPS as u32,
}
}
}
#[repr(C)]
#[derive(Clone, Debug, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct DeviceDescriptor {
pub extensions: Extensions,
pub limits: Limits,
}
#[cfg(feature = "local")]
pub fn wgpu_create_surface(raw_handle: raw_window_handle::RawWindowHandle) -> SurfaceId {
use raw_window_handle::RawWindowHandle as Rwh;
let instance = &GLOBAL.instance;
let surface = match raw_handle {
#[cfg(target_os = "ios")]
Rwh::IOS(h) => Surface {
#[cfg(feature = "gfx-backend-vulkan")]
vulkan: None,
metal: instance
.metal
.create_surface_from_uiview(h.ui_view, cfg!(debug_assertions)),
},
#[cfg(target_os = "macos")]
Rwh::MacOS(h) => Surface {
#[cfg(feature = "gfx-backend-vulkan")]
vulkan: instance
.vulkan
.as_ref()
.map(|inst| inst.create_surface_from_ns_view(h.ns_view)),
metal: instance
.metal
.create_surface_from_nsview(h.ns_view, cfg!(debug_assertions)),
},
#[cfg(all(unix, not(target_os = "ios"), not(target_os = "macos")))]
Rwh::Xlib(h) => Surface {
vulkan: instance
.vulkan
.as_ref()
.map(|inst| inst.create_surface_from_xlib(h.display as _, h.window as _)),
},
#[cfg(all(unix, not(target_os = "ios"), not(target_os = "macos")))]
Rwh::Wayland(h) => Surface {
vulkan: instance
.vulkan
.as_ref()
.map(|inst| inst.create_surface_from_wayland(h.display, h.surface)),
},
#[cfg(windows)]
Rwh::Windows(h) => Surface {
vulkan: instance
.vulkan
.as_ref()
.map(|inst| inst.create_surface_from_hwnd(std::ptr::null_mut(), h.hwnd)),
dx12: instance
.dx12
.as_ref()
.map(|inst| inst.create_surface_from_hwnd(h.hwnd)),
dx11: instance.dx11.create_surface_from_hwnd(h.hwnd),
},
_ => panic!("Unsupported window handle"),
};
let mut token = Token::root();
GLOBAL
.surfaces
.register_identity(PhantomData, surface, &mut token)
}
#[cfg(all(
feature = "local",
unix,
not(target_os = "ios"),
not(target_os = "macos")
))]
#[no_mangle]
pub extern "C" fn wgpu_create_surface_from_xlib(
display: *mut *const std::ffi::c_void,
window: u64,
) -> SurfaceId {
use raw_window_handle::unix::XlibHandle;
wgpu_create_surface(raw_window_handle::RawWindowHandle::Xlib(XlibHandle {
window,
display: display as *mut _,
..XlibHandle::empty()
}))
}
#[cfg(all(feature = "local", any(target_os = "ios", target_os = "macos")))]
#[no_mangle]
pub extern "C" fn wgpu_create_surface_from_metal_layer(layer: *mut std::ffi::c_void) -> SurfaceId {
let surface = Surface {
#[cfg(feature = "gfx-backend-vulkan")]
vulkan: None, //TODO: currently requires `NSView`
metal: GLOBAL
.instance
.metal
.create_surface_from_layer(layer as *mut _, cfg!(debug_assertions)),
};
GLOBAL
.surfaces
.register_identity(PhantomData, surface, &mut Token::root())
}
#[cfg(all(feature = "local", windows))]
#[no_mangle]
pub extern "C" fn wgpu_create_surface_from_windows_hwnd(
_hinstance: *mut std::ffi::c_void,
hwnd: *mut std::ffi::c_void,
) -> SurfaceId {
use raw_window_handle::windows::WindowsHandle;
wgpu_create_surface(raw_window_handle::RawWindowHandle::Windows(
raw_window_handle::windows::WindowsHandle {
hwnd,
..WindowsHandle::empty()
},
))
}
pub fn request_adapter(
global: &Global,
desc: &RequestAdapterOptions,
input_ids: &[Input<AdapterId>],
) -> Option<AdapterId> {
let instance = &global.instance;
let mut device_types = Vec::new();
#[cfg(not(feature = "local"))]
let find_input = |b: Backend| input_ids.iter().find(|id| id.backend() == b).cloned();
#[cfg(feature = "local")]
let find_input = |b: Backend| {
let _ = input_ids;
if desc.backends.contains(b.into()) {
Some(PhantomData)
} else {
None
}
};
#[cfg(not(feature = "local"))]
let pick = |_output, input_maybe| input_maybe;
#[cfg(feature = "local")]
let pick = |output, _input_maybe| Some(output);
let id_vulkan = find_input(Backend::Vulkan);
let id_metal = find_input(Backend::Metal);
let id_dx12 = find_input(Backend::Dx12);
let id_dx11 = find_input(Backend::Dx11);
#[cfg(any(
not(any(target_os = "ios", target_os = "macos")),
feature = "gfx-backend-vulkan"
))]
let mut adapters_vk = match instance.vulkan {
Some(ref inst) if id_vulkan.is_some() => {
let adapters = inst.enumerate_adapters();
device_types.extend(adapters.iter().map(|ad| ad.info.device_type.clone()));
adapters
}
_ => Vec::new(),
};
#[cfg(any(target_os = "ios", target_os = "macos"))]
let mut adapters_mtl = if id_metal.is_some() {
let adapters = instance.metal.enumerate_adapters();
device_types.extend(adapters.iter().map(|ad| ad.info.device_type.clone()));
adapters
} else {
Vec::new()
};
#[cfg(windows)]
let mut adapters_dx12 = match instance.dx12 {
Some(ref inst) if id_dx12.is_some() => {
let adapters = inst.enumerate_adapters();
device_types.extend(adapters.iter().map(|ad| ad.info.device_type.clone()));
adapters
}
_ => Vec::new(),
};
#[cfg(windows)]
let mut adapters_dx11 = if id_dx11.is_some() {
let adapters = instance.dx11.enumerate_adapters();
device_types.extend(adapters.iter().map(|ad| ad.info.device_type.clone()));
adapters
} else {
Vec::new()
};
if device_types.is_empty() {
log::warn!("No adapters are available!");
return None;
}
let (mut integrated, mut discrete, mut virt, mut other) = (None, None, None, None);
for (i, ty) in device_types.into_iter().enumerate() {
match ty {
hal::adapter::DeviceType::IntegratedGpu => {
integrated = integrated.or(Some(i));
}
hal::adapter::DeviceType::DiscreteGpu => {
discrete = discrete.or(Some(i));
}
hal::adapter::DeviceType::VirtualGpu => {
virt = virt.or(Some(i));
}
_ => {
other = other.or(Some(i));
}
}
}
let preferred_gpu = match desc.power_preference {
PowerPreference::Default => integrated.or(discrete).or(other).or(virt),
PowerPreference::LowPower => integrated.or(other).or(discrete).or(virt),
PowerPreference::HighPerformance => discrete.or(other).or(integrated).or(virt),
};
let mut token = Token::root();
let mut selected = preferred_gpu.unwrap_or(0);
#[cfg(any(
not(any(target_os = "ios", target_os = "macos")),
feature = "gfx-backend-vulkan"
))]
{
if selected < adapters_vk.len() {
let adapter = Adapter {
raw: adapters_vk.swap_remove(selected),
};
log::info!("Adapter Vulkan {:?}", adapter.raw.info);
let id_out = backend::Vulkan::hub(global).adapters.register_identity(
id_vulkan.unwrap(),
adapter,
&mut token,
);
return pick(id_out, id_vulkan);
}
selected -= adapters_vk.len();
}
#[cfg(any(target_os = "ios", target_os = "macos"))]
{
if selected < adapters_mtl.len() {
let adapter = Adapter {
raw: adapters_mtl.swap_remove(selected),
};
log::info!("Adapter Metal {:?}", adapter.raw.info);
let id_out = backend::Metal::hub(global).adapters.register_identity(
id_metal.unwrap(),
adapter,
&mut token,
);
return pick(id_out, id_metal);
}
selected -= adapters_mtl.len();
}
#[cfg(windows)]
{
if selected < adapters_dx12.len() {
let adapter = Adapter {
raw: adapters_dx12.swap_remove(selected),
};
log::info!("Adapter Dx12 {:?}", adapter.raw.info);
let id_out = backend::Dx12::hub(global).adapters.register_identity(
id_dx12.unwrap(),
adapter,
&mut token,
);
return pick(id_out, id_dx12);
}
selected -= adapters_dx12.len();
if selected < adapters_dx11.len() {
let adapter = Adapter {
raw: adapters_dx11.swap_remove(selected),
};
log::info!("Adapter Dx11 {:?}", adapter.raw.info);
let id_out = backend::Dx11::hub(global).adapters.register_identity(
id_dx11.unwrap(),
adapter,
&mut token,
);
return pick(id_out, id_dx11);
}
selected -= adapters_dx11.len();
}
let _ = (selected, id_vulkan, id_metal, id_dx12, id_dx11);
unreachable!()
}
#[cfg(feature = "local")]
#[no_mangle]
pub extern "C" fn wgpu_request_adapter(desc: Option<&RequestAdapterOptions>) -> AdapterId {
request_adapter(&*GLOBAL, &desc.cloned().unwrap_or_default(), &[]).unwrap()
}
pub fn adapter_request_device<B: GfxBackend>(
global: &Global,
adapter_id: AdapterId,
desc: &DeviceDescriptor,
id_in: Input<DeviceId>,
) -> Output<DeviceId> {
let hub = B::hub(global);
let mut token = Token::root();
let device = {
let (adapter_guard, _) = hub.adapters.read(&mut token);
let adapter = &adapter_guard[adapter_id].raw;
let family = adapter
.queue_families
.iter()
.find(|family| family.queue_type().supports_graphics())
.unwrap();
let mut gpu = unsafe {
adapter
.physical_device
.open(&[(family, &[1.0])], hal::Features::empty())
.unwrap()
};
let limits = adapter.physical_device.limits();
assert_eq!(
0,
BIND_BUFFER_ALIGNMENT % limits.min_storage_buffer_offset_alignment,
"Adapter storage buffer offset alignment not compatible with WGPU"
);
assert_eq!(
0,
BIND_BUFFER_ALIGNMENT % limits.min_uniform_buffer_offset_alignment,
"Adapter uniform buffer offset alignment not compatible with WGPU"
);
if desc.limits.max_bind_groups == 0 {
log::warn!("max_bind_groups limit is missing");
} else {
assert!(
u32::from(limits.max_bound_descriptor_sets) >= desc.limits.max_bind_groups,
"Adapter does not support the requested max_bind_groups"
);
}
let mem_props = adapter.physical_device.memory_properties();
let supports_texture_d24_s8 = adapter
.physical_device
.format_properties(Some(hal::format::Format::D24UnormS8Uint))
.optimal_tiling
.contains(hal::format::ImageFeature::DEPTH_STENCIL_ATTACHMENT);
Device::new(
gpu.device,
adapter_id,
gpu.queue_groups.swap_remove(0),
mem_props,
supports_texture_d24_s8,
desc.limits.max_bind_groups,
)
};
hub.devices.register_identity(id_in, device, &mut token)
}
#[cfg(feature = "local")]
#[no_mangle]
pub extern "C" fn wgpu_adapter_request_device(
adapter_id: AdapterId,
desc: Option<&DeviceDescriptor>,
) -> DeviceId {
let desc = &desc.cloned().unwrap_or_default();
gfx_select!(adapter_id => adapter_request_device(&*GLOBAL, adapter_id, desc, PhantomData))
}
pub fn adapter_get_info<B: GfxBackend>(global: &Global, adapter_id: AdapterId) -> AdapterInfo {
let hub = B::hub(global);
let mut token = Token::root();
let (adapter_guard, _) = hub.adapters.read(&mut token);
let adapter = &adapter_guard[adapter_id];
adapter.raw.info.clone()
}
#[cfg(feature = "local")]
pub fn wgpu_adapter_get_info(adapter_id: AdapterId) -> AdapterInfo {
gfx_select!(adapter_id => adapter_get_info(&*GLOBAL, adapter_id))
}

View File

@ -1,234 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
pub mod backend {
#[cfg(windows)]
pub use gfx_backend_dx11::Backend as Dx11;
#[cfg(windows)]
pub use gfx_backend_dx12::Backend as Dx12;
pub use gfx_backend_empty::Backend as Empty;
#[cfg(any(target_os = "ios", target_os = "macos"))]
pub use gfx_backend_metal::Backend as Metal;
#[cfg(any(
not(any(target_os = "ios", target_os = "macos")),
feature = "gfx-backend-vulkan"
))]
pub use gfx_backend_vulkan::Backend as Vulkan;
}
mod binding_model;
mod command;
mod conv;
mod device;
mod hub;
mod id;
mod instance;
mod pipeline;
mod resource;
mod swap_chain;
mod track;
pub use self::binding_model::*;
pub use self::command::*;
pub use self::device::*;
#[cfg(not(feature = "local"))]
pub use self::hub::{Access, Global, IdentityManager, Registry, Token};
pub use self::id::*;
pub use self::instance::*;
pub use self::pipeline::*;
pub use self::resource::*;
pub use self::swap_chain::*;
pub use hal::adapter::AdapterInfo;
pub use hal::pso::read_spirv;
use std::{
os::raw::c_char,
ptr,
sync::atomic::{AtomicUsize, Ordering},
};
type SubmissionIndex = usize;
type Index = u32;
type Epoch = u32;
#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Backend {
Empty = 0,
Vulkan = 1,
Metal = 2,
Dx12 = 3,
Dx11 = 4,
Gl = 5,
}
pub type BufferAddress = u64;
pub type RawString = *const c_char;
//TODO: make it private. Currently used for swapchain creation impl.
#[derive(Debug)]
pub struct RefCount(ptr::NonNull<AtomicUsize>);
unsafe impl Send for RefCount {}
unsafe impl Sync for RefCount {}
impl RefCount {
const MAX: usize = 1 << 24;
fn load(&self) -> usize {
unsafe { self.0.as_ref() }.load(Ordering::Acquire)
}
}
impl Clone for RefCount {
fn clone(&self) -> Self {
let old_size = unsafe { self.0.as_ref() }.fetch_add(1, Ordering::Relaxed);
assert!(old_size < Self::MAX);
RefCount(self.0)
}
}
impl Drop for RefCount {
fn drop(&mut self) {
if unsafe { self.0.as_ref() }.fetch_sub(1, Ordering::Relaxed) == 1 {
let _ = unsafe { Box::from_raw(self.0.as_ptr()) };
}
}
}
#[derive(Debug)]
struct LifeGuard {
ref_count: RefCount,
submission_index: AtomicUsize,
}
impl LifeGuard {
fn new() -> Self {
let bx = Box::new(AtomicUsize::new(1));
LifeGuard {
ref_count: RefCount(ptr::NonNull::new(Box::into_raw(bx)).unwrap()),
submission_index: AtomicUsize::new(0),
}
}
}
#[derive(Clone, Debug)]
struct Stored<T> {
value: T,
ref_count: RefCount,
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct Color {
pub r: f64,
pub g: f64,
pub b: f64,
pub a: f64,
}
impl Color {
pub const TRANSPARENT: Self = Color {
r: 0.0,
g: 0.0,
b: 0.0,
a: 0.0,
};
pub const BLACK: Self = Color {
r: 0.0,
g: 0.0,
b: 0.0,
a: 1.0,
};
pub const WHITE: Self = Color {
r: 1.0,
g: 1.0,
b: 1.0,
a: 1.0,
};
pub const RED: Self = Color {
r: 1.0,
g: 0.0,
b: 0.0,
a: 1.0,
};
pub const GREEN: Self = Color {
r: 0.0,
g: 1.0,
b: 0.0,
a: 1.0,
};
pub const BLUE: Self = Color {
r: 0.0,
g: 0.0,
b: 1.0,
a: 1.0,
};
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct Origin3d {
pub x: f32,
pub y: f32,
pub z: f32,
}
impl Origin3d {
pub const ZERO: Self = Origin3d {
x: 0.0,
y: 0.0,
z: 0.0,
};
}
impl Default for Origin3d {
fn default() -> Self {
Origin3d::ZERO
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct Extent3d {
pub width: u32,
pub height: u32,
pub depth: u32,
}
#[repr(C)]
#[derive(Debug)]
pub struct U32Array {
pub bytes: *const u32,
pub length: usize,
}
#[derive(Debug)]
pub enum InputState {}
#[macro_export]
macro_rules! gfx_select {
($id:expr => $function:ident( $($param:expr),+ )) => {
match $id.backend() {
#[cfg(any(not(any(target_os = "ios", target_os = "macos")), feature = "gfx-backend-vulkan"))]
$crate::Backend::Vulkan => $function::<$crate::backend::Vulkan>( $($param),+ ),
#[cfg(any(target_os = "ios", target_os = "macos"))]
$crate::Backend::Metal => $function::<$crate::backend::Metal>( $($param),+ ),
#[cfg(windows)]
$crate::Backend::Dx12 => $function::<$crate::backend::Dx12>( $($param),+ ),
#[cfg(windows)]
$crate::Backend::Dx11 => $function::<$crate::backend::Dx11>( $($param),+ ),
_ => unreachable!()
}
};
}
#[derive(Clone, Copy, Debug)]
pub(crate) struct Features {
pub max_bind_groups: u32,
pub supports_texture_d24_s8: bool,
}
/// Fast hash map used internally.
type FastHashMap<K, V> = std::collections::HashMap<K, V, std::hash::BuildHasherDefault<fxhash::FxHasher>>;

View File

@ -1,354 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use crate::{
device::RenderPassContext,
resource,
BufferAddress,
PipelineLayoutId,
RawString,
ShaderModuleId,
U32Array,
};
use bitflags::bitflags;
pub type ShaderLocation = u32;
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum BlendFactor {
Zero = 0,
One = 1,
SrcColor = 2,
OneMinusSrcColor = 3,
SrcAlpha = 4,
OneMinusSrcAlpha = 5,
DstColor = 6,
OneMinusDstColor = 7,
DstAlpha = 8,
OneMinusDstAlpha = 9,
SrcAlphaSaturated = 10,
BlendColor = 11,
OneMinusBlendColor = 12,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum BlendOperation {
Add = 0,
Subtract = 1,
ReverseSubtract = 2,
Min = 3,
Max = 4,
}
impl Default for BlendOperation {
fn default() -> Self {
BlendOperation::Add
}
}
bitflags! {
#[repr(transparent)]
pub struct ColorWrite: u32 {
const RED = 1;
const GREEN = 2;
const BLUE = 4;
const ALPHA = 8;
const COLOR = 7;
const ALL = 15;
}
}
impl Default for ColorWrite {
fn default() -> Self {
ColorWrite::ALL
}
}
#[repr(C)]
#[derive(Clone, Debug, PartialEq)]
pub struct BlendDescriptor {
pub src_factor: BlendFactor,
pub dst_factor: BlendFactor,
pub operation: BlendOperation,
}
impl BlendDescriptor {
pub const REPLACE: Self = BlendDescriptor {
src_factor: BlendFactor::One,
dst_factor: BlendFactor::Zero,
operation: BlendOperation::Add,
};
pub fn uses_color(&self) -> bool {
match (self.src_factor, self.dst_factor) {
(BlendFactor::BlendColor, _)
| (BlendFactor::OneMinusBlendColor, _)
| (_, BlendFactor::BlendColor)
| (_, BlendFactor::OneMinusBlendColor) => true,
(_, _) => false,
}
}
}
impl Default for BlendDescriptor {
fn default() -> Self {
BlendDescriptor::REPLACE
}
}
#[repr(C)]
#[derive(Clone, Debug)]
pub struct ColorStateDescriptor {
pub format: resource::TextureFormat,
pub alpha_blend: BlendDescriptor,
pub color_blend: BlendDescriptor,
pub write_mask: ColorWrite,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum StencilOperation {
Keep = 0,
Zero = 1,
Replace = 2,
Invert = 3,
IncrementClamp = 4,
DecrementClamp = 5,
IncrementWrap = 6,
DecrementWrap = 7,
}
impl Default for StencilOperation {
fn default() -> Self {
StencilOperation::Keep
}
}
#[repr(C)]
#[derive(Clone, Debug, PartialEq)]
pub struct StencilStateFaceDescriptor {
pub compare: resource::CompareFunction,
pub fail_op: StencilOperation,
pub depth_fail_op: StencilOperation,
pub pass_op: StencilOperation,
}
impl StencilStateFaceDescriptor {
pub const IGNORE: Self = StencilStateFaceDescriptor {
compare: resource::CompareFunction::Always,
fail_op: StencilOperation::Keep,
depth_fail_op: StencilOperation::Keep,
pass_op: StencilOperation::Keep,
};
}
impl Default for StencilStateFaceDescriptor {
fn default() -> Self {
StencilStateFaceDescriptor::IGNORE
}
}
#[repr(C)]
#[derive(Clone, Debug)]
pub struct DepthStencilStateDescriptor {
pub format: resource::TextureFormat,
pub depth_write_enabled: bool,
pub depth_compare: resource::CompareFunction,
pub stencil_front: StencilStateFaceDescriptor,
pub stencil_back: StencilStateFaceDescriptor,
pub stencil_read_mask: u32,
pub stencil_write_mask: u32,
}
impl DepthStencilStateDescriptor {
pub fn needs_stencil_reference(&self) -> bool {
!self.stencil_front.compare.is_trivial() || !self.stencil_back.compare.is_trivial()
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum IndexFormat {
Uint16 = 0,
Uint32 = 1,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum VertexFormat {
Uchar2 = 1,
Uchar4 = 3,
Char2 = 5,
Char4 = 7,
Uchar2Norm = 9,
Uchar4Norm = 11,
Char2Norm = 14,
Char4Norm = 16,
Ushort2 = 18,
Ushort4 = 20,
Short2 = 22,
Short4 = 24,
Ushort2Norm = 26,
Ushort4Norm = 28,
Short2Norm = 30,
Short4Norm = 32,
Half2 = 34,
Half4 = 36,
Float = 37,
Float2 = 38,
Float3 = 39,
Float4 = 40,
Uint = 41,
Uint2 = 42,
Uint3 = 43,
Uint4 = 44,
Int = 45,
Int2 = 46,
Int3 = 47,
Int4 = 48,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum InputStepMode {
Vertex = 0,
Instance = 1,
}
#[repr(C)]
#[derive(Clone, Debug)]
pub struct VertexAttributeDescriptor {
pub offset: BufferAddress,
pub format: VertexFormat,
pub shader_location: ShaderLocation,
}
#[repr(C)]
#[derive(Debug)]
pub struct VertexBufferDescriptor {
pub stride: BufferAddress,
pub step_mode: InputStepMode,
pub attributes: *const VertexAttributeDescriptor,
pub attributes_length: usize,
}
#[repr(C)]
#[derive(Debug)]
pub struct VertexInputDescriptor {
pub index_format: IndexFormat,
pub vertex_buffers: *const VertexBufferDescriptor,
pub vertex_buffers_length: usize,
}
#[repr(C)]
#[derive(Debug)]
pub struct ShaderModuleDescriptor {
pub code: U32Array,
}
#[repr(C)]
#[derive(Debug)]
pub struct ProgrammableStageDescriptor {
pub module: ShaderModuleId,
pub entry_point: RawString,
}
#[repr(C)]
#[derive(Debug)]
pub struct ComputePipelineDescriptor {
pub layout: PipelineLayoutId,
pub compute_stage: ProgrammableStageDescriptor,
}
#[derive(Debug)]
pub struct ComputePipeline<B: hal::Backend> {
pub(crate) raw: B::ComputePipeline,
pub(crate) layout_id: PipelineLayoutId,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum PrimitiveTopology {
PointList = 0,
LineList = 1,
LineStrip = 2,
TriangleList = 3,
TriangleStrip = 4,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum FrontFace {
Ccw = 0,
Cw = 1,
}
impl Default for FrontFace {
fn default() -> Self {
FrontFace::Ccw
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum CullMode {
None = 0,
Front = 1,
Back = 2,
}
impl Default for CullMode {
fn default() -> Self {
CullMode::None
}
}
#[repr(C)]
#[derive(Clone, Debug, Default)]
pub struct RasterizationStateDescriptor {
pub front_face: FrontFace,
pub cull_mode: CullMode,
pub depth_bias: i32,
pub depth_bias_slope_scale: f32,
pub depth_bias_clamp: f32,
}
#[repr(C)]
#[derive(Debug)]
pub struct RenderPipelineDescriptor {
pub layout: PipelineLayoutId,
pub vertex_stage: ProgrammableStageDescriptor,
pub fragment_stage: *const ProgrammableStageDescriptor,
pub primitive_topology: PrimitiveTopology,
pub rasterization_state: *const RasterizationStateDescriptor,
pub color_states: *const ColorStateDescriptor,
pub color_states_length: usize,
pub depth_stencil_state: *const DepthStencilStateDescriptor,
pub vertex_input: VertexInputDescriptor,
pub sample_count: u32,
pub sample_mask: u32,
pub alpha_to_coverage_enabled: bool,
}
bitflags! {
#[repr(transparent)]
pub struct PipelineFlags: u32 {
const BLEND_COLOR = 1;
const STENCIL_REFERENCE = 2;
}
}
#[derive(Debug)]
pub struct RenderPipeline<B: hal::Backend> {
pub(crate) raw: B::GraphicsPipeline,
pub(crate) layout_id: PipelineLayoutId,
pub(crate) pass_context: RenderPassContext,
pub(crate) flags: PipelineFlags,
pub(crate) index_format: IndexFormat,
pub(crate) sample_count: u8,
pub(crate) vertex_strides: Vec<(BufferAddress, InputStepMode)>,
}

View File

@ -1,373 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use crate::{
BufferAddress,
BufferMapReadCallback,
BufferMapWriteCallback,
DeviceId,
Extent3d,
LifeGuard,
RefCount,
Stored,
SwapChainId,
TextureId,
};
use bitflags::bitflags;
use hal;
use rendy_memory::MemoryBlock;
use smallvec::SmallVec;
use std::borrow::Borrow;
bitflags! {
#[repr(transparent)]
pub struct BufferUsage: u32 {
const MAP_READ = 1;
const MAP_WRITE = 2;
const COPY_SRC = 4;
const COPY_DST = 8;
const INDEX = 16;
const VERTEX = 32;
const UNIFORM = 64;
const STORAGE = 128;
const STORAGE_READ = 256;
const INDIRECT = 512;
const NONE = 0;
/// The combination of all read-only usages.
const READ_ALL = Self::MAP_READ.bits | Self::COPY_SRC.bits |
Self::INDEX.bits | Self::VERTEX.bits | Self::UNIFORM.bits |
Self::STORAGE_READ.bits | Self::INDIRECT.bits;
/// The combination of all write-only and read-write usages.
const WRITE_ALL = Self::MAP_WRITE.bits | Self::COPY_DST.bits | Self::STORAGE.bits;
/// The combination of all usages that the are guaranteed to be be ordered by the hardware.
/// If a usage is not ordered, then even if it doesn't change between draw calls, there
/// still need to be pipeline barriers inserted for synchronization.
const ORDERED = Self::READ_ALL.bits;
}
}
#[repr(C)]
#[derive(Clone, Debug)]
pub struct BufferDescriptor {
pub size: BufferAddress,
pub usage: BufferUsage,
}
#[repr(C)]
#[derive(Debug)]
pub enum BufferMapAsyncStatus {
Success,
Error,
Unknown,
ContextLost,
}
#[derive(Clone, Debug)]
pub enum BufferMapOperation {
Read(std::ops::Range<u64>, BufferMapReadCallback, *mut u8),
Write(std::ops::Range<u64>, BufferMapWriteCallback, *mut u8),
}
unsafe impl Send for BufferMapOperation {}
unsafe impl Sync for BufferMapOperation {}
impl BufferMapOperation {
pub(crate) fn call_error(self) {
match self {
BufferMapOperation::Read(_, callback, userdata) => {
log::error!("wgpu_buffer_map_read_async failed: buffer mapping is pending");
callback(BufferMapAsyncStatus::Error, std::ptr::null_mut(), userdata);
}
BufferMapOperation::Write(_, callback, userdata) => {
log::error!("wgpu_buffer_map_write_async failed: buffer mapping is pending");
callback(BufferMapAsyncStatus::Error, std::ptr::null_mut(), userdata);
}
}
}
}
#[derive(Debug)]
pub struct Buffer<B: hal::Backend> {
pub(crate) raw: B::Buffer,
pub(crate) device_id: Stored<DeviceId>,
pub(crate) usage: BufferUsage,
pub(crate) memory: MemoryBlock<B>,
pub(crate) size: BufferAddress,
pub(crate) mapped_write_ranges: Vec<std::ops::Range<u64>>,
pub(crate) pending_map_operation: Option<BufferMapOperation>,
pub(crate) life_guard: LifeGuard,
}
impl<B: hal::Backend> Borrow<RefCount> for Buffer<B> {
fn borrow(&self) -> &RefCount {
&self.life_guard.ref_count
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum TextureDimension {
D1,
D2,
D3,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum TextureFormat {
// Normal 8 bit formats
R8Unorm = 0,
R8Snorm = 1,
R8Uint = 2,
R8Sint = 3,
// Normal 16 bit formats
R16Unorm = 4,
R16Snorm = 5,
R16Uint = 6,
R16Sint = 7,
R16Float = 8,
Rg8Unorm = 9,
Rg8Snorm = 10,
Rg8Uint = 11,
Rg8Sint = 12,
// Normal 32 bit formats
R32Uint = 13,
R32Sint = 14,
R32Float = 15,
Rg16Unorm = 16,
Rg16Snorm = 17,
Rg16Uint = 18,
Rg16Sint = 19,
Rg16Float = 20,
Rgba8Unorm = 21,
Rgba8UnormSrgb = 22,
Rgba8Snorm = 23,
Rgba8Uint = 24,
Rgba8Sint = 25,
Bgra8Unorm = 26,
Bgra8UnormSrgb = 27,
// Packed 32 bit formats
Rgb10a2Unorm = 28,
Rg11b10Float = 29,
// Normal 64 bit formats
Rg32Uint = 30,
Rg32Sint = 31,
Rg32Float = 32,
Rgba16Unorm = 33,
Rgba16Snorm = 34,
Rgba16Uint = 35,
Rgba16Sint = 36,
Rgba16Float = 37,
// Normal 128 bit formats
Rgba32Uint = 38,
Rgba32Sint = 39,
Rgba32Float = 40,
// Depth and stencil formats
Depth32Float = 41,
Depth24Plus = 42,
Depth24PlusStencil8 = 43,
}
bitflags! {
#[repr(transparent)]
pub struct TextureUsage: u32 {
const COPY_SRC = 1;
const COPY_DST = 2;
const SAMPLED = 4;
const STORAGE = 8;
const OUTPUT_ATTACHMENT = 16;
const NONE = 0;
/// The combination of all read-only usages.
const READ_ALL = Self::COPY_SRC.bits | Self::SAMPLED.bits;
/// The combination of all write-only and read-write usages.
const WRITE_ALL = Self::COPY_DST.bits | Self::STORAGE.bits | Self::OUTPUT_ATTACHMENT.bits;
/// The combination of all usages that the are guaranteed to be be ordered by the hardware.
/// If a usage is not ordered, then even if it doesn't change between draw calls, there
/// still need to be pipeline barriers inserted for synchronization.
const ORDERED = Self::READ_ALL.bits | Self::OUTPUT_ATTACHMENT.bits;
const UNINITIALIZED = 0xFFFF;
}
}
#[repr(C)]
#[derive(Debug)]
pub struct TextureDescriptor {
pub size: Extent3d,
pub array_layer_count: u32,
pub mip_level_count: u32,
pub sample_count: u32,
pub dimension: TextureDimension,
pub format: TextureFormat,
pub usage: TextureUsage,
}
#[derive(Debug)]
pub struct Texture<B: hal::Backend> {
pub(crate) raw: B::Image,
pub(crate) device_id: Stored<DeviceId>,
pub(crate) usage: TextureUsage,
pub(crate) kind: hal::image::Kind,
pub(crate) format: TextureFormat,
pub(crate) full_range: hal::image::SubresourceRange,
pub(crate) memory: MemoryBlock<B>,
pub(crate) life_guard: LifeGuard,
}
impl<B: hal::Backend> Borrow<RefCount> for Texture<B> {
fn borrow(&self) -> &RefCount {
&self.life_guard.ref_count
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum TextureAspect {
All,
StencilOnly,
DepthOnly,
}
impl Default for TextureAspect {
fn default() -> Self {
TextureAspect::All
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum TextureViewDimension {
D1,
D2,
D2Array,
Cube,
CubeArray,
D3,
}
#[repr(C)]
#[derive(Debug)]
pub struct TextureViewDescriptor {
pub format: TextureFormat,
pub dimension: TextureViewDimension,
pub aspect: TextureAspect,
pub base_mip_level: u32,
pub level_count: u32,
pub base_array_layer: u32,
pub array_layer_count: u32,
}
#[derive(Debug)]
pub(crate) enum TextureViewInner<B: hal::Backend> {
Native {
raw: B::ImageView,
source_id: Stored<TextureId>,
},
SwapChain {
image: <B::Surface as hal::window::PresentationSurface<B>>::SwapchainImage,
source_id: Stored<SwapChainId>,
framebuffers: SmallVec<[B::Framebuffer; 1]>,
},
}
#[derive(Debug)]
pub struct TextureView<B: hal::Backend> {
pub(crate) inner: TextureViewInner<B>,
//TODO: store device_id for quick access?
pub(crate) format: TextureFormat,
pub(crate) extent: hal::image::Extent,
pub(crate) samples: hal::image::NumSamples,
pub(crate) range: hal::image::SubresourceRange,
pub(crate) life_guard: LifeGuard,
}
impl<B: hal::Backend> Borrow<RefCount> for TextureView<B> {
fn borrow(&self) -> &RefCount {
&self.life_guard.ref_count
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum AddressMode {
ClampToEdge = 0,
Repeat = 1,
MirrorRepeat = 2,
}
impl Default for AddressMode {
fn default() -> Self {
AddressMode::ClampToEdge
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum FilterMode {
Nearest = 0,
Linear = 1,
}
impl Default for FilterMode {
fn default() -> Self {
FilterMode::Nearest
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum CompareFunction {
Never = 0,
Less = 1,
Equal = 2,
LessEqual = 3,
Greater = 4,
NotEqual = 5,
GreaterEqual = 6,
Always = 7,
}
impl CompareFunction {
pub fn is_trivial(&self) -> bool {
match *self {
CompareFunction::Never | CompareFunction::Always => true,
_ => false,
}
}
}
#[repr(C)]
#[derive(Debug)]
pub struct SamplerDescriptor {
pub address_mode_u: AddressMode,
pub address_mode_v: AddressMode,
pub address_mode_w: AddressMode,
pub mag_filter: FilterMode,
pub min_filter: FilterMode,
pub mipmap_filter: FilterMode,
pub lod_min_clamp: f32,
pub lod_max_clamp: f32,
pub compare_function: CompareFunction,
}
#[derive(Debug)]
pub struct Sampler<B: hal::Backend> {
pub(crate) raw: B::Sampler,
pub(crate) device_id: Stored<DeviceId>,
pub(crate) life_guard: LifeGuard,
}
impl<B: hal::Backend> Borrow<RefCount> for Sampler<B> {
fn borrow(&self) -> &RefCount {
&self.life_guard.ref_count
}
}

View File

@ -1,254 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*! Swap chain management.
## Lifecycle
At the low level, the swap chain is using the new simplified model of gfx-rs.
A swap chain is a separate object that is backend-dependent but shares the index with
the parent surface, which is backend-independent. This ensures a 1:1 correspondence
between them.
`get_next_image()` requests a new image from the surface. It becomes a part of
`TextureViewInner::SwapChain` of the resulted view. The view is registered in the HUB
but not in the device tracker.
The only operation allowed on the view is to be either a color or a resolve attachment.
It can only be used in one command buffer, which needs to be submitted before presenting.
Command buffer tracker knows about the view, but only for the duration of recording.
The view ID is erased from it at the end, so that it's not merged into the device tracker.
When a swapchain view is used in `begin_render_pass()`, we assume the start and end image
layouts purely based on whether or not this view was used in this command buffer before.
It always starts with `Uninitialized` and ends with `Present`, so that no barriers are
needed when we need to actually present it.
In `queue_submit()` we make sure to signal the semaphore whenever we render to a swap
chain view.
In `present()` we return the swap chain image back and wait on the semaphore.
!*/
use crate::{
conv,
hub::{GfxBackend, Global, Token},
resource,
DeviceId,
Extent3d,
Features,
Input,
LifeGuard,
Stored,
SwapChainId,
TextureViewId,
};
#[cfg(feature = "local")]
use crate::{gfx_select, hub::GLOBAL};
use hal::{self, device::Device as _, queue::CommandQueue as _, window::PresentationSurface as _};
use smallvec::SmallVec;
#[cfg(feature = "local")]
use std::marker::PhantomData;
const FRAME_TIMEOUT_MS: u64 = 1000;
pub const DESIRED_NUM_FRAMES: u32 = 3;
#[derive(Debug)]
pub struct SwapChain<B: hal::Backend> {
pub(crate) life_guard: LifeGuard,
pub(crate) device_id: Stored<DeviceId>,
pub(crate) desc: SwapChainDescriptor,
pub(crate) num_frames: hal::window::SwapImageIndex,
pub(crate) semaphore: B::Semaphore,
pub(crate) acquired_view_id: Option<Stored<TextureViewId>>,
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub enum PresentMode {
NoVsync = 0,
Vsync = 1,
}
#[repr(C)]
#[derive(Clone, Debug)]
pub struct SwapChainDescriptor {
pub usage: resource::TextureUsage,
pub format: resource::TextureFormat,
pub width: u32,
pub height: u32,
pub present_mode: PresentMode,
}
impl SwapChainDescriptor {
pub(crate) fn to_hal(
&self,
num_frames: u32,
features: &Features,
) -> hal::window::SwapchainConfig {
let mut config = hal::window::SwapchainConfig::new(
self.width,
self.height,
conv::map_texture_format(self.format, *features),
num_frames,
);
//TODO: check for supported
config.image_usage = conv::map_texture_usage(self.usage, hal::format::Aspects::COLOR);
config.composite_alpha_mode = hal::window::CompositeAlphaMode::OPAQUE;
config.present_mode = match self.present_mode {
PresentMode::NoVsync => hal::window::PresentMode::IMMEDIATE,
PresentMode::Vsync => hal::window::PresentMode::FIFO,
};
config
}
pub fn to_texture_desc(&self) -> resource::TextureDescriptor {
resource::TextureDescriptor {
size: Extent3d {
width: self.width,
height: self.height,
depth: 1,
},
mip_level_count: 1,
array_layer_count: 1,
sample_count: 1,
dimension: resource::TextureDimension::D2,
format: self.format,
usage: self.usage,
}
}
}
#[repr(C)]
#[derive(Debug)]
pub struct SwapChainOutput {
pub view_id: TextureViewId,
}
pub fn swap_chain_get_next_texture<B: GfxBackend>(
global: &Global,
swap_chain_id: SwapChainId,
view_id_in: Input<TextureViewId>,
) -> SwapChainOutput {
let hub = B::hub(global);
let mut token = Token::root();
let (mut surface_guard, mut token) = global.surfaces.write(&mut token);
let surface = &mut surface_guard[swap_chain_id.to_surface_id()];
let (device_guard, mut token) = hub.devices.read(&mut token);
let (mut swap_chain_guard, mut token) = hub.swap_chains.write(&mut token);
let sc = &mut swap_chain_guard[swap_chain_id];
let device = &device_guard[sc.device_id.value];
let (image, _) = {
let suf = B::get_surface_mut(surface);
match unsafe { suf.acquire_image(FRAME_TIMEOUT_MS * 1_000_000) } {
Ok(surface_image) => surface_image,
Err(hal::window::AcquireError::Timeout) => {
panic!("GPU took too much time processing last frames :(");
}
Err(e) => {
log::warn!("acquire_image() failed ({:?}), reconfiguring swapchain", e);
let desc = sc.desc.to_hal(sc.num_frames, &device.features);
unsafe {
suf.configure_swapchain(&device.raw, desc).unwrap();
suf.acquire_image(FRAME_TIMEOUT_MS * 1_000_000).unwrap()
}
}
}
};
let view = resource::TextureView {
inner: resource::TextureViewInner::SwapChain {
image,
source_id: Stored {
value: swap_chain_id,
ref_count: sc.life_guard.ref_count.clone(),
},
framebuffers: SmallVec::new(),
},
format: sc.desc.format,
extent: hal::image::Extent {
width: sc.desc.width,
height: sc.desc.height,
depth: 1,
},
samples: 1,
range: hal::image::SubresourceRange {
aspects: hal::format::Aspects::COLOR,
layers: 0 .. 1,
levels: 0 .. 1,
},
life_guard: LifeGuard::new(),
};
let ref_count = view.life_guard.ref_count.clone();
let (view_id, _) = hub.texture_views.new_identity(view_id_in);
hub.texture_views.register(view_id, view, &mut token);
assert!(
sc.acquired_view_id.is_none(),
"Swap chain image is already acquired"
);
sc.acquired_view_id = Some(Stored {
value: view_id,
ref_count,
});
SwapChainOutput { view_id }
}
#[cfg(feature = "local")]
#[no_mangle]
pub extern "C" fn wgpu_swap_chain_get_next_texture(swap_chain_id: SwapChainId) -> SwapChainOutput {
gfx_select!(swap_chain_id => swap_chain_get_next_texture(&*GLOBAL, swap_chain_id, PhantomData))
}
pub fn swap_chain_present<B: GfxBackend>(global: &Global, swap_chain_id: SwapChainId) {
let hub = B::hub(global);
let mut token = Token::root();
let (mut surface_guard, mut token) = global.surfaces.write(&mut token);
let surface = &mut surface_guard[swap_chain_id.to_surface_id()];
let (mut device_guard, mut token) = hub.devices.write(&mut token);
let (mut swap_chain_guard, mut token) = hub.swap_chains.write(&mut token);
let sc = &mut swap_chain_guard[swap_chain_id];
let device = &mut device_guard[sc.device_id.value];
let view_id = sc
.acquired_view_id
.take()
.expect("Swap chain image is not acquired");
let (view, _) = hub.texture_views.unregister(view_id.value, &mut token);
let (image, framebuffers) = match view.inner {
resource::TextureViewInner::Native { .. } => unreachable!(),
resource::TextureViewInner::SwapChain {
image, framebuffers, ..
} => (image, framebuffers),
};
let err = unsafe {
let queue = &mut device.queue_group.queues[0];
queue.present_surface(B::get_surface_mut(surface), image, Some(&sc.semaphore))
};
if let Err(e) = err {
log::warn!("present failed: {:?}", e);
}
for fbo in framebuffers {
unsafe {
device.raw.destroy_framebuffer(fbo);
}
}
}
#[cfg(feature = "local")]
#[no_mangle]
pub extern "C" fn wgpu_swap_chain_present(swap_chain_id: SwapChainId) {
gfx_select!(swap_chain_id => swap_chain_present(&*GLOBAL, swap_chain_id))
}

View File

@ -1,124 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use super::{PendingTransition, ResourceState, Stitch, Unit};
use crate::{conv, resource::BufferUsage, BufferId};
use std::ops::Range;
//TODO: store `hal::buffer::State` here to avoid extra conversions
pub type BufferState = Unit<BufferUsage>;
impl PendingTransition<BufferState> {
/// Produce the gfx-hal buffer states corresponding to the transition.
pub fn to_states(&self) -> Range<hal::buffer::State> {
conv::map_buffer_state(self.usage.start) .. conv::map_buffer_state(self.usage.end)
}
}
impl Default for BufferState {
fn default() -> Self {
BufferState {
init: BufferUsage::empty(),
last: BufferUsage::empty(),
}
}
}
impl ResourceState for BufferState {
type Id = BufferId;
type Selector = ();
type Usage = BufferUsage;
fn query(&self, _selector: Self::Selector) -> Option<Self::Usage> {
Some(self.last)
}
fn change(
&mut self,
id: Self::Id,
_selector: Self::Selector,
usage: Self::Usage,
output: Option<&mut Vec<PendingTransition<Self>>>,
) -> Result<(), PendingTransition<Self>> {
let old = self.last;
if usage != old || !BufferUsage::ORDERED.contains(usage) {
let pending = PendingTransition {
id,
selector: (),
usage: old .. usage,
};
self.last = match output {
Some(transitions) => {
transitions.push(pending);
usage
}
None => {
if !old.is_empty()
&& old != usage
&& BufferUsage::WRITE_ALL.intersects(old | usage)
{
return Err(pending);
}
old | usage
}
};
}
Ok(())
}
fn merge(
&mut self,
id: Self::Id,
other: &Self,
stitch: Stitch,
output: Option<&mut Vec<PendingTransition<Self>>>,
) -> Result<(), PendingTransition<Self>> {
let old = self.last;
let new = other.select(stitch);
self.last = if old == new && BufferUsage::ORDERED.contains(new) {
other.last
} else {
let pending = PendingTransition {
id,
selector: (),
usage: old .. new,
};
match output {
Some(transitions) => {
transitions.push(pending);
other.last
}
None => {
if !old.is_empty() && BufferUsage::WRITE_ALL.intersects(old | new) {
return Err(pending);
}
old | new
}
}
};
Ok(())
}
fn optimize(&mut self) {}
}
#[cfg(test)]
mod test {
use super::*;
use crate::{Backend, TypedId};
#[test]
fn change() {
let mut bs = Unit {
init: BufferUsage::INDEX,
last: BufferUsage::STORAGE,
};
let id = TypedId::zip(0, 0, Backend::Empty);
assert!(bs.change(id, (), BufferUsage::VERTEX, None).is_err());
bs.change(id, (), BufferUsage::VERTEX, Some(&mut Vec::new()))
.unwrap();
bs.change(id, (), BufferUsage::INDEX, None).unwrap();
assert_eq!(bs.last, BufferUsage::VERTEX | BufferUsage::INDEX);
}
}

View File

@ -1,472 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
mod buffer;
mod range;
mod texture;
use crate::{
hub::Storage,
Backend,
BindGroupId,
Epoch,
FastHashMap,
Index,
RefCount,
SamplerId,
TextureViewId,
TypedId,
};
use std::{
borrow::Borrow,
collections::hash_map::Entry,
fmt::Debug,
marker::PhantomData,
ops::Range,
vec::Drain,
};
use buffer::BufferState;
use texture::TextureState;
/// A single unit of state tracking. It keeps an initial
/// usage as well as the last/current one, similar to `Range`.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Unit<U> {
init: U,
last: U,
}
impl<U: Copy> Unit<U> {
/// Create a new unit from a given usage.
fn new(usage: U) -> Self {
Unit {
init: usage,
last: usage,
}
}
/// Select one of the ends of the usage, based on the
/// given `Stitch`.
///
/// In some scenarios, when merging two trackers
/// A and B for a resource, we want to connect A to the initial state
/// of B. In other scenarios, we want to reach the last state of B.
fn select(&self, stitch: Stitch) -> U {
match stitch {
Stitch::Init => self.init,
Stitch::Last => self.last,
}
}
}
/// Mode of stitching to states together.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Stitch {
/// Stitch to the init state of the other resource.
Init,
/// Stitch to the last state of the other resource.
Last,
}
/// The main trait that abstracts away the tracking logic of
/// a particular resource type, like a buffer or a texture.
pub trait ResourceState: Clone + Default {
/// Corresponding `HUB` identifier.
type Id: Copy + Debug + TypedId;
/// A type specifying the sub-resources.
type Selector: Debug;
/// Usage type for a `Unit` of a sub-resource.
type Usage: Debug;
/// Check if all the selected sub-resources have the same
/// usage, and return it.
///
/// Returns `None` if no sub-resources
/// are intersecting with the selector, or their usage
/// isn't consistent.
fn query(&self, selector: Self::Selector) -> Option<Self::Usage>;
/// Change the last usage of the selected sub-resources.
///
/// If `output` is specified, it's filled with the
/// `PendingTransition` objects corresponding to smaller
/// sub-resource transitions. The old usage is replaced by
/// the new one.
///
/// If `output` is `None`, the old usage is extended with
/// the new usage. The error is returned if it's not possible,
/// specifying the conflicting transition. Extension can only
/// be done for read-only usages.
fn change(
&mut self,
id: Self::Id,
selector: Self::Selector,
usage: Self::Usage,
output: Option<&mut Vec<PendingTransition<Self>>>,
) -> Result<(), PendingTransition<Self>>;
/// Merge the state of this resource tracked by a different instance
/// with the current one.
///
/// Same rules for `output` apply as with `change()`: last usage state
/// is either replaced (when `output` is provided) with a
/// `PendingTransition` pushed to this vector, or extended with the
/// other read-only usage, unless there is a usage conflict, and
/// the error is generated (returning the conflict).
///
/// `stitch` only defines the end points of generated transitions.
/// Last states of `self` are nevertheless updated to the *last* states
/// of `other`, if `output` is provided.
fn merge(
&mut self,
id: Self::Id,
other: &Self,
stitch: Stitch,
output: Option<&mut Vec<PendingTransition<Self>>>,
) -> Result<(), PendingTransition<Self>>;
/// Try to optimize the internal representation.
fn optimize(&mut self);
}
/// Structure wrapping the abstract tracking state with the relevant resource
/// data, such as the reference count and the epoch.
#[derive(Clone, Debug)]
struct Resource<S> {
ref_count: RefCount,
state: S,
epoch: Epoch,
}
/// A structure containing all the information about a particular resource
/// transition. User code should be able to generate a pipeline barrier
/// based on the contents.
#[derive(Debug)]
pub struct PendingTransition<S: ResourceState> {
pub id: S::Id,
pub selector: S::Selector,
pub usage: Range<S::Usage>,
}
/// A tracker for all resources of a given type.
#[derive(Debug)]
pub struct ResourceTracker<S: ResourceState> {
/// An association of known resource indices with their tracked states.
map: FastHashMap<Index, Resource<S>>,
/// Temporary storage for collecting transitions.
temp: Vec<PendingTransition<S>>,
/// The backend variant for all the tracked resources.
backend: Backend,
}
impl<S: ResourceState> ResourceTracker<S> {
/// Create a new empty tracker.
pub fn new(backend: Backend) -> Self {
ResourceTracker {
map: FastHashMap::default(),
temp: Vec::new(),
backend,
}
}
/// Remove an id from the tracked map.
pub fn remove(&mut self, id: S::Id) -> bool {
let (index, epoch, backend) = id.unzip();
debug_assert_eq!(backend, self.backend);
match self.map.remove(&index) {
Some(resource) => {
assert_eq!(resource.epoch, epoch);
true
}
None => false,
}
}
/// Try to optimize the internal representation.
pub fn optimize(&mut self) {
for resource in self.map.values_mut() {
resource.state.optimize();
}
}
/// Return an iterator over used resources keys.
pub fn used<'a>(&'a self) -> impl 'a + Iterator<Item = S::Id> {
let backend = self.backend;
self.map
.iter()
.map(move |(&index, resource)| S::Id::zip(index, resource.epoch, backend))
}
/// Clear the tracked contents.
fn clear(&mut self) {
self.map.clear();
}
/// Initialize a resource to be used.
///
/// Returns `false` if the resource is already tracked.
pub fn init(
&mut self,
id: S::Id,
ref_count: &RefCount,
selector: S::Selector,
default: S::Usage,
) -> bool {
let mut state = S::default();
match state.change(id, selector, default, None) {
Ok(()) => (),
Err(_) => unreachable!(),
}
let (index, epoch, backend) = id.unzip();
debug_assert_eq!(backend, self.backend);
self.map
.insert(
index,
Resource {
ref_count: ref_count.clone(),
state,
epoch,
},
)
.is_none()
}
/// Query the usage of a resource selector.
///
/// Returns `Some(Usage)` only if this usage is consistent
/// across the given selector.
pub fn query(&mut self, id: S::Id, selector: S::Selector) -> Option<S::Usage> {
let (index, epoch, backend) = id.unzip();
debug_assert_eq!(backend, self.backend);
let res = self.map.get(&index)?;
assert_eq!(res.epoch, epoch);
res.state.query(selector)
}
/// Make sure that a resource is tracked, and return a mutable
/// reference to it.
fn get_or_insert<'a>(
self_backend: Backend,
map: &'a mut FastHashMap<Index, Resource<S>>,
id: S::Id,
ref_count: &RefCount,
) -> &'a mut Resource<S> {
let (index, epoch, backend) = id.unzip();
debug_assert_eq!(self_backend, backend);
match map.entry(index) {
Entry::Vacant(e) => e.insert(Resource {
ref_count: ref_count.clone(),
state: S::default(),
epoch,
}),
Entry::Occupied(e) => {
assert_eq!(e.get().epoch, epoch);
e.into_mut()
}
}
}
/// Extend the usage of a specified resource.
///
/// Returns conflicting transition as an error.
pub fn change_extend(
&mut self,
id: S::Id,
ref_count: &RefCount,
selector: S::Selector,
usage: S::Usage,
) -> Result<(), PendingTransition<S>> {
Self::get_or_insert(self.backend, &mut self.map, id, ref_count)
.state
.change(id, selector, usage, None)
}
/// Replace the usage of a specified resource.
pub fn change_replace(
&mut self,
id: S::Id,
ref_count: &RefCount,
selector: S::Selector,
usage: S::Usage,
) -> Drain<PendingTransition<S>> {
let res = Self::get_or_insert(self.backend, &mut self.map, id, ref_count);
res.state
.change(id, selector, usage, Some(&mut self.temp))
.ok(); //TODO: unwrap?
self.temp.drain(..)
}
/// Merge another tracker into `self` by extending the current states
/// without any transitions.
pub fn merge_extend(&mut self, other: &Self) -> Result<(), PendingTransition<S>> {
debug_assert_eq!(self.backend, other.backend);
for (&index, new) in other.map.iter() {
match self.map.entry(index) {
Entry::Vacant(e) => {
e.insert(new.clone());
}
Entry::Occupied(e) => {
assert_eq!(e.get().epoch, new.epoch);
let id = S::Id::zip(index, new.epoch, self.backend);
e.into_mut()
.state
.merge(id, &new.state, Stitch::Last, None)?;
}
}
}
Ok(())
}
/// Merge another tracker, adding it's transitions to `self`.
/// Transitions the current usage to the new one.
pub fn merge_replace<'a>(
&'a mut self,
other: &'a Self,
stitch: Stitch,
) -> Drain<PendingTransition<S>> {
for (&index, new) in other.map.iter() {
match self.map.entry(index) {
Entry::Vacant(e) => {
e.insert(new.clone());
}
Entry::Occupied(e) => {
assert_eq!(e.get().epoch, new.epoch);
let id = S::Id::zip(index, new.epoch, self.backend);
e.into_mut()
.state
.merge(id, &new.state, stitch, Some(&mut self.temp))
.ok(); //TODO: unwrap?
}
}
}
self.temp.drain(..)
}
/// Use a given resource provided by an `Id` with the specified usage.
/// Combines storage access by 'Id' with the transition that extends
/// the last read-only usage, if possible.
///
/// Returns the old usage as an error if there is a conflict.
pub fn use_extend<'a, T: 'a + Borrow<RefCount>>(
&mut self,
storage: &'a Storage<T, S::Id>,
id: S::Id,
selector: S::Selector,
usage: S::Usage,
) -> Result<&'a T, S::Usage> {
let item = &storage[id];
self.change_extend(id, item.borrow(), selector, usage)
.map(|()| item)
.map_err(|pending| pending.usage.start)
}
/// Use a given resource provided by an `Id` with the specified usage.
/// Combines storage access by 'Id' with the transition that replaces
/// the last usage with a new one, returning an iterator over these
/// transitions.
pub fn use_replace<'a, T: 'a + Borrow<RefCount>>(
&mut self,
storage: &'a Storage<T, S::Id>,
id: S::Id,
selector: S::Selector,
usage: S::Usage,
) -> (&'a T, Drain<PendingTransition<S>>) {
let item = &storage[id];
let drain = self.change_replace(id, item.borrow(), selector, usage);
(item, drain)
}
}
impl<I: Copy + Debug + TypedId> ResourceState for PhantomData<I> {
type Id = I;
type Selector = ();
type Usage = ();
fn query(&self, _selector: Self::Selector) -> Option<Self::Usage> {
Some(())
}
fn change(
&mut self,
_id: Self::Id,
_selector: Self::Selector,
_usage: Self::Usage,
_output: Option<&mut Vec<PendingTransition<Self>>>,
) -> Result<(), PendingTransition<Self>> {
Ok(())
}
fn merge(
&mut self,
_id: Self::Id,
_other: &Self,
_stitch: Stitch,
_output: Option<&mut Vec<PendingTransition<Self>>>,
) -> Result<(), PendingTransition<Self>> {
Ok(())
}
fn optimize(&mut self) {}
}
/// A set of trackers for all relevant resources.
#[derive(Debug)]
pub struct TrackerSet {
pub buffers: ResourceTracker<BufferState>,
pub textures: ResourceTracker<TextureState>,
pub views: ResourceTracker<PhantomData<TextureViewId>>,
pub bind_groups: ResourceTracker<PhantomData<BindGroupId>>,
pub samplers: ResourceTracker<PhantomData<SamplerId>>,
}
impl TrackerSet {
/// Create an empty set.
pub fn new(backend: Backend) -> Self {
TrackerSet {
buffers: ResourceTracker::new(backend),
textures: ResourceTracker::new(backend),
views: ResourceTracker::new(backend),
bind_groups: ResourceTracker::new(backend),
samplers: ResourceTracker::new(backend),
}
}
/// Clear all the trackers.
pub fn clear(&mut self) {
self.buffers.clear();
self.textures.clear();
self.views.clear();
self.bind_groups.clear();
self.samplers.clear();
}
/// Try to optimize the tracking representation.
pub fn optimize(&mut self) {
self.buffers.optimize();
self.textures.optimize();
self.views.optimize();
self.bind_groups.optimize();
self.samplers.optimize();
}
/// Merge all the trackers of another instance by extending
/// the usage. Panics on a conflict.
pub fn merge_extend(&mut self, other: &Self) {
self.buffers.merge_extend(&other.buffers).unwrap();
self.textures.merge_extend(&other.textures).unwrap();
self.views.merge_extend(&other.views).unwrap();
self.bind_groups.merge_extend(&other.bind_groups).unwrap();
self.samplers.merge_extend(&other.samplers).unwrap();
}
pub fn backend(&self) -> Backend {
self.buffers.backend
}
}

View File

@ -1,411 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use std::{cmp::Ordering, fmt::Debug, iter::Peekable, ops::Range, slice::Iter};
/// Structure that keeps track of a I -> T mapping,
/// optimized for a case where keys of the same values
/// are often grouped together linearly.
#[derive(Clone, Debug)]
pub struct RangedStates<I, T> {
/// List of ranges, each associated with a singe value.
/// Ranges of keys have to be non-intersecting and ordered.
ranges: Vec<(Range<I>, T)>,
}
impl<I, T> Default for RangedStates<I, T> {
fn default() -> Self {
RangedStates { ranges: Vec::new() }
}
}
impl<I: Copy + PartialOrd, T: Copy + PartialEq> RangedStates<I, T> {
/// Construct a new instance from a slice of ranges.
#[cfg(test)]
pub fn new(values: &[(Range<I>, T)]) -> Self {
RangedStates {
ranges: values.to_vec(),
}
}
/// Clear all the ranges.
pub fn clear(&mut self) {
self.ranges.clear();
}
/// Append a range.
///
/// Assumes that the object is being constructed from a set of
/// ranges, and they are given in the ascending order of their keys.
pub fn append(&mut self, index: Range<I>, value: T) {
if let Some(last) = self.ranges.last() {
debug_assert!(last.0.end <= index.start);
}
self.ranges.push((index, value));
}
/// Check that all the ranges are non-intersecting and ordered.
/// Panics otherwise.
#[cfg(test)]
fn check_sanity(&self) {
for a in self.ranges.iter() {
assert!(a.0.start < a.0.end);
}
for (a, b) in self.ranges.iter().zip(self.ranges[1 ..].iter()) {
assert!(a.0.end <= b.0.start);
}
}
/// Merge the neighboring ranges together, where possible.
pub fn coalesce(&mut self) {
let mut num_removed = 0;
let mut iter = self.ranges.iter_mut();
let mut cur = match iter.next() {
Some(elem) => elem,
None => return,
};
while let Some(next) = iter.next() {
if cur.0.end == next.0.start && cur.1 == next.1 {
num_removed += 1;
cur.0.end = next.0.end;
next.0.end = next.0.start;
} else {
cur = next;
}
}
if num_removed != 0 {
self.ranges.retain(|pair| pair.0.start != pair.0.end);
}
}
/// Check if all intersecting ranges have the same value, which is returned.
///
/// Returns `None` if no intersections are detected.
/// Returns `Some(Err)` if the intersected values are inconsistent.
pub fn query<U: PartialEq>(
&self,
index: &Range<I>,
fun: impl Fn(&T) -> U,
) -> Option<Result<U, ()>> {
let mut result = None;
for &(ref range, ref value) in self.ranges.iter() {
if range.end > index.start && range.start < index.end {
let old = result.replace(fun(value));
if old.is_some() && old != result {
return Some(Err(()));
}
}
}
result.map(Ok)
}
/// Split the storage ranges in such a way that there is a linear subset of
/// them occupying exactly `index` range, which is returned mutably.
///
/// Gaps in the ranges are filled with `default` value.
pub fn isolate(&mut self, index: &Range<I>, default: T) -> &mut [(Range<I>, T)] {
//TODO: implement this in 2 passes:
// 1. scan the ranges to figure out how many extra ones need to be inserted
// 2. go through the ranges by moving them them to the right and inserting the missing ones
let mut start_pos = match self.ranges.iter().position(|pair| pair.0.end > index.start) {
Some(pos) => pos,
None => {
let pos = self.ranges.len();
self.ranges.push((index.clone(), default));
return &mut self.ranges[pos ..];
}
};
{
let (range, value) = self.ranges[start_pos].clone();
if range.start < index.start {
self.ranges[start_pos].0.start = index.start;
self.ranges
.insert(start_pos, (range.start .. index.start, value));
start_pos += 1;
}
}
let mut pos = start_pos;
let mut range_pos = index.start;
loop {
let (range, value) = self.ranges[pos].clone();
if range.start >= index.end {
self.ranges.insert(pos, (range_pos .. index.end, default));
pos += 1;
break;
}
if range.start > range_pos {
self.ranges.insert(pos, (range_pos .. range.start, default));
pos += 1;
range_pos = range.start;
}
if range.end >= index.end {
if range.end != index.end {
self.ranges[pos].0.start = index.end;
self.ranges.insert(pos, (range_pos .. index.end, value));
}
pos += 1;
break;
}
pos += 1;
range_pos = range.end;
if pos == self.ranges.len() {
self.ranges.push((range_pos .. index.end, default));
pos += 1;
break;
}
}
&mut self.ranges[start_pos .. pos]
}
/// Helper method for isolation that checks the sanity of the results.
#[cfg(test)]
pub fn sanely_isolated(&self, index: Range<I>, default: T) -> Vec<(Range<I>, T)> {
let mut clone = self.clone();
let result = clone.isolate(&index, default).to_vec();
clone.check_sanity();
result
}
/// Produce an iterator that merges two instances together.
///
/// Each range in the returned iterator is a subset of a range in either
/// `self` or `other`, and the value returned as a `Range` from `self` to `other`.
pub fn merge<'a>(&'a self, other: &'a Self, base: I) -> Merge<'a, I, T> {
Merge {
base,
sa: self.ranges.iter().peekable(),
sb: other.ranges.iter().peekable(),
}
}
}
/// A custom iterator that goes through two `RangedStates` and process a merge.
#[derive(Debug)]
pub struct Merge<'a, I, T> {
base: I,
sa: Peekable<Iter<'a, (Range<I>, T)>>,
sb: Peekable<Iter<'a, (Range<I>, T)>>,
}
impl<'a, I: Copy + Debug + Ord, T: Copy + Debug> Iterator for Merge<'a, I, T> {
type Item = (Range<I>, Range<Option<T>>);
fn next(&mut self) -> Option<Self::Item> {
match (self.sa.peek(), self.sb.peek()) {
// we have both streams
(Some(&(ref ra, va)), Some(&(ref rb, vb))) => {
let (range, usage) = if ra.start < self.base {
// in the middle of the left stream
if self.base == rb.start {
// right stream is starting
debug_assert!(self.base < ra.end);
(self.base .. ra.end.min(rb.end), Some(*va) .. Some(*vb))
} else {
// right hasn't started yet
debug_assert!(self.base < rb.start);
(self.base .. rb.start, Some(*va) .. None)
}
} else if rb.start < self.base {
// in the middle of the right stream
if self.base == ra.start {
// left stream is starting
debug_assert!(self.base < rb.end);
(self.base .. ra.end.min(rb.end), Some(*va) .. Some(*vb))
} else {
// left hasn't started yet
debug_assert!(self.base < ra.start);
(self.base .. ra.start, None .. Some(*vb))
}
} else {
// no active streams
match ra.start.cmp(&rb.start) {
// both are starting
Ordering::Equal => (ra.start .. ra.end.min(rb.end), Some(*va) .. Some(*vb)),
// only left is starting
Ordering::Less => (ra.start .. rb.start.min(ra.end), Some(*va) .. None),
// only right is starting
Ordering::Greater => (rb.start .. ra.start.min(rb.end), None .. Some(*vb)),
}
};
self.base = range.end;
if ra.end == range.end {
let _ = self.sa.next();
}
if rb.end == range.end {
let _ = self.sb.next();
}
Some((range, usage))
}
// only right stream
(None, Some(&(ref rb, vb))) => {
let range = self.base.max(rb.start) .. rb.end;
self.base = rb.end;
let _ = self.sb.next();
Some((range, None .. Some(*vb)))
}
// only left stream
(Some(&(ref ra, va)), None) => {
let range = self.base.max(ra.start) .. ra.end;
self.base = ra.end;
let _ = self.sa.next();
Some((range, Some(*va) .. None))
}
// done
(None, None) => None,
}
}
}
#[cfg(test)]
mod test {
//TODO: randomized/fuzzy testing
use super::RangedStates;
use std::{fmt::Debug, ops::Range};
fn easy_merge<T: PartialEq + Copy + Debug>(
ra: Vec<(Range<usize>, T)>,
rb: Vec<(Range<usize>, T)>,
) -> Vec<(Range<usize>, Range<Option<T>>)> {
RangedStates { ranges: ra }
.merge(&RangedStates { ranges: rb }, 0)
.collect()
}
#[test]
fn sane_good() {
let rs = RangedStates {
ranges: vec![(1 .. 4, 9u8), (4 .. 5, 9)],
};
rs.check_sanity();
}
#[test]
#[should_panic]
fn sane_empty() {
let rs = RangedStates {
ranges: vec![(1 .. 4, 9u8), (5 .. 5, 9)],
};
rs.check_sanity();
}
#[test]
#[should_panic]
fn sane_intersect() {
let rs = RangedStates {
ranges: vec![(1 .. 4, 9u8), (3 .. 5, 9)],
};
rs.check_sanity();
}
#[test]
fn coalesce() {
let mut rs = RangedStates {
ranges: vec![(1 .. 4, 9u8), (4 .. 5, 9), (5 .. 7, 1), (8 .. 9, 1)],
};
rs.coalesce();
rs.check_sanity();
assert_eq!(rs.ranges, vec![(1 .. 5, 9), (5 .. 7, 1), (8 .. 9, 1),]);
}
#[test]
fn query() {
let rs = RangedStates {
ranges: vec![(1 .. 4, 1u8), (5 .. 7, 2)],
};
assert_eq!(rs.query(&(0 .. 1), |v| *v), None);
assert_eq!(rs.query(&(1 .. 3), |v| *v), Some(Ok(1)));
assert_eq!(rs.query(&(1 .. 6), |v| *v), Some(Err(())));
}
#[test]
fn isolate() {
let rs = RangedStates {
ranges: vec![(1 .. 4, 9u8), (4 .. 5, 9), (5 .. 7, 1), (8 .. 9, 1)],
};
assert_eq!(&rs.sanely_isolated(4 .. 5, 0), &[(4 .. 5, 9u8),]);
assert_eq!(
&rs.sanely_isolated(0 .. 6, 0),
&[(0 .. 1, 0), (1 .. 4, 9u8), (4 .. 5, 9), (5 .. 6, 1),]
);
assert_eq!(
&rs.sanely_isolated(8 .. 10, 1),
&[(8 .. 9, 1), (9 .. 10, 1),]
);
assert_eq!(
&rs.sanely_isolated(6 .. 9, 0),
&[(6 .. 7, 1), (7 .. 8, 0), (8 .. 9, 1),]
);
}
#[test]
fn merge_same() {
assert_eq!(
easy_merge(vec![(1 .. 4, 0u8),], vec![(1 .. 4, 2u8),],),
vec![(1 .. 4, Some(0) .. Some(2)),]
);
}
#[test]
fn merge_empty() {
assert_eq!(
easy_merge(vec![(1 .. 2, 0u8),], vec![],),
vec![(1 .. 2, Some(0) .. None),]
);
assert_eq!(
easy_merge(vec![], vec![(3 .. 4, 1u8),],),
vec![(3 .. 4, None .. Some(1)),]
);
}
#[test]
fn merge_separate() {
assert_eq!(
easy_merge(vec![(1 .. 2, 0u8), (5 .. 6, 1u8),], vec![(2 .. 4, 2u8),],),
vec![
(1 .. 2, Some(0) .. None),
(2 .. 4, None .. Some(2)),
(5 .. 6, Some(1) .. None),
]
);
}
#[test]
fn merge_subset() {
assert_eq!(
easy_merge(vec![(1 .. 6, 0u8),], vec![(2 .. 4, 2u8),],),
vec![
(1 .. 2, Some(0) .. None),
(2 .. 4, Some(0) .. Some(2)),
(4 .. 6, Some(0) .. None),
]
);
assert_eq!(
easy_merge(vec![(2 .. 4, 0u8),], vec![(1 .. 4, 2u8),],),
vec![(1 .. 2, None .. Some(2)), (2 .. 4, Some(0) .. Some(2)),]
);
}
#[test]
fn merge_all() {
assert_eq!(
easy_merge(
vec![(1 .. 4, 0u8), (5 .. 8, 1u8),],
vec![(2 .. 6, 2u8), (7 .. 9, 3u8),],
),
vec![
(1 .. 2, Some(0) .. None),
(2 .. 4, Some(0) .. Some(2)),
(4 .. 5, None .. Some(2)),
(5 .. 6, Some(1) .. Some(2)),
(6 .. 7, Some(1) .. None),
(7 .. 8, Some(1) .. Some(3)),
(8 .. 9, None .. Some(3)),
]
);
}
}

View File

@ -1,301 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use super::{range::RangedStates, PendingTransition, ResourceState, Stitch, Unit};
use crate::{conv, device::MAX_MIP_LEVELS, resource::TextureUsage, TextureId};
use arrayvec::ArrayVec;
use std::ops::Range;
type PlaneStates = RangedStates<hal::image::Layer, Unit<TextureUsage>>;
//TODO: store `hal::image::State` here to avoid extra conversions
#[derive(Clone, Debug, Default)]
struct MipState {
color: PlaneStates,
depth: PlaneStates,
stencil: PlaneStates,
}
#[derive(Clone, Debug, Default)]
pub struct TextureState {
mips: ArrayVec<[MipState; MAX_MIP_LEVELS]>,
}
impl PendingTransition<TextureState> {
/// Produce the gfx-hal image states corresponding to the transition.
pub fn to_states(&self) -> Range<hal::image::State> {
conv::map_texture_state(self.usage.start, self.selector.aspects)
.. conv::map_texture_state(self.usage.end, self.selector.aspects)
}
//TODO: make this less awkward!
/// Check for the validity of `self` with regards to the presence of `output`.
///
/// Return the end usage if the `output` is provided and pushes self to it.
/// Otherwise, return the extended usage, or an error if extension is impossible.
///
/// When a transition is generated, returns the specified `replace` usage.
fn record(
self,
output: Option<&mut &mut Vec<Self>>,
replace: TextureUsage,
) -> Result<TextureUsage, Self> {
let u = self.usage.clone();
match output {
Some(out) => {
out.push(self);
Ok(replace)
}
None => {
if !u.start.is_empty()
&& u.start != u.end
&& TextureUsage::WRITE_ALL.intersects(u.start | u.end)
{
Err(self)
} else {
Ok(u.start | u.end)
}
}
}
}
}
impl ResourceState for TextureState {
type Id = TextureId;
type Selector = hal::image::SubresourceRange;
type Usage = TextureUsage;
fn query(&self, selector: Self::Selector) -> Option<Self::Usage> {
let mut result = None;
let num_levels = self.mips.len();
let mip_start = num_levels.min(selector.levels.start as usize);
let mip_end = num_levels.min(selector.levels.end as usize);
for mip in self.mips[mip_start .. mip_end].iter() {
for &(aspect, plane_states) in &[
(hal::format::Aspects::COLOR, &mip.color),
(hal::format::Aspects::DEPTH, &mip.depth),
(hal::format::Aspects::STENCIL, &mip.stencil),
] {
if !selector.aspects.contains(aspect) {
continue;
}
match plane_states.query(&selector.layers, |unit| unit.last) {
None => {}
Some(Ok(usage)) if result == Some(usage) => {}
Some(Ok(usage)) if result.is_none() => {
result = Some(usage);
}
Some(Ok(_)) | Some(Err(())) => return None,
}
}
}
result
}
fn change(
&mut self,
id: Self::Id,
selector: Self::Selector,
usage: Self::Usage,
mut output: Option<&mut Vec<PendingTransition<Self>>>,
) -> Result<(), PendingTransition<Self>> {
while self.mips.len() < selector.levels.end as usize {
self.mips.push(MipState::default());
}
for (mip_id, mip) in self.mips
[selector.levels.start as usize .. selector.levels.end as usize]
.iter_mut()
.enumerate()
{
let level = selector.levels.start + mip_id as hal::image::Level;
for &mut (aspect, ref mut plane_states) in &mut [
(hal::format::Aspects::COLOR, &mut mip.color),
(hal::format::Aspects::DEPTH, &mut mip.depth),
(hal::format::Aspects::STENCIL, &mut mip.stencil),
] {
if !selector.aspects.contains(aspect) {
continue;
}
let layers = plane_states.isolate(&selector.layers, Unit::new(usage));
for &mut (ref range, ref mut unit) in layers {
if unit.last == usage && TextureUsage::ORDERED.contains(usage) {
continue;
}
let pending = PendingTransition {
id,
selector: hal::image::SubresourceRange {
aspects: hal::format::Aspects::COLOR,
levels: level .. level + 1,
layers: range.clone(),
},
usage: unit.last .. usage,
};
unit.last = pending.record(output.as_mut(), usage)?;
}
}
}
Ok(())
}
fn merge(
&mut self,
id: Self::Id,
other: &Self,
stitch: Stitch,
mut output: Option<&mut Vec<PendingTransition<Self>>>,
) -> Result<(), PendingTransition<Self>> {
assert!(output.is_some() || stitch == Stitch::Last);
let mut temp = Vec::new();
while self.mips.len() < other.mips.len() as usize {
self.mips.push(MipState::default());
}
for (mip_id, (mip_self, mip_other)) in self.mips.iter_mut().zip(&other.mips).enumerate() {
let level = mip_id as hal::image::Level;
for &mut (aspects, ref mut planes_self, planes_other) in &mut [
(
hal::format::Aspects::COLOR,
&mut mip_self.color,
&mip_other.color,
),
(
hal::format::Aspects::DEPTH,
&mut mip_self.depth,
&mip_other.depth,
),
(
hal::format::Aspects::STENCIL,
&mut mip_self.stencil,
&mip_other.stencil,
),
] {
temp.extend(planes_self.merge(planes_other, 0));
planes_self.clear();
for (layers, states) in temp.drain(..) {
let unit = match states {
Range {
start: None,
end: None,
} => unreachable!(),
Range {
start: Some(start),
end: None,
} => start,
Range {
start: None,
end: Some(end),
} => end,
Range {
start: Some(start),
end: Some(end),
} => {
let mut final_usage = end.select(stitch);
if start.last != final_usage
|| !TextureUsage::ORDERED.contains(final_usage)
{
let pending = PendingTransition {
id,
selector: hal::image::SubresourceRange {
aspects,
levels: level .. level + 1,
layers: layers.clone(),
},
usage: start.last .. final_usage,
};
final_usage = pending.record(output.as_mut(), end.last)?;
}
Unit {
init: start.init,
last: final_usage,
}
}
};
planes_self.append(layers, unit);
}
}
}
Ok(())
}
fn optimize(&mut self) {
for mip in self.mips.iter_mut() {
mip.color.coalesce();
mip.depth.coalesce();
mip.stencil.coalesce();
}
}
}
#[cfg(test)]
mod test {
//TODO: change() and merge() tests
//use crate::TypedId;
use super::*;
use hal::{format::Aspects, image::SubresourceRange};
#[test]
fn query() {
let mut ts = TextureState::default();
ts.mips.push(MipState::default());
ts.mips.push(MipState::default());
ts.mips[1].color = PlaneStates::new(&[
(1 .. 3, Unit::new(TextureUsage::SAMPLED)),
(3 .. 5, Unit::new(TextureUsage::SAMPLED)),
(5 .. 6, Unit::new(TextureUsage::STORAGE)),
]);
assert_eq!(
ts.query(SubresourceRange {
aspects: Aspects::COLOR,
levels: 1 .. 2,
layers: 2 .. 5,
}),
// level 1 matches
Some(TextureUsage::SAMPLED),
);
assert_eq!(
ts.query(SubresourceRange {
aspects: Aspects::DEPTH,
levels: 1 .. 2,
layers: 2 .. 5,
}),
// no depth found
None,
);
assert_eq!(
ts.query(SubresourceRange {
aspects: Aspects::COLOR,
levels: 0 .. 2,
layers: 2 .. 5,
}),
// level 0 is empty, level 1 matches
Some(TextureUsage::SAMPLED),
);
assert_eq!(
ts.query(SubresourceRange {
aspects: Aspects::COLOR,
levels: 1 .. 2,
layers: 1 .. 5,
}),
// level 1 matches with gaps
Some(TextureUsage::SAMPLED),
);
assert_eq!(
ts.query(SubresourceRange {
aspects: Aspects::COLOR,
levels: 1 .. 2,
layers: 4 .. 6,
}),
// level 1 doesn't match
None,
);
}
}

View File

@ -1,20 +0,0 @@
[package]
name = "wgpu-remote"
version = "0.1.0"
authors = [
"Dzmitry Malyshau <kvark@mozilla.com>",
"Joshua Groves <josh@joshgroves.com>",
]
edition = "2018"
[lib]
#crate-type = ["lib", "cdylib", "staticlib"]
crate-type = ["lib"]
[features]
default = []
[dependencies]
wgn = { path = "../wgpu-native", package = "wgpu-native", version = "0.4" }
log = "0.4"
parking_lot = { version = "0.9" }

View File

@ -1,46 +0,0 @@
header = """/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */"""
autogen_warning = """/* DO NOT MODIFY THIS MANUALLY! This file was generated using cbindgen.
* To generate this file:
* 1. Get the latest cbindgen using `cargo install --force cbindgen`
* a. Alternatively, you can clone `https://github.com/eqrion/cbindgen` and use a tagged release
* 2. Run `rustup run nightly cbindgen toolkit/library/rust/ --lockfile Cargo.lock --crate wgpu-remote -o dom/webgpu/ffi/wgpu_ffi_generated.h`
*/
typedef void WGPUEmpty;
"""
include_version = true
braces = "SameLine"
line_length = 100
tab_width = 2
language = "C"
[export]
prefix = "WGPU"
exclude = ["BufferMapResult"]
[parse]
parse_deps = true
include = ["wgpu-native"]
[fn]
prefix = "WGPU_INLINE"
postfix = "WGPU_FUNC"
args = "Vertical"
rename_args = "GeckoCase"
[struct]
derive_eq = true
[enum]
prefix_with_name = true
derive_helper_methods = true
[macro_expansion]
bitflags = true
[defines]
"target_os = windows" = "XP_WIN"
"target_os = macos" = "XP_MACOSX"
"target_os = android" = "ANDROID"

View File

@ -1,150 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use wgn::{AdapterId, Backend, DeviceId, IdentityManager, SurfaceId};
use parking_lot::Mutex;
use std::{ptr, slice};
pub mod server;
#[derive(Debug)]
struct IdentityHub {
adapters: IdentityManager<AdapterId>,
devices: IdentityManager<DeviceId>,
}
impl IdentityHub {
fn new(backend: Backend) -> Self {
IdentityHub {
adapters: IdentityManager::new(backend),
devices: IdentityManager::new(backend),
}
}
}
#[derive(Debug)]
struct Identities {
surfaces: IdentityManager<SurfaceId>,
vulkan: IdentityHub,
#[cfg(any(target_os = "ios", target_os = "macos"))]
metal: IdentityHub,
#[cfg(windows)]
dx12: IdentityHub,
}
impl Identities {
fn new() -> Self {
Identities {
surfaces: IdentityManager::new(Backend::Empty),
vulkan: IdentityHub::new(Backend::Vulkan),
#[cfg(any(target_os = "ios", target_os = "macos"))]
metal: IdentityHub::new(Backend::Metal),
#[cfg(windows)]
dx12: IdentityHub::new(Backend::Dx12),
}
}
fn select(&mut self, backend: Backend) -> &mut IdentityHub {
match backend {
Backend::Vulkan => &mut self.vulkan,
#[cfg(any(target_os = "ios", target_os = "macos"))]
Backend::Metal => &mut self.metal,
#[cfg(windows)]
Backend::Dx12 => &mut self.dx12,
_ => panic!("Unexpected backend: {:?}", backend),
}
}
}
#[derive(Debug)]
pub struct Client {
identities: Mutex<Identities>,
}
#[repr(C)]
#[derive(Debug)]
pub struct Infrastructure {
pub client: *mut Client,
pub error: *const u8,
}
#[no_mangle]
pub extern "C" fn wgpu_client_new() -> Infrastructure {
log::info!("Initializing WGPU client");
let client = Box::new(Client {
identities: Mutex::new(Identities::new()),
});
Infrastructure {
client: Box::into_raw(client),
error: ptr::null(),
}
}
#[no_mangle]
pub extern "C" fn wgpu_client_delete(client: *mut Client) {
log::info!("Terminating WGPU client");
let _client = unsafe { Box::from_raw(client) };
}
#[no_mangle]
pub extern "C" fn wgpu_client_make_adapter_ids(
client: &Client,
ids: *mut wgn::AdapterId,
id_length: usize,
) -> usize {
let mut identities = client.identities.lock();
assert_ne!(id_length, 0);
let mut ids = unsafe { slice::from_raw_parts_mut(ids, id_length) }.iter_mut();
*ids.next().unwrap() = identities.vulkan.adapters.alloc();
#[cfg(any(target_os = "ios", target_os = "macos"))]
{
*ids.next().unwrap() = identities.metal.adapters.alloc();
}
#[cfg(windows)]
{
*ids.next().unwrap() = identities.dx12.adapters.alloc();
}
id_length - ids.len()
}
#[no_mangle]
pub extern "C" fn wgpu_client_kill_adapter_ids(
client: &Client,
ids: *const wgn::AdapterId,
id_length: usize,
) {
let mut identity = client.identities.lock();
let ids = unsafe { slice::from_raw_parts(ids, id_length) };
for &id in ids {
identity.select(id.backend()).adapters.free(id)
}
}
#[no_mangle]
pub extern "C" fn wgpu_client_make_device_id(
client: &Client,
adapter_id: wgn::AdapterId,
) -> wgn::DeviceId {
client
.identities
.lock()
.select(adapter_id.backend())
.devices
.alloc()
}
#[no_mangle]
pub extern "C" fn wgpu_client_kill_device_id(client: &Client, id: wgn::DeviceId) {
client
.identities
.lock()
.select(id.backend())
.devices
.free(id)
}

View File

@ -1,53 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use std::slice;
#[no_mangle]
pub extern "C" fn wgpu_server_new() -> *mut wgn::Global {
log::info!("Initializing WGPU server");
Box::into_raw(Box::new(wgn::Global::new("wgpu")))
}
#[no_mangle]
pub extern "C" fn wgpu_server_delete(global: *mut wgn::Global) {
log::info!("Terminating WGPU server");
unsafe { Box::from_raw(global) }.delete();
log::info!("\t...done");
}
/// Request an adapter according to the specified options.
/// Provide the list of IDs to pick from.
///
/// Returns the index in this list, or -1 if unable to pick.
#[no_mangle]
pub extern "C" fn wgpu_server_instance_request_adapter(
global: &wgn::Global,
desc: &wgn::RequestAdapterOptions,
ids: *const wgn::AdapterId,
id_length: usize,
) -> i8 {
let ids = unsafe { slice::from_raw_parts(ids, id_length) };
match wgn::request_adapter(global, desc, ids) {
Some(id) => ids.iter().position(|&i| i == id).unwrap() as i8,
None => -1,
}
}
#[no_mangle]
pub extern "C" fn wgpu_server_adapter_request_device(
global: &wgn::Global,
self_id: wgn::AdapterId,
desc: &wgn::DeviceDescriptor,
new_id: wgn::DeviceId,
) {
use wgn::adapter_request_device as func;
wgn::gfx_select!(self_id => func(global, self_id, desc, new_id));
}
#[no_mangle]
pub extern "C" fn wgpu_server_device_destroy(global: &wgn::Global, self_id: wgn::DeviceId) {
use wgn::device_destroy as func;
wgn::gfx_select!(self_id => func(global, self_id))
}

View File

@ -57,9 +57,8 @@ dictionary GPUObjectDescriptorBase {
Exposed=Window,
]
interface GPU {
// May reject with DOMException
[Throws]
Promise<GPUAdapter> requestAdapter(optional GPURequestAdapterOptions options = {});
//[Exposed=Window]
//Promise<GPUAdapter> requestAdapter(optional GPURequestAdapterOptions options = {});
};
// Add a "webgpu" member to Navigator/Worker that contains the global instance of a "WebGPU"
@ -83,9 +82,8 @@ interface GPUAdapter {
//GPUExtensions getExtensions();
//readonly attribute GPULimits limits; Don't expose higher limits for now.
// May reject with DOMException
[Throws]
Promise<GPUDevice> requestDevice(optional GPUDeviceDescriptor descriptor = {});
// May reject with DOMException // TODO: DOMException("OperationError")?
//Promise<GPUDevice> requestDevice(optional GPUDeviceDescriptor descriptor = {});
};
GPUAdapter includes GPUObjectBase;

View File

@ -22,6 +22,7 @@
#include "mozilla/RemoteDecoderManagerChild.h"
#include "mozilla/RemoteDecoderManagerParent.h"
#include "mozilla/dom/MemoryReportRequest.h"
#include "mozilla/webgpu/WebGPUThreading.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/image/ImageMemoryReporter.h"
@ -271,6 +272,10 @@ mozilla::ipc::IPCResult GPUParent::RecvInit(
}
#endif
if (gfxConfig::IsEnabled(Feature::WEBGPU)) {
webgpu::WebGPUThreading::Start();
}
VRManager::ManagerInit();
// Send a message to the UI process that we're done.
GPUDeviceData data;
@ -554,6 +559,10 @@ void GPUParent::ActorDestroy(ActorDestroyReason aWhy) {
image::ImageMemoryReporter::ShutdownForWebRender();
if (gfxConfig::IsEnabled(Feature::WEBGPU)) {
webgpu::WebGPUThreading::ShutDown();
}
// Shut down the default GL context provider.
gl::GLContextProvider::Shutdown();

View File

@ -30,10 +30,8 @@
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/gfx/GPUProcessManager.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/webgpu/WebGPUChild.h"
#include "mozilla/mozalloc.h" // for operator new, etc
#include "mozilla/Telemetry.h"
#include "gfxConfig.h"
#include "nsAutoPtr.h"
#include "nsDebug.h" // for NS_WARNING
#include "nsIObserver.h" // for nsIObserver
@ -187,12 +185,6 @@ void CompositorBridgeChild::Destroy() {
Unused << child->SendDestroy();
}
AutoTArray<PWebGPUChild*, 16> webGPUChildren;
ManagedPWebGPUChild(webGPUChildren);
for (PWebGPUChild* child : webGPUChildren) {
Unused << child->SendShutdown();
}
const ManagedContainer<PTextureChild>& textures = ManagedPTextureChild();
for (auto iter = textures.ConstIter(); !iter.Done(); iter.Next()) {
RefPtr<TextureClient> texture =
@ -966,16 +958,6 @@ void CompositorBridgeChild::EndCanvasTransaction() {
}
}
RefPtr<webgpu::WebGPUChild> CompositorBridgeChild::GetWebGPUChild() {
MOZ_ASSERT(gfx::gfxConfig::IsEnabled(gfx::Feature::WEBGPU));
if (!mWebGPUChild) {
webgpu::PWebGPUChild* bridge = SendPWebGPUConstructor();
mWebGPUChild = static_cast<webgpu::WebGPUChild*>(bridge);
}
return mWebGPUChild;
}
bool CompositorBridgeChild::AllocUnsafeShmem(
size_t aSize, ipc::SharedMemory::SharedMemoryType aType,
ipc::Shmem* aShmem) {
@ -1066,18 +1048,6 @@ bool CompositorBridgeChild::DeallocPWebRenderBridgeChild(
return true;
}
webgpu::PWebGPUChild* CompositorBridgeChild::AllocPWebGPUChild() {
webgpu::WebGPUChild* child = new webgpu::WebGPUChild();
child->AddIPDLReference();
return child;
}
bool CompositorBridgeChild::DeallocPWebGPUChild(webgpu::PWebGPUChild* aActor) {
webgpu::WebGPUChild* child = static_cast<webgpu::WebGPUChild*>(aActor);
child->ReleaseIPDLReference();
return true;
}
void CompositorBridgeChild::ClearSharedFrameMetricsData(LayersId aLayersId) {
for (auto iter = mFrameMetricsTable.Iter(); !iter.Done(); iter.Next()) {
nsAutoPtr<SharedFrameMetricsData>& data = iter.Data();

View File

@ -31,11 +31,6 @@ namespace dom {
class BrowserChild;
} // namespace dom
namespace webgpu {
class PWebGPUChild;
class WebGPUChild;
} // namespace webgpu
namespace widget {
class CompositorWidget;
} // namespace widget
@ -132,8 +127,6 @@ class CompositorBridgeChild final : public PCompositorBridgeChild,
void EndCanvasTransaction();
RefPtr<webgpu::WebGPUChild> GetWebGPUChild();
/**
* Request that the parent tell us when graphics are ready on GPU.
* When we get that message, we bounce it to the BrowserParent via
@ -228,9 +221,6 @@ class CompositorBridgeChild final : public PCompositorBridgeChild,
const wr::PipelineId& aPipelineId, const LayoutDeviceIntSize&);
bool DeallocPWebRenderBridgeChild(PWebRenderBridgeChild* aActor);
webgpu::PWebGPUChild* AllocPWebGPUChild();
bool DeallocPWebGPUChild(webgpu::PWebGPUChild* aActor);
wr::MaybeExternalImageId GetNextExternalImageId() override;
wr::PipelineId GetNextPipelineId();
@ -409,8 +399,6 @@ class CompositorBridgeChild final : public PCompositorBridgeChild,
uintptr_t mTotalFlushCount;
RefPtr<CanvasChild> mCanvasChild;
RefPtr<webgpu::WebGPUChild> mWebGPUChild;
};
} // namespace layers

View File

@ -65,7 +65,6 @@
#include "mozilla/layers/WebRenderBridgeParent.h"
#include "mozilla/layers/AsyncImagePipelineManager.h"
#include "mozilla/webrender/WebRenderAPI.h"
#include "mozilla/webgpu/WebGPUParent.h"
#include "mozilla/media/MediaSystemResourceService.h" // for MediaSystemResourceService
#include "mozilla/mozalloc.h" // for operator new, etc
#include "mozilla/PerfStats.h"
@ -1923,22 +1922,6 @@ bool CompositorBridgeParent::DeallocPWebRenderBridgeParent(
return true;
}
webgpu::PWebGPUParent* CompositorBridgeParent::AllocPWebGPUParent() {
MOZ_ASSERT(!mWebGPUBridge);
mWebGPUBridge = new webgpu::WebGPUParent();
mWebGPUBridge.get()->AddRef(); // IPDL reference
return mWebGPUBridge;
}
bool CompositorBridgeParent::DeallocPWebGPUParent(
webgpu::PWebGPUParent* aActor) {
webgpu::WebGPUParent* parent = static_cast<webgpu::WebGPUParent*>(aActor);
MOZ_ASSERT(mWebGPUBridge == parent);
parent->Release(); // IPDL reference
mWebGPUBridge = nullptr;
return true;
}
void CompositorBridgeParent::NotifyMemoryPressure() {
if (mWrBridge) {
RefPtr<wr::WebRenderAPI> api =

View File

@ -52,11 +52,6 @@ namespace mozilla {
class CancelableRunnable;
namespace webgpu {
class PWebGPUParent;
class WebGPUParent;
} // namespace webgpu
namespace gfx {
class DrawTarget;
class GPUProcessManager;
@ -236,9 +231,6 @@ class CompositorBridgeParentBase : public PCompositorBridgeParent,
virtual bool DeallocPWebRenderBridgeParent(
PWebRenderBridgeParent* aActor) = 0;
virtual webgpu::PWebGPUParent* AllocPWebGPUParent() = 0;
virtual bool DeallocPWebGPUParent(webgpu::PWebGPUParent* aActor) = 0;
virtual PCompositorWidgetParent* AllocPCompositorWidgetParent(
const CompositorWidgetInitData& aInitData) = 0;
virtual bool DeallocPCompositorWidgetParent(
@ -647,9 +639,6 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase,
RefPtr<WebRenderBridgeParent> GetWebRenderBridgeParent() const;
Maybe<TimeStamp> GetTestingTimeStamp() const;
webgpu::PWebGPUParent* AllocPWebGPUParent() override;
bool DeallocPWebGPUParent(webgpu::PWebGPUParent* aActor) override;
static CompositorBridgeParent* GetCompositorBridgeParentFromLayersId(
const LayersId& aLayersId);
static RefPtr<CompositorBridgeParent> GetCompositorBridgeParentFromWindowId(
@ -669,8 +658,6 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase,
WebRenderBridgeParent* GetWrBridge() { return mWrBridge; }
webgpu::WebGPUParent* GetWebGPUBridge() { return mWebGPUBridge; }
private:
void Initialize();
@ -767,7 +754,6 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase,
RefPtr<AsyncCompositionManager> mCompositionManager;
RefPtr<AsyncImagePipelineManager> mAsyncImageManager;
RefPtr<WebRenderBridgeParent> mWrBridge;
RefPtr<webgpu::WebGPUParent> mWebGPUBridge;
widget::CompositorWidget* mWidget;
Maybe<TimeStamp> mTestTime;
CSSToLayoutDeviceScale mScale;

View File

@ -31,7 +31,6 @@
#include "mozilla/layers/RemoteContentController.h"
#include "mozilla/layers/WebRenderBridgeParent.h"
#include "mozilla/layers/AsyncImagePipelineManager.h"
#include "mozilla/webgpu/WebGPUParent.h"
#include "mozilla/mozalloc.h" // for operator new, etc
#include "nsDebug.h" // for NS_ASSERTION, etc
#include "nsTArray.h" // for nsTArray
@ -272,19 +271,6 @@ bool ContentCompositorBridgeParent::DeallocPWebRenderBridgeParent(
return true;
}
webgpu::PWebGPUParent* ContentCompositorBridgeParent::AllocPWebGPUParent() {
webgpu::WebGPUParent* parent = new webgpu::WebGPUParent();
parent->AddRef(); // IPDL reference
return parent;
}
bool ContentCompositorBridgeParent::DeallocPWebGPUParent(
webgpu::PWebGPUParent* aActor) {
webgpu::WebGPUParent* parent = static_cast<webgpu::WebGPUParent*>(aActor);
parent->Release(); // IPDL reference
return true;
}
mozilla::ipc::IPCResult ContentCompositorBridgeParent::RecvNotifyChildCreated(
const LayersId& child, CompositorOptions* aOptions) {
MonitorAutoLock lock(*sIndirectLayerTreesLock);

View File

@ -12,10 +12,6 @@
#include "mozilla/UniquePtr.h"
namespace mozilla {
namespace webgpu {
class PWebGPUParent;
} // namespace webgpu
namespace layers {
class CanvasParent;
@ -203,9 +199,6 @@ class ContentCompositorBridgeParent final : public CompositorBridgeParentBase {
const LayoutDeviceIntSize& aSize) override;
bool DeallocPWebRenderBridgeParent(PWebRenderBridgeParent* aActor) override;
webgpu::PWebGPUParent* AllocPWebGPUParent() override;
bool DeallocPWebGPUParent(webgpu::PWebGPUParent* aActor) override;
void ObserveLayersUpdate(LayersId aLayersId, LayersObserverEpoch aEpoch,
bool aActive) override;

View File

@ -17,7 +17,6 @@ include protocol PCompositorWidget;
include protocol PLayerTransaction;
include protocol PTexture;
include protocol PWebRenderBridge;
include protocol PWebGPU;
include "mozilla/GfxMessageUtils.h";
include "mozilla/layers/LayersMessageUtils.h";
include "mozilla/layers/WebRenderMessageUtils.h";
@ -102,7 +101,6 @@ sync refcounted protocol PCompositorBridge
manages PTexture;
manages PCompositorWidget;
manages PWebRenderBridge;
manages PWebGPU;
child:
// The child should invalidate retained layers. This is used for local
@ -168,10 +166,6 @@ parent:
async PAPZ(LayersId layersId);
async PAPZCTreeManager(LayersId layersId);
// Constructor for WebGPU IPDL
// Must be called before Initialize().
async PWebGPU();
/**
* Confirmation callback for UpdatePluginConfigurations and HideAllPlugins.
*/
@ -280,7 +274,7 @@ parent:
sync EndRecording()
returns (bool success);
// To set up sharing the composited output to Firefox Reality on Desktop
// To set up sharing the composited output to Firefox Reality on Desktop
async RequestFxrOutput();
child:

View File

@ -986,8 +986,6 @@ void gfxPlatform::Init() {
gPlatform->InitAcceleration();
gPlatform->InitWebRenderConfig();
gPlatform->InitWebGPUConfig();
// When using WebRender, we defer initialization of the D3D11 devices until
// the (rare) cases where they're used. Note that the GPU process where
// WebRender runs doesn't initialize gfxPlatform and performs explicit

View File

@ -1 +0,0 @@
{"files":{"Cargo.toml":"650501cb36febb1a25ce0218a5ccaeb01343f89389a97a43a50e4fd6e5a97a47","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0245ee104228a100ce5fceecf43e25faae450494d9173f43fd94c27d69fdac13","README.rst":"d8cac600ed199c2b77606f76c77cc201d93dfaf750e16b2dd76b2dcde1107bd0","benches/arraystring.rs":"f12b890977117ebde4ca42bcd6b91f2a6a087f2b235aaca6d15e30d125ae9f67","benches/extend.rs":"8c8f78df7e90b62c7e160cf5ea6c61b90bc4035a9704b6a179a1e01d8fafe2e9","build.rs":"fc29930f06cb4dde58f43d2f30b28c366ca3bafcd7e44b41a1c250d60fa900fb","custom.css":"e6f2cd299392337b4e2959c52f422e5b7be11920ea98d10db44d10ddef5ed47c","src/array.rs":"67fb063ee515bfd4968ede219dff81091a5935ef93529ebd1bb2a716ea3ed3d3","src/array_string.rs":"8a1a4cfc1699e2373815e57dc676a87a30629f91a9e861c866ccc6cb1381eadf","src/char.rs":"64a08f6a743b67bf2c96483f91c2fdaea79f6e91df5cd752f770b16a6b1d5b1e","src/errors.rs":"dde99bffaddfd45396aab7e07642cc018ef5435fe60c4f26a2c05a36555be18c","src/lib.rs":"566db78e5352be102d910e5826bb66cf3a4c4a5e9c68223d4e834c2793edcfc1","src/maybe_uninit.rs":"7cca39ffe0f122716baaa174b433ff5fe9c93560f8e54fc077a0083500eaa1dd","src/maybe_uninit_nodrop.rs":"7fb2e24bf815dd6e1d104056fa9be4a11de7e0f0e5474742af186c580a6b47cc","src/maybe_uninit_stable.rs":"3f7daba622cf5df86992b451b46636a491c9611292f59969eb6890a10a00476d","src/range.rs":"65744ab7def208a1ab155ea2448fe9ea7fc14f33211361b1041f540125b32efd","tests/serde.rs":"ef3986a82656b09f3fbb14358e767051ffabe09592c61e69ea695cb88760e8ba","tests/tests.rs":"8066a4aca7b40356525ed87f7658773e610ef4fce3522b0cc0f301384d880f00"},"package":"b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba"}

View File

@ -1,61 +0,0 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies
#
# If you believe there's an error in this file please file an
# issue against the rust-lang/cargo repository. If you're
# editing this file be aware that the upstream Cargo.toml
# will likely look very different (and much more reasonable)
[package]
name = "arrayvec"
version = "0.4.11"
authors = ["bluss"]
description = "A vector with fixed capacity, backed by an array (it can be stored on the stack too). Implements fixed capacity ArrayVec and ArrayString."
documentation = "https://docs.rs/arrayvec/"
keywords = ["stack", "vector", "array", "data-structure", "no_std"]
categories = ["data-structures", "no-std"]
license = "MIT/Apache-2.0"
repository = "https://github.com/bluss/arrayvec"
[package.metadata.docs.rs]
features = ["serde-1"]
[package.metadata.release]
no-dev-version = true
[[bench]]
name = "extend"
harness = false
[[bench]]
name = "arraystring"
harness = false
[dependencies.nodrop]
version = "0.1.12"
default-features = false
[dependencies.serde]
version = "1.0"
optional = true
default-features = false
[dev-dependencies.bencher]
version = "0.1.4"
[dev-dependencies.matches]
version = "0.1"
[dev-dependencies.serde_test]
version = "1.0"
[build-dependencies]
[features]
array-sizes-129-255 = []
array-sizes-33-128 = []
default = ["std"]
serde-1 = ["serde"]
std = []
use_union = []

View File

@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -1,25 +0,0 @@
Copyright (c) Ulrik Sverdrup "bluss" 2015-2017
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View File

@ -1,219 +0,0 @@
arrayvec
========
A vector with fixed capacity.
Please read the `API documentation here`__
__ https://docs.rs/arrayvec
|build_status|_ |crates|_ |crates2|_
.. |build_status| image:: https://travis-ci.org/bluss/arrayvec.svg
.. _build_status: https://travis-ci.org/bluss/arrayvec
.. |crates| image:: http://meritbadge.herokuapp.com/arrayvec
.. _crates: https://crates.io/crates/arrayvec
.. |crates2| image:: http://meritbadge.herokuapp.com/nodrop
.. _crates2: https://crates.io/crates/nodrop
Recent Changes (arrayvec)
-------------------------
- 0.4.11
- In Rust 1.36 or later, use newly stable MaybeUninit. This extends the
soundness work introduced in 0.4.9, we are finally able to use this in
stable. We use feature detection (build script) to enable this at build
time.
- 0.4.10
- Use ``repr(C)`` in the ``union`` version that was introduced in 0.4.9, to
allay some soundness concerns.
- 0.4.9
- Use ``union`` in the implementation on when this is detected to be supported
(nightly only for now). This is a better solution for treating uninitialized
regions correctly, and we'll use it in stable Rust as soon as we are able.
When this is enabled, the ``ArrayVec`` has no space overhead in its memory
layout, although the size of the vec should not be relied upon. (See `#114`_)
- ``ArrayString`` updated to not use uninitialized memory, it instead zeros its
backing array. This will be refined in the next version, since we
need to make changes to the user visible API.
- The ``use_union`` feature now does nothing (like its documentation foretold).
.. _`#114`: https://github.com/bluss/arrayvec/pull/114
- 0.4.8
- Implement Clone and Debug for ``IntoIter`` by @clarcharr
- Add more array sizes under crate features. These cover all in the range
up to 128 and 129 to 255 respectively (we have a few of those by default):
- ``array-size-33-128``
- ``array-size-129-255``
- 0.4.7
- Fix future compat warning about raw pointer casts
- Use ``drop_in_place`` when dropping the arrayvec by-value iterator
- Decrease mininum Rust version (see docs) by @jeehoonkang
- 0.3.25
- Fix future compat warning about raw pointer casts
- 0.4.6
- Fix compilation on 16-bit targets. This means, the 65536 array size is not
included on these targets.
- 0.3.24
- Fix compilation on 16-bit targets. This means, the 65536 array size is not
included on these targets.
- Fix license files so that they are both included (was fixed in 0.4 before)
- 0.4.5
- Add methods to ``ArrayString`` by @DenialAdams:
- ``.pop() -> Option<char>``
- ``.truncate(new_len)``
- ``.remove(index) -> char``
- Remove dependency on crate odds
- Document debug assertions in unsafe methods better
- 0.4.4
- Add method ``ArrayVec::truncate()`` by @niklasf
- 0.4.3
- Improve performance for ``ArrayVec::extend`` with a lower level
implementation (#74)
- Small cleanup in dependencies (use no std for crates where we don't need more)
- 0.4.2
- Add constructor method ``new`` to ``CapacityError``.
- 0.4.1
- Add ``Default`` impl to ``ArrayString`` by @tbu-
- 0.4.0
- Reformed signatures and error handling by @bluss and @tbu-:
- ``ArrayVec``'s ``push, insert, remove, swap_remove`` now match ``Vec``'s
corresponding signature and panic on capacity errors where applicable.
- Add fallible methods ``try_push, insert`` and checked methods
``pop_at, swap_pop``.
- Similar changes to ``ArrayString``'s push methods.
- Use a local version of the ``RangeArgument`` trait
- Add array sizes 50, 150, 200 by @daboross
- Support serde 1.0 by @daboross
- New method ``.push_unchecked()`` by @niklasf
- ``ArrayString`` implements ``PartialOrd, Ord`` by @tbu-
- Require Rust 1.14
- crate feature ``use_generic_array`` was dropped.
- 0.3.23
- Implement ``PartialOrd, Ord`` as well as ``PartialOrd<str>`` for
``ArrayString``.
- 0.3.22
- Implement ``Array`` for the 65536 size
- 0.3.21
- Use ``encode_utf8`` from crate odds
- Add constructor ``ArrayString::from_byte_string``
- 0.3.20
- Simplify and speed up ``ArrayString``s ``.push(char)``-
- 0.3.19
- Add new crate feature ``use_generic_array`` which allows using their
``GenericArray`` just like a regular fixed size array for the storage
of an ``ArrayVec``.
- 0.3.18
- Fix bounds check in ``ArrayVec::insert``!
It would be buggy if ``self.len() < index < self.capacity()``. Take note of
the push out behavior specified in the docs.
- 0.3.17
- Added crate feature ``use_union`` which forwards to the nodrop crate feature
- Added methods ``.is_full()`` to ``ArrayVec`` and ``ArrayString``.
- 0.3.16
- Added method ``.retain()`` to ``ArrayVec``.
- Added methods ``.as_slice(), .as_mut_slice()`` to ``ArrayVec`` and ``.as_str()``
to ``ArrayString``.
- 0.3.15
- Add feature std, which you can opt out of to use ``no_std`` (requires Rust 1.6
to opt out).
- Implement ``Clone::clone_from`` for ArrayVec and ArrayString
- 0.3.14
- Add ``ArrayString::from(&str)``
- 0.3.13
- Added ``DerefMut`` impl for ``ArrayString``.
- Added method ``.simplify()`` to drop the element for ``CapacityError``.
- Added method ``.dispose()`` to ``ArrayVec``
- 0.3.12
- Added ArrayString, a fixed capacity analogy of String
- 0.3.11
- Added trait impls Default, PartialOrd, Ord, Write for ArrayVec
- 0.3.10
- Go back to using external NoDrop, fixing a panic safety bug (issue #3)
- 0.3.8
- Inline the non-dropping logic to remove one drop flag in the
ArrayVec representation.
- 0.3.7
- Added method .into_inner()
- Added unsafe method .set_len()
License
=======
Dual-licensed to be compatible with the Rust project.
Licensed under the Apache License, Version 2.0
http://www.apache.org/licenses/LICENSE-2.0 or the MIT license
http://opensource.org/licenses/MIT, at your
option. This file may not be copied, modified, or distributed
except according to those terms.

View File

@ -1,90 +0,0 @@
extern crate arrayvec;
#[macro_use] extern crate bencher;
use arrayvec::ArrayString;
use bencher::Bencher;
fn try_push_c(b: &mut Bencher) {
let mut v = ArrayString::<[u8; 512]>::new();
b.iter(|| {
v.clear();
while v.try_push('c').is_ok() {
}
v.len()
});
b.bytes = v.capacity() as u64;
}
fn try_push_alpha(b: &mut Bencher) {
let mut v = ArrayString::<[u8; 512]>::new();
b.iter(|| {
v.clear();
while v.try_push('α').is_ok() {
}
v.len()
});
b.bytes = v.capacity() as u64;
}
// Yes, pushing a string char-by-char is slow. Use .push_str.
fn try_push_string(b: &mut Bencher) {
let mut v = ArrayString::<[u8; 512]>::new();
let input = "abcαβγ“”";
b.iter(|| {
v.clear();
for ch in input.chars().cycle() {
if !v.try_push(ch).is_ok() {
break;
}
}
v.len()
});
b.bytes = v.capacity() as u64;
}
fn push_c(b: &mut Bencher) {
let mut v = ArrayString::<[u8; 512]>::new();
b.iter(|| {
v.clear();
while !v.is_full() {
v.push('c');
}
v.len()
});
b.bytes = v.capacity() as u64;
}
fn push_alpha(b: &mut Bencher) {
let mut v = ArrayString::<[u8; 512]>::new();
b.iter(|| {
v.clear();
while !v.is_full() {
v.push('α');
}
v.len()
});
b.bytes = v.capacity() as u64;
}
fn push_string(b: &mut Bencher) {
let mut v = ArrayString::<[u8; 512]>::new();
let input = "abcαβγ“”";
b.iter(|| {
v.clear();
for ch in input.chars().cycle() {
if !v.is_full() {
v.push(ch);
} else {
break;
}
}
v.len()
});
b.bytes = v.capacity() as u64;
}
benchmark_group!(benches, try_push_c, try_push_alpha, try_push_string, push_c,
push_alpha, push_string);
benchmark_main!(benches);

View File

@ -1,43 +0,0 @@
extern crate arrayvec;
#[macro_use] extern crate bencher;
use arrayvec::ArrayVec;
use bencher::Bencher;
fn extend_with_constant(b: &mut Bencher) {
let mut v = ArrayVec::<[u8; 512]>::new();
let cap = v.capacity();
b.iter(|| {
v.clear();
v.extend((0..cap).map(|_| 1));
v[0]
});
b.bytes = v.capacity() as u64;
}
fn extend_with_range(b: &mut Bencher) {
let mut v = ArrayVec::<[u8; 512]>::new();
let cap = v.capacity();
b.iter(|| {
v.clear();
v.extend((0..cap).map(|x| x as _));
v[0]
});
b.bytes = v.capacity() as u64;
}
fn extend_with_slice(b: &mut Bencher) {
let mut v = ArrayVec::<[u8; 512]>::new();
let data = [1; 512];
b.iter(|| {
v.clear();
v.extend(data.iter().cloned());
v[0]
});
b.bytes = v.capacity() as u64;
}
benchmark_group!(benches, extend_with_constant, extend_with_range, extend_with_slice);
benchmark_main!(benches);

View File

@ -1,25 +0,0 @@
.docblock pre.rust { background: #eeeeff; }
pre.trait, pre.fn, pre.struct, pre.enum, pre.typedef { background: #fcfefc; }
/* Small “example” label for doc examples */
.docblock pre.rust::before {
content: "example";
float: right;
font-style: italic;
font-size: 0.8em;
margin-top: -10px;
margin-right: -5px;
}
/* Fixup where display in trait listing */
pre.trait .where::before {
content: '\a ';
}
.docblock code {
background-color: inherit;
font-weight: bold;
padding: 0 0.1em;
}

View File

@ -1,137 +0,0 @@
/// Trait for fixed size arrays.
///
/// This trait is implemented for some specific array sizes, see
/// the implementor list below. At the current state of Rust we can't
/// make this fully general for every array size.
///
/// The following crate features add more array sizes (and they are not
/// enabled by default due to their impact on compliation speed).
///
/// - `array-sizes-33-128`: All sizes 33 to 128 are implemented
/// (a few in this range are included by default).
/// - `array-sizes-129-255`: All sizes 129 to 255 are implemented
/// (a few in this range are included by default).
pub unsafe trait Array {
/// The arrays element type
type Item;
#[doc(hidden)]
/// The smallest index type that indexes the array.
type Index: Index;
#[doc(hidden)]
fn as_ptr(&self) -> *const Self::Item;
#[doc(hidden)]
fn as_mut_ptr(&mut self) -> *mut Self::Item;
#[doc(hidden)]
fn capacity() -> usize;
}
pub trait Index : PartialEq + Copy {
fn to_usize(self) -> usize;
fn from(usize) -> Self;
}
use std::slice::{from_raw_parts};
pub trait ArrayExt : Array {
#[inline(always)]
fn as_slice(&self) -> &[Self::Item] {
unsafe {
from_raw_parts(self.as_ptr(), Self::capacity())
}
}
}
impl<A> ArrayExt for A where A: Array { }
impl Index for u8 {
#[inline(always)]
fn to_usize(self) -> usize { self as usize }
#[inline(always)]
fn from(ix: usize) -> Self { ix as u8 }
}
impl Index for u16 {
#[inline(always)]
fn to_usize(self) -> usize { self as usize }
#[inline(always)]
fn from(ix: usize) -> Self { ix as u16 }
}
impl Index for u32 {
#[inline(always)]
fn to_usize(self) -> usize { self as usize }
#[inline(always)]
fn from(ix: usize) -> Self { ix as u32 }
}
impl Index for usize {
#[inline(always)]
fn to_usize(self) -> usize { self }
#[inline(always)]
fn from(ix: usize) -> Self { ix }
}
macro_rules! fix_array_impl {
($index_type:ty, $len:expr ) => (
unsafe impl<T> Array for [T; $len] {
type Item = T;
type Index = $index_type;
#[doc(hidden)]
#[inline(always)]
fn as_ptr(&self) -> *const T { self as *const _ as *const _ }
#[doc(hidden)]
#[inline(always)]
fn as_mut_ptr(&mut self) -> *mut T { self as *mut _ as *mut _}
#[doc(hidden)]
#[inline(always)]
fn capacity() -> usize { $len }
}
)
}
macro_rules! fix_array_impl_recursive {
($index_type:ty, ) => ();
($index_type:ty, $($len:expr,)*) => (
$(fix_array_impl!($index_type, $len);)*
);
}
fix_array_impl_recursive!(u8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
28, 29, 30, 31, );
#[cfg(not(feature="array-sizes-33-128"))]
fix_array_impl_recursive!(u8, 32, 40, 48, 50, 56, 64, 72, 96, 100, 128, );
#[cfg(feature="array-sizes-33-128")]
fix_array_impl_recursive!(u8,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108,
109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124,
125, 126, 127, 128,
);
#[cfg(not(feature="array-sizes-129-255"))]
fix_array_impl_recursive!(u8, 160, 192, 200, 224,);
#[cfg(feature="array-sizes-129-255")]
fix_array_impl_recursive!(u8,
129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140,
141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156,
157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172,
173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188,
189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204,
205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220,
221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236,
237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252,
253, 254, 255,
);
fix_array_impl_recursive!(u16, 256, 384, 512, 768, 1024, 2048, 4096, 8192, 16384, 32768,);
// This array size doesn't exist on 16-bit
#[cfg(any(target_pointer_width="32", target_pointer_width="64"))]
fix_array_impl_recursive!(u32, 1 << 16,);

View File

@ -1,516 +0,0 @@
use std::borrow::Borrow;
use std::cmp;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::mem;
use std::ptr;
use std::ops::{Deref, DerefMut};
use std::str;
use std::str::Utf8Error;
use std::slice;
use array::{Array, ArrayExt};
use array::Index;
use CapacityError;
use char::encode_utf8;
#[cfg(feature="serde-1")]
use serde::{Serialize, Deserialize, Serializer, Deserializer};
/// A string with a fixed capacity.
///
/// The `ArrayString` is a string backed by a fixed size array. It keeps track
/// of its length.
///
/// The string is a contiguous value that you can store directly on the stack
/// if needed.
#[derive(Copy)]
pub struct ArrayString<A: Array<Item=u8>> {
// FIXME: Use Copyable union for xs when we can
xs: A,
len: A::Index,
}
impl<A: Array<Item=u8>> Default for ArrayString<A> {
/// Return an empty `ArrayString`
fn default() -> ArrayString<A> {
ArrayString::new()
}
}
impl<A: Array<Item=u8>> ArrayString<A> {
/// Create a new empty `ArrayString`.
///
/// Capacity is inferred from the type parameter.
///
/// ```
/// use arrayvec::ArrayString;
///
/// let mut string = ArrayString::<[_; 16]>::new();
/// string.push_str("foo");
/// assert_eq!(&string[..], "foo");
/// assert_eq!(string.capacity(), 16);
/// ```
pub fn new() -> ArrayString<A> {
unsafe {
ArrayString {
// FIXME: Use Copyable union for xs when we can
xs: mem::zeroed(),
len: Index::from(0),
}
}
}
/// Create a new `ArrayString` from a `str`.
///
/// Capacity is inferred from the type parameter.
///
/// **Errors** if the backing array is not large enough to fit the string.
///
/// ```
/// use arrayvec::ArrayString;
///
/// let mut string = ArrayString::<[_; 3]>::from("foo").unwrap();
/// assert_eq!(&string[..], "foo");
/// assert_eq!(string.len(), 3);
/// assert_eq!(string.capacity(), 3);
/// ```
pub fn from(s: &str) -> Result<Self, CapacityError<&str>> {
let mut arraystr = Self::new();
arraystr.try_push_str(s)?;
Ok(arraystr)
}
/// Create a new `ArrayString` from a byte string literal.
///
/// **Errors** if the byte string literal is not valid UTF-8.
///
/// ```
/// use arrayvec::ArrayString;
///
/// let string = ArrayString::from_byte_string(b"hello world").unwrap();
/// ```
pub fn from_byte_string(b: &A) -> Result<Self, Utf8Error> {
let mut arraystr = Self::new();
let s = try!(str::from_utf8(b.as_slice()));
let _result = arraystr.try_push_str(s);
debug_assert!(_result.is_ok());
Ok(arraystr)
}
/// Return the capacity of the `ArrayString`.
///
/// ```
/// use arrayvec::ArrayString;
///
/// let string = ArrayString::<[_; 3]>::new();
/// assert_eq!(string.capacity(), 3);
/// ```
#[inline]
pub fn capacity(&self) -> usize { A::capacity() }
/// Return if the `ArrayString` is completely filled.
///
/// ```
/// use arrayvec::ArrayString;
///
/// let mut string = ArrayString::<[_; 1]>::new();
/// assert!(!string.is_full());
/// string.push_str("A");
/// assert!(string.is_full());
/// ```
pub fn is_full(&self) -> bool { self.len() == self.capacity() }
/// Adds the given char to the end of the string.
///
/// ***Panics*** if the backing array is not large enough to fit the additional char.
///
/// ```
/// use arrayvec::ArrayString;
///
/// let mut string = ArrayString::<[_; 2]>::new();
///
/// string.push('a');
/// string.push('b');
///
/// assert_eq!(&string[..], "ab");
/// ```
pub fn push(&mut self, c: char) {
self.try_push(c).unwrap();
}
/// Adds the given char to the end of the string.
///
/// Returns `Ok` if the push succeeds.
///
/// **Errors** if the backing array is not large enough to fit the additional char.
///
/// ```
/// use arrayvec::ArrayString;
///
/// let mut string = ArrayString::<[_; 2]>::new();
///
/// string.try_push('a').unwrap();
/// string.try_push('b').unwrap();
/// let overflow = string.try_push('c');
///
/// assert_eq!(&string[..], "ab");
/// assert_eq!(overflow.unwrap_err().element(), 'c');
/// ```
pub fn try_push(&mut self, c: char) -> Result<(), CapacityError<char>> {
let len = self.len();
unsafe {
match encode_utf8(c, &mut self.raw_mut_bytes()[len..]) {
Ok(n) => {
self.set_len(len + n);
Ok(())
}
Err(_) => Err(CapacityError::new(c)),
}
}
}
/// Adds the given string slice to the end of the string.
///
/// ***Panics*** if the backing array is not large enough to fit the string.
///
/// ```
/// use arrayvec::ArrayString;
///
/// let mut string = ArrayString::<[_; 2]>::new();
///
/// string.push_str("a");
/// string.push_str("d");
///
/// assert_eq!(&string[..], "ad");
/// ```
pub fn push_str(&mut self, s: &str) {
self.try_push_str(s).unwrap()
}
/// Adds the given string slice to the end of the string.
///
/// Returns `Ok` if the push succeeds.
///
/// **Errors** if the backing array is not large enough to fit the string.
///
/// ```
/// use arrayvec::ArrayString;
///
/// let mut string = ArrayString::<[_; 2]>::new();
///
/// string.try_push_str("a").unwrap();
/// let overflow1 = string.try_push_str("bc");
/// string.try_push_str("d").unwrap();
/// let overflow2 = string.try_push_str("ef");
///
/// assert_eq!(&string[..], "ad");
/// assert_eq!(overflow1.unwrap_err().element(), "bc");
/// assert_eq!(overflow2.unwrap_err().element(), "ef");
/// ```
pub fn try_push_str<'a>(&mut self, s: &'a str) -> Result<(), CapacityError<&'a str>> {
if s.len() > self.capacity() - self.len() {
return Err(CapacityError::new(s));
}
unsafe {
let dst = self.xs.as_mut_ptr().offset(self.len() as isize);
let src = s.as_ptr();
ptr::copy_nonoverlapping(src, dst, s.len());
let newl = self.len() + s.len();
self.set_len(newl);
}
Ok(())
}
/// Removes the last character from the string and returns it.
///
/// Returns `None` if this `ArrayString` is empty.
///
/// ```
/// use arrayvec::ArrayString;
///
/// let mut s = ArrayString::<[_; 3]>::from("foo").unwrap();
///
/// assert_eq!(s.pop(), Some('o'));
/// assert_eq!(s.pop(), Some('o'));
/// assert_eq!(s.pop(), Some('f'));
///
/// assert_eq!(s.pop(), None);
/// ```
#[inline]
pub fn pop(&mut self) -> Option<char> {
let ch = match self.chars().rev().next() {
Some(ch) => ch,
None => return None,
};
let new_len = self.len() - ch.len_utf8();
unsafe {
self.set_len(new_len);
}
Some(ch)
}
/// Shortens this `ArrayString` to the specified length.
///
/// If `new_len` is greater than the strings current length, this has no
/// effect.
///
/// ***Panics*** if `new_len` does not lie on a `char` boundary.
///
/// ```
/// use arrayvec::ArrayString;
///
/// let mut string = ArrayString::<[_; 6]>::from("foobar").unwrap();
/// string.truncate(3);
/// assert_eq!(&string[..], "foo");
/// string.truncate(4);
/// assert_eq!(&string[..], "foo");
/// ```
#[inline]
pub fn truncate(&mut self, new_len: usize) {
if new_len <= self.len() {
assert!(self.is_char_boundary(new_len));
unsafe {
// In libstd truncate is called on the underlying vector,
// which in turns drops each element.
// As we know we don't have to worry about Drop,
// we can just set the length (a la clear.)
self.set_len(new_len);
}
}
}
/// Removes a `char` from this `ArrayString` at a byte position and returns it.
///
/// This is an `O(n)` operation, as it requires copying every element in the
/// array.
///
/// ***Panics*** if `idx` is larger than or equal to the `ArrayString`s length,
/// or if it does not lie on a `char` boundary.
///
/// ```
/// use arrayvec::ArrayString;
///
/// let mut s = ArrayString::<[_; 3]>::from("foo").unwrap();
///
/// assert_eq!(s.remove(0), 'f');
/// assert_eq!(s.remove(1), 'o');
/// assert_eq!(s.remove(0), 'o');
/// ```
#[inline]
pub fn remove(&mut self, idx: usize) -> char {
let ch = match self[idx..].chars().next() {
Some(ch) => ch,
None => panic!("cannot remove a char from the end of a string"),
};
let next = idx + ch.len_utf8();
let len = self.len();
unsafe {
ptr::copy(self.xs.as_ptr().offset(next as isize),
self.xs.as_mut_ptr().offset(idx as isize),
len - next);
self.set_len(len - (next - idx));
}
ch
}
/// Make the string empty.
pub fn clear(&mut self) {
unsafe {
self.set_len(0);
}
}
/// Set the stringss length.
///
/// This function is `unsafe` because it changes the notion of the
/// number of “valid” bytes in the string. Use with care.
///
/// This method uses *debug assertions* to check the validity of `length`
/// and may use other debug assertions.
#[inline]
pub unsafe fn set_len(&mut self, length: usize) {
debug_assert!(length <= self.capacity());
self.len = Index::from(length);
}
/// Return a string slice of the whole `ArrayString`.
pub fn as_str(&self) -> &str {
self
}
/// Return a mutable slice of the whole strings buffer
unsafe fn raw_mut_bytes(&mut self) -> &mut [u8] {
slice::from_raw_parts_mut(self.xs.as_mut_ptr(), self.capacity())
}
}
impl<A: Array<Item=u8>> Deref for ArrayString<A> {
type Target = str;
#[inline]
fn deref(&self) -> &str {
unsafe {
let sl = slice::from_raw_parts(self.xs.as_ptr(), self.len.to_usize());
str::from_utf8_unchecked(sl)
}
}
}
impl<A: Array<Item=u8>> DerefMut for ArrayString<A> {
#[inline]
fn deref_mut(&mut self) -> &mut str {
unsafe {
let sl = slice::from_raw_parts_mut(self.xs.as_mut_ptr(), self.len.to_usize());
// FIXME: Nothing but transmute to do this right now
mem::transmute(sl)
}
}
}
impl<A: Array<Item=u8>> PartialEq for ArrayString<A> {
fn eq(&self, rhs: &Self) -> bool {
**self == **rhs
}
}
impl<A: Array<Item=u8>> PartialEq<str> for ArrayString<A> {
fn eq(&self, rhs: &str) -> bool {
&**self == rhs
}
}
impl<A: Array<Item=u8>> PartialEq<ArrayString<A>> for str {
fn eq(&self, rhs: &ArrayString<A>) -> bool {
self == &**rhs
}
}
impl<A: Array<Item=u8>> Eq for ArrayString<A> { }
impl<A: Array<Item=u8>> Hash for ArrayString<A> {
fn hash<H: Hasher>(&self, h: &mut H) {
(**self).hash(h)
}
}
impl<A: Array<Item=u8>> Borrow<str> for ArrayString<A> {
fn borrow(&self) -> &str { self }
}
impl<A: Array<Item=u8>> AsRef<str> for ArrayString<A> {
fn as_ref(&self) -> &str { self }
}
impl<A: Array<Item=u8>> fmt::Debug for ArrayString<A> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) }
}
impl<A: Array<Item=u8>> fmt::Display for ArrayString<A> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) }
}
/// `Write` appends written data to the end of the string.
impl<A: Array<Item=u8>> fmt::Write for ArrayString<A> {
fn write_char(&mut self, c: char) -> fmt::Result {
self.try_push(c).map_err(|_| fmt::Error)
}
fn write_str(&mut self, s: &str) -> fmt::Result {
self.try_push_str(s).map_err(|_| fmt::Error)
}
}
impl<A: Array<Item=u8> + Copy> Clone for ArrayString<A> {
fn clone(&self) -> ArrayString<A> {
*self
}
fn clone_from(&mut self, rhs: &Self) {
// guaranteed to fit due to types matching.
self.clear();
self.try_push_str(rhs).ok();
}
}
impl<A: Array<Item=u8>> PartialOrd for ArrayString<A> {
fn partial_cmp(&self, rhs: &Self) -> Option<cmp::Ordering> {
(**self).partial_cmp(&**rhs)
}
fn lt(&self, rhs: &Self) -> bool { **self < **rhs }
fn le(&self, rhs: &Self) -> bool { **self <= **rhs }
fn gt(&self, rhs: &Self) -> bool { **self > **rhs }
fn ge(&self, rhs: &Self) -> bool { **self >= **rhs }
}
impl<A: Array<Item=u8>> PartialOrd<str> for ArrayString<A> {
fn partial_cmp(&self, rhs: &str) -> Option<cmp::Ordering> {
(**self).partial_cmp(rhs)
}
fn lt(&self, rhs: &str) -> bool { &**self < rhs }
fn le(&self, rhs: &str) -> bool { &**self <= rhs }
fn gt(&self, rhs: &str) -> bool { &**self > rhs }
fn ge(&self, rhs: &str) -> bool { &**self >= rhs }
}
impl<A: Array<Item=u8>> PartialOrd<ArrayString<A>> for str {
fn partial_cmp(&self, rhs: &ArrayString<A>) -> Option<cmp::Ordering> {
self.partial_cmp(&**rhs)
}
fn lt(&self, rhs: &ArrayString<A>) -> bool { self < &**rhs }
fn le(&self, rhs: &ArrayString<A>) -> bool { self <= &**rhs }
fn gt(&self, rhs: &ArrayString<A>) -> bool { self > &**rhs }
fn ge(&self, rhs: &ArrayString<A>) -> bool { self >= &**rhs }
}
impl<A: Array<Item=u8>> Ord for ArrayString<A> {
fn cmp(&self, rhs: &Self) -> cmp::Ordering {
(**self).cmp(&**rhs)
}
}
#[cfg(feature="serde-1")]
/// Requires crate feature `"serde-1"`
impl<A: Array<Item=u8>> Serialize for ArrayString<A> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
serializer.serialize_str(&*self)
}
}
#[cfg(feature="serde-1")]
/// Requires crate feature `"serde-1"`
impl<'de, A: Array<Item=u8>> Deserialize<'de> for ArrayString<A> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>
{
use serde::de::{self, Visitor};
use std::marker::PhantomData;
struct ArrayStringVisitor<A: Array<Item=u8>>(PhantomData<A>);
impl<'de, A: Array<Item=u8>> Visitor<'de> for ArrayStringVisitor<A> {
type Value = ArrayString<A>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a string no more than {} bytes long", A::capacity())
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where E: de::Error,
{
ArrayString::from(v).map_err(|_| E::invalid_length(v.len(), &self))
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where E: de::Error,
{
let s = try!(str::from_utf8(v).map_err(|_| E::invalid_value(de::Unexpected::Bytes(v), &self)));
ArrayString::from(s).map_err(|_| E::invalid_length(s.len(), &self))
}
}
deserializer.deserialize_str(ArrayStringVisitor::<A>(PhantomData))
}
}

View File

@ -1,54 +0,0 @@
// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
// Original authors: alexchrichton, bluss
// UTF-8 ranges and tags for encoding characters
const TAG_CONT: u8 = 0b1000_0000;
const TAG_TWO_B: u8 = 0b1100_0000;
const TAG_THREE_B: u8 = 0b1110_0000;
const TAG_FOUR_B: u8 = 0b1111_0000;
const MAX_ONE_B: u32 = 0x80;
const MAX_TWO_B: u32 = 0x800;
const MAX_THREE_B: u32 = 0x10000;
/// Placeholder
pub struct EncodeUtf8Error;
/// Encode a char into buf using UTF-8.
///
/// On success, return the byte length of the encoding (1, 2, 3 or 4).<br>
/// On error, return `EncodeUtf8Error` if the buffer was too short for the char.
#[inline]
pub fn encode_utf8(ch: char, buf: &mut [u8]) -> Result<usize, EncodeUtf8Error>
{
let code = ch as u32;
if code < MAX_ONE_B && buf.len() >= 1 {
buf[0] = code as u8;
return Ok(1);
} else if code < MAX_TWO_B && buf.len() >= 2 {
buf[0] = (code >> 6 & 0x1F) as u8 | TAG_TWO_B;
buf[1] = (code & 0x3F) as u8 | TAG_CONT;
return Ok(2);
} else if code < MAX_THREE_B && buf.len() >= 3 {
buf[0] = (code >> 12 & 0x0F) as u8 | TAG_THREE_B;
buf[1] = (code >> 6 & 0x3F) as u8 | TAG_CONT;
buf[2] = (code & 0x3F) as u8 | TAG_CONT;
return Ok(3);
} else if buf.len() >= 4 {
buf[0] = (code >> 18 & 0x07) as u8 | TAG_FOUR_B;
buf[1] = (code >> 12 & 0x3F) as u8 | TAG_CONT;
buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT;
buf[3] = (code & 0x3F) as u8 | TAG_CONT;
return Ok(4);
};
Err(EncodeUtf8Error)
}

View File

@ -1,53 +0,0 @@
use std::fmt;
#[cfg(feature="std")]
use std::any::Any;
#[cfg(feature="std")]
use std::error::Error;
/// Error value indicating insufficient capacity
#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
pub struct CapacityError<T = ()> {
element: T,
}
impl<T> CapacityError<T> {
/// Create a new `CapacityError` from `element`.
pub fn new(element: T) -> CapacityError<T> {
CapacityError {
element: element,
}
}
/// Extract the overflowing element
pub fn element(self) -> T {
self.element
}
/// Convert into a `CapacityError` that does not carry an element.
pub fn simplify(self) -> CapacityError {
CapacityError { element: () }
}
}
const CAPERROR: &'static str = "insufficient capacity";
#[cfg(feature="std")]
/// Requires `features="std"`.
impl<T: Any> Error for CapacityError<T> {
fn description(&self) -> &str {
CAPERROR
}
}
impl<T> fmt::Display for CapacityError<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", CAPERROR)
}
}
impl<T> fmt::Debug for CapacityError<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}: {}", "CapacityError", CAPERROR)
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,46 +0,0 @@
use array::Array;
use std::mem::ManuallyDrop;
/// A combination of ManuallyDrop and “maybe uninitialized”;
/// this wraps a value that can be wholly or partially uninitialized;
/// it also has no drop regardless of the type of T.
#[repr(C)] // for cast from self ptr to value
pub union MaybeUninit<T> {
empty: (),
value: ManuallyDrop<T>,
}
// Why we don't use std's MaybeUninit on nightly? See the ptr method
impl<T> MaybeUninit<T> {
/// Create a new MaybeUninit with uninitialized interior
pub unsafe fn uninitialized() -> Self {
MaybeUninit { empty: () }
}
/// Create a new MaybeUninit from the value `v`.
pub fn from(v: T) -> Self {
MaybeUninit { value: ManuallyDrop::new(v) }
}
// Raw pointer casts written so that we don't reference or access the
// uninitialized interior value
/// Return a raw pointer to the start of the interior array
pub fn ptr(&self) -> *const T::Item
where T: Array
{
// std MaybeUninit creates a &self.value reference here which is
// not guaranteed to be sound in our case - we will partially
// initialize the value, not always wholly.
self as *const _ as *const T::Item
}
/// Return a mut raw pointer to the start of the interior array
pub fn ptr_mut(&mut self) -> *mut T::Item
where T: Array
{
self as *mut _ as *mut T::Item
}
}

View File

@ -1,79 +0,0 @@
#![cfg(feature = "serde-1")]
extern crate arrayvec;
extern crate serde_test;
mod array_vec {
use arrayvec::ArrayVec;
use serde_test::{Token, assert_tokens, assert_de_tokens_error};
#[test]
fn test_ser_de_empty() {
let vec = ArrayVec::<[u32; 0]>::new();
assert_tokens(&vec, &[
Token::Seq { len: Some(0) },
Token::SeqEnd,
]);
}
#[test]
fn test_ser_de() {
let mut vec = ArrayVec::<[u32; 3]>::new();
vec.push(20);
vec.push(55);
vec.push(123);
assert_tokens(&vec, &[
Token::Seq { len: Some(3) },
Token::U32(20),
Token::U32(55),
Token::U32(123),
Token::SeqEnd,
]);
}
#[test]
fn test_de_too_large() {
assert_de_tokens_error::<ArrayVec<[u32; 2]>>(&[
Token::Seq { len: Some(3) },
Token::U32(13),
Token::U32(42),
Token::U32(68),
], "invalid length 3, expected an array with no more than 2 items");
}
}
mod array_string {
use arrayvec::ArrayString;
use serde_test::{Token, assert_tokens, assert_de_tokens_error};
#[test]
fn test_ser_de_empty() {
let string = ArrayString::<[u8; 0]>::new();
assert_tokens(&string, &[
Token::Str(""),
]);
}
#[test]
fn test_ser_de() {
let string = ArrayString::<[u8; 9]>::from("1234 abcd")
.expect("expected exact specified capacity to be enough");
assert_tokens(&string, &[
Token::Str("1234 abcd"),
]);
}
#[test]
fn test_de_too_large() {
assert_de_tokens_error::<ArrayString<[u8; 2]>>(&[
Token::Str("afd")
], "invalid length 3, expected a string no more than 2 bytes long");
}
}

View File

@ -1,517 +0,0 @@
extern crate arrayvec;
#[macro_use] extern crate matches;
use arrayvec::ArrayVec;
use arrayvec::ArrayString;
use std::mem;
use arrayvec::CapacityError;
use std::collections::HashMap;
#[test]
fn test_simple() {
use std::ops::Add;
let mut vec: ArrayVec<[Vec<i32>; 3]> = ArrayVec::new();
vec.push(vec![1, 2, 3, 4]);
vec.push(vec![10]);
vec.push(vec![-1, 13, -2]);
for elt in &vec {
assert_eq!(elt.iter().fold(0, Add::add), 10);
}
let sum_len = vec.into_iter().map(|x| x.len()).fold(0, Add::add);
assert_eq!(sum_len, 8);
}
#[test]
fn test_u16_index() {
const N: usize = 4096;
let mut vec: ArrayVec<[_; N]> = ArrayVec::new();
for _ in 0..N {
assert!(vec.try_push(1u8).is_ok());
}
assert!(vec.try_push(0).is_err());
assert_eq!(vec.len(), N);
}
#[test]
fn test_iter() {
let mut iter = ArrayVec::from([1, 2, 3]).into_iter();
assert_eq!(iter.size_hint(), (3, Some(3)));
assert_eq!(iter.next_back(), Some(3));
assert_eq!(iter.next(), Some(1));
assert_eq!(iter.next_back(), Some(2));
assert_eq!(iter.size_hint(), (0, Some(0)));
assert_eq!(iter.next_back(), None);
}
#[test]
fn test_drop() {
use std::cell::Cell;
let flag = &Cell::new(0);
#[derive(Clone)]
struct Bump<'a>(&'a Cell<i32>);
impl<'a> Drop for Bump<'a> {
fn drop(&mut self) {
let n = self.0.get();
self.0.set(n + 1);
}
}
{
let mut array = ArrayVec::<[Bump; 128]>::new();
array.push(Bump(flag));
array.push(Bump(flag));
}
assert_eq!(flag.get(), 2);
// test something with the nullable pointer optimization
flag.set(0);
{
let mut array = ArrayVec::<[_; 3]>::new();
array.push(vec![Bump(flag)]);
array.push(vec![Bump(flag), Bump(flag)]);
array.push(vec![]);
let push4 = array.try_push(vec![Bump(flag)]);
assert_eq!(flag.get(), 0);
drop(push4);
assert_eq!(flag.get(), 1);
drop(array.pop());
assert_eq!(flag.get(), 1);
drop(array.pop());
assert_eq!(flag.get(), 3);
}
assert_eq!(flag.get(), 4);
// test into_inner
flag.set(0);
{
let mut array = ArrayVec::<[_; 3]>::new();
array.push(Bump(flag));
array.push(Bump(flag));
array.push(Bump(flag));
let inner = array.into_inner();
assert!(inner.is_ok());
assert_eq!(flag.get(), 0);
drop(inner);
assert_eq!(flag.get(), 3);
}
// test cloning into_iter
flag.set(0);
{
let mut array = ArrayVec::<[_; 3]>::new();
array.push(Bump(flag));
array.push(Bump(flag));
array.push(Bump(flag));
let mut iter = array.into_iter();
assert_eq!(flag.get(), 0);
iter.next();
assert_eq!(flag.get(), 1);
let clone = iter.clone();
assert_eq!(flag.get(), 1);
drop(clone);
assert_eq!(flag.get(), 3);
drop(iter);
assert_eq!(flag.get(), 5);
}
}
#[test]
fn test_extend() {
let mut range = 0..10;
let mut array: ArrayVec<[_; 5]> = range.by_ref().collect();
assert_eq!(&array[..], &[0, 1, 2, 3, 4]);
assert_eq!(range.next(), Some(5));
array.extend(range.by_ref());
assert_eq!(range.next(), Some(6));
let mut array: ArrayVec<[_; 10]> = (0..3).collect();
assert_eq!(&array[..], &[0, 1, 2]);
array.extend(3..5);
assert_eq!(&array[..], &[0, 1, 2, 3, 4]);
}
#[test]
fn test_is_send_sync() {
let data = ArrayVec::<[Vec<i32>; 5]>::new();
&data as &Send;
&data as &Sync;
}
#[test]
fn test_compact_size() {
// Future rust will kill these drop flags!
// 4 elements size + 1 len + 1 enum tag + [1 drop flag]
type ByteArray = ArrayVec<[u8; 4]>;
println!("{}", mem::size_of::<ByteArray>());
assert!(mem::size_of::<ByteArray>() <= 8);
// 12 element size + 1 enum tag + 3 padding + 1 len + 1 drop flag + 2 padding
type QuadArray = ArrayVec<[u32; 3]>;
println!("{}", mem::size_of::<QuadArray>());
assert!(mem::size_of::<QuadArray>() <= 24);
}
#[test]
fn test_still_works_with_option_arrayvec() {
type RefArray = ArrayVec<[&'static i32; 2]>;
let array = Some(RefArray::new());
assert!(array.is_some());
println!("{:?}", array);
}
#[test]
fn test_drain() {
let mut v = ArrayVec::from([0; 8]);
v.pop();
v.drain(0..7);
assert_eq!(&v[..], &[]);
v.extend(0..);
v.drain(1..4);
assert_eq!(&v[..], &[0, 4, 5, 6, 7]);
let u: ArrayVec<[_; 3]> = v.drain(1..4).rev().collect();
assert_eq!(&u[..], &[6, 5, 4]);
assert_eq!(&v[..], &[0, 7]);
v.drain(..);
assert_eq!(&v[..], &[]);
}
#[test]
fn test_retain() {
let mut v = ArrayVec::from([0; 8]);
for (i, elt) in v.iter_mut().enumerate() {
*elt = i;
}
v.retain(|_| true);
assert_eq!(&v[..], &[0, 1, 2, 3, 4, 5, 6, 7]);
v.retain(|elt| {
*elt /= 2;
*elt % 2 == 0
});
assert_eq!(&v[..], &[0, 0, 2, 2]);
v.retain(|_| false);
assert_eq!(&v[..], &[]);
}
#[test]
#[should_panic]
fn test_drain_oob() {
let mut v = ArrayVec::from([0; 8]);
v.pop();
v.drain(0..8);
}
#[test]
#[should_panic]
fn test_drop_panic() {
struct DropPanic;
impl Drop for DropPanic {
fn drop(&mut self) {
panic!("drop");
}
}
let mut array = ArrayVec::<[DropPanic; 1]>::new();
array.push(DropPanic);
}
#[test]
#[should_panic]
fn test_drop_panic_into_iter() {
struct DropPanic;
impl Drop for DropPanic {
fn drop(&mut self) {
panic!("drop");
}
}
let mut array = ArrayVec::<[DropPanic; 1]>::new();
array.push(DropPanic);
array.into_iter();
}
#[test]
fn test_insert() {
let mut v = ArrayVec::from([]);
assert_matches!(v.try_push(1), Err(_));
let mut v = ArrayVec::<[_; 3]>::new();
v.insert(0, 0);
v.insert(1, 1);
//let ret1 = v.try_insert(3, 3);
//assert_matches!(ret1, Err(InsertError::OutOfBounds(_)));
assert_eq!(&v[..], &[0, 1]);
v.insert(2, 2);
assert_eq!(&v[..], &[0, 1, 2]);
let ret2 = v.try_insert(1, 9);
assert_eq!(&v[..], &[0, 1, 2]);
assert_matches!(ret2, Err(_));
let mut v = ArrayVec::from([2]);
assert_matches!(v.try_insert(0, 1), Err(CapacityError { .. }));
assert_matches!(v.try_insert(1, 1), Err(CapacityError { .. }));
//assert_matches!(v.try_insert(2, 1), Err(CapacityError { .. }));
}
#[test]
fn test_into_inner_1() {
let mut v = ArrayVec::from([1, 2]);
v.pop();
let u = v.clone();
assert_eq!(v.into_inner(), Err(u));
}
#[test]
fn test_into_inner_2() {
let mut v = ArrayVec::<[String; 4]>::new();
v.push("a".into());
v.push("b".into());
v.push("c".into());
v.push("d".into());
assert_eq!(v.into_inner().unwrap(), ["a", "b", "c", "d"]);
}
#[test]
fn test_into_inner_3_() {
let mut v = ArrayVec::<[i32; 4]>::new();
v.extend(1..);
assert_eq!(v.into_inner().unwrap(), [1, 2, 3, 4]);
}
#[test]
fn test_write() {
use std::io::Write;
let mut v = ArrayVec::<[_; 8]>::new();
write!(&mut v, "\x01\x02\x03").unwrap();
assert_eq!(&v[..], &[1, 2, 3]);
let r = v.write(&[9; 16]).unwrap();
assert_eq!(r, 5);
assert_eq!(&v[..], &[1, 2, 3, 9, 9, 9, 9, 9]);
}
#[test]
fn array_clone_from() {
let mut v = ArrayVec::<[_; 4]>::new();
v.push(vec![1, 2]);
v.push(vec![3, 4, 5]);
v.push(vec![6]);
let reference = v.to_vec();
let mut u = ArrayVec::<[_; 4]>::new();
u.clone_from(&v);
assert_eq!(&u, &reference[..]);
let mut t = ArrayVec::<[_; 4]>::new();
t.push(vec![97]);
t.push(vec![]);
t.push(vec![5, 6, 2]);
t.push(vec![2]);
t.clone_from(&v);
assert_eq!(&t, &reference[..]);
t.clear();
t.clone_from(&v);
assert_eq!(&t, &reference[..]);
}
#[test]
fn test_string() {
use std::error::Error;
let text = "hello world";
let mut s = ArrayString::<[_; 16]>::new();
s.try_push_str(text).unwrap();
assert_eq!(&s, text);
assert_eq!(text, &s);
// Make sure Hash / Eq / Borrow match up so we can use HashMap
let mut map = HashMap::new();
map.insert(s, 1);
assert_eq!(map[text], 1);
let mut t = ArrayString::<[_; 2]>::new();
assert!(t.try_push_str(text).is_err());
assert_eq!(&t, "");
t.push_str("ab");
// DerefMut
let tmut: &mut str = &mut t;
assert_eq!(tmut, "ab");
// Test Error trait / try
let t = || -> Result<(), Box<Error>> {
let mut t = ArrayString::<[_; 2]>::new();
try!(t.try_push_str(text));
Ok(())
}();
assert!(t.is_err());
}
#[test]
fn test_string_from() {
let text = "hello world";
// Test `from` constructor
let u = ArrayString::<[_; 11]>::from(text).unwrap();
assert_eq!(&u, text);
assert_eq!(u.len(), text.len());
}
#[test]
fn test_string_from_bytes() {
let text = "hello world";
let u = ArrayString::from_byte_string(b"hello world").unwrap();
assert_eq!(&u, text);
assert_eq!(u.len(), text.len());
}
#[test]
fn test_string_clone() {
let text = "hi";
let mut s = ArrayString::<[_; 4]>::new();
s.push_str("abcd");
let t = ArrayString::<[_; 4]>::from(text).unwrap();
s.clone_from(&t);
assert_eq!(&t, &s);
}
#[test]
fn test_string_push() {
let text = "abcαβγ";
let mut s = ArrayString::<[_; 8]>::new();
for c in text.chars() {
if let Err(_) = s.try_push(c) {
break;
}
}
assert_eq!("abcαβ", &s[..]);
s.push('x');
assert_eq!("abcαβx", &s[..]);
assert!(s.try_push('x').is_err());
}
#[test]
fn test_insert_at_length() {
let mut v = ArrayVec::<[_; 8]>::new();
let result1 = v.try_insert(0, "a");
let result2 = v.try_insert(1, "b");
assert!(result1.is_ok() && result2.is_ok());
assert_eq!(&v[..], &["a", "b"]);
}
#[should_panic]
#[test]
fn test_insert_out_of_bounds() {
let mut v = ArrayVec::<[_; 8]>::new();
let _ = v.try_insert(1, "test");
}
/*
* insert that pushes out the last
let mut u = ArrayVec::from([1, 2, 3, 4]);
let ret = u.try_insert(3, 99);
assert_eq!(&u[..], &[1, 2, 3, 99]);
assert_matches!(ret, Err(_));
let ret = u.try_insert(4, 77);
assert_eq!(&u[..], &[1, 2, 3, 99]);
assert_matches!(ret, Err(_));
*/
#[test]
fn test_drop_in_insert() {
use std::cell::Cell;
let flag = &Cell::new(0);
struct Bump<'a>(&'a Cell<i32>);
impl<'a> Drop for Bump<'a> {
fn drop(&mut self) {
let n = self.0.get();
self.0.set(n + 1);
}
}
flag.set(0);
{
let mut array = ArrayVec::<[_; 2]>::new();
array.push(Bump(flag));
array.insert(0, Bump(flag));
assert_eq!(flag.get(), 0);
let ret = array.try_insert(1, Bump(flag));
assert_eq!(flag.get(), 0);
assert_matches!(ret, Err(_));
drop(ret);
assert_eq!(flag.get(), 1);
}
assert_eq!(flag.get(), 3);
}
#[test]
fn test_pop_at() {
let mut v = ArrayVec::<[String; 4]>::new();
let s = String::from;
v.push(s("a"));
v.push(s("b"));
v.push(s("c"));
v.push(s("d"));
assert_eq!(v.pop_at(4), None);
assert_eq!(v.pop_at(1), Some(s("b")));
assert_eq!(v.pop_at(1), Some(s("c")));
assert_eq!(v.pop_at(2), None);
assert_eq!(&v[..], &["a", "d"]);
}
#[test]
fn test_sizes() {
let v = ArrayVec::from([0u8; 1 << 16]);
assert_eq!(vec![0u8; v.len()], &v[..]);
}
#[test]
fn test_default() {
use std::net;
let s: ArrayString<[u8; 4]> = Default::default();
// Something without `Default` implementation.
let v: ArrayVec<[net::TcpStream; 4]> = Default::default();
assert_eq!(s.len(), 0);
assert_eq!(v.len(), 0);
}
#[cfg(feature="array-sizes-33-128")]
#[test]
fn test_sizes_33_128() {
ArrayVec::from([0u8; 52]);
ArrayVec::from([0u8; 127]);
}
#[cfg(feature="array-sizes-129-255")]
#[test]
fn test_sizes_129_255() {
ArrayVec::from([0u8; 237]);
ArrayVec::from([0u8; 255]);
}
#[test]
fn test_newish_stable_uses_maybe_uninit() {
if option_env!("ARRAYVECTEST_ENSURE_MAYBEUNINIT").map(|s| !s.is_empty()).unwrap_or(false) {
assert!(cfg!(has_stable_maybe_uninit));
}
}

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"e7405a91fea075bb4fedb0e76e2039af27d6c380beaa31150f37655d79a7a3ab","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0245ee104228a100ce5fceecf43e25faae450494d9173f43fd94c27d69fdac13","README.rst":"8fab86c3c759d153a1a8a48e5f7f48546c898f0ec91433001c57fe0002af6455","benches/arraystring.rs":"f12b890977117ebde4ca42bcd6b91f2a6a087f2b235aaca6d15e30d125ae9f67","benches/extend.rs":"c3d69cc488ec5341b019cfed545ebbfea252f98718037b413f6a349da9489d1b","custom.css":"e6f2cd299392337b4e2959c52f422e5b7be11920ea98d10db44d10ddef5ed47c","src/array.rs":"8a42b3ff7a5a0713e8ee22462f303b0ce15bdc49a9fd5eb64f58e56855bdf944","src/array_string.rs":"fdcc24f0fd07e781b378f5d0190279e6d9c89b422f67e546ae443c602f967896","src/char.rs":"40af597d93895f206abcd33953b5d3d5a512d3b16ff5f96e492e659d9cca4209","src/errors.rs":"dde99bffaddfd45396aab7e07642cc018ef5435fe60c4f26a2c05a36555be18c","src/lib.rs":"4c00e50b532aec68b52fde4a737b7b5980b0cfb28f5c09ab8408d04896895a87","src/maybe_uninit.rs":"00659a86e8f84852d4355077a16beceaad0440ac0e81851fbac712fdb1850622","tests/serde.rs":"18c165cf6024f04a25b19aa139657d7c59f72d1541c9b24b44f9eaea01f507db","tests/tests.rs":"9633b92fe6c650b9b816cecac23b9c9e6a0365b1f67d4f0bfaad9e645e2bdc49"},"package":"cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"}
{"files":{"Cargo.toml":"650501cb36febb1a25ce0218a5ccaeb01343f89389a97a43a50e4fd6e5a97a47","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0245ee104228a100ce5fceecf43e25faae450494d9173f43fd94c27d69fdac13","README.rst":"d8cac600ed199c2b77606f76c77cc201d93dfaf750e16b2dd76b2dcde1107bd0","benches/arraystring.rs":"f12b890977117ebde4ca42bcd6b91f2a6a087f2b235aaca6d15e30d125ae9f67","benches/extend.rs":"8c8f78df7e90b62c7e160cf5ea6c61b90bc4035a9704b6a179a1e01d8fafe2e9","build.rs":"fc29930f06cb4dde58f43d2f30b28c366ca3bafcd7e44b41a1c250d60fa900fb","custom.css":"e6f2cd299392337b4e2959c52f422e5b7be11920ea98d10db44d10ddef5ed47c","src/array.rs":"67fb063ee515bfd4968ede219dff81091a5935ef93529ebd1bb2a716ea3ed3d3","src/array_string.rs":"8a1a4cfc1699e2373815e57dc676a87a30629f91a9e861c866ccc6cb1381eadf","src/char.rs":"64a08f6a743b67bf2c96483f91c2fdaea79f6e91df5cd752f770b16a6b1d5b1e","src/errors.rs":"dde99bffaddfd45396aab7e07642cc018ef5435fe60c4f26a2c05a36555be18c","src/lib.rs":"566db78e5352be102d910e5826bb66cf3a4c4a5e9c68223d4e834c2793edcfc1","src/maybe_uninit.rs":"7cca39ffe0f122716baaa174b433ff5fe9c93560f8e54fc077a0083500eaa1dd","src/maybe_uninit_nodrop.rs":"7fb2e24bf815dd6e1d104056fa9be4a11de7e0f0e5474742af186c580a6b47cc","src/maybe_uninit_stable.rs":"3f7daba622cf5df86992b451b46636a491c9611292f59969eb6890a10a00476d","src/range.rs":"65744ab7def208a1ab155ea2448fe9ea7fc14f33211361b1041f540125b32efd","tests/serde.rs":"ef3986a82656b09f3fbb14358e767051ffabe09592c61e69ea695cb88760e8ba","tests/tests.rs":"8066a4aca7b40356525ed87f7658773e610ef4fce3522b0cc0f301384d880f00"},"package":"b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba"}

View File

@ -11,9 +11,8 @@
# will likely look very different (and much more reasonable)
[package]
edition = "2018"
name = "arrayvec"
version = "0.5.1"
version = "0.4.11"
authors = ["bluss"]
description = "A vector with fixed capacity, backed by an array (it can be stored on the stack too). Implements fixed capacity ArrayVec and ArrayString."
documentation = "https://docs.rs/arrayvec/"
@ -22,16 +21,10 @@ categories = ["data-structures", "no-std"]
license = "MIT/Apache-2.0"
repository = "https://github.com/bluss/arrayvec"
[package.metadata.docs.rs]
features = ["serde"]
features = ["serde-1"]
[package.metadata.release]
no-dev-version = true
tag-name = "{{version}}"
[profile.bench]
debug = true
[profile.release]
debug = true
[[bench]]
name = "extend"
@ -40,6 +33,10 @@ harness = false
[[bench]]
name = "arraystring"
harness = false
[dependencies.nodrop]
version = "0.1.12"
default-features = false
[dependencies.serde]
version = "1.0"
optional = true
@ -59,4 +56,6 @@ version = "1.0"
array-sizes-129-255 = []
array-sizes-33-128 = []
default = ["std"]
serde-1 = ["serde"]
std = []
use_union = []

View File

@ -22,46 +22,6 @@ __ https://docs.rs/arrayvec
Recent Changes (arrayvec)
-------------------------
- 0.5.1
- Add ``as_ptr``, ``as_mut_ptr`` accessors directly on the ``ArrayVec`` by @tbu-
(matches the same addition to ``Vec`` which happened in Rust 1.37).
- Add method ``ArrayString::len`` (now available directly, not just through deref to str).
- Use raw pointers instead of ``&mut [u8]`` for encoding chars into ``ArrayString``
(uninit best practice fix).
- Use raw pointers instead of ``get_unchecked_mut`` where the target may be
uninitialized a everywhere relevant in the ArrayVec implementation
(uninit best practice fix).
- Changed inline hints on many methods, mainly removing inline hints
- ``ArrayVec::dispose`` is now deprecated (it has no purpose anymore)
- 0.4.12
- Use raw pointers instead of ``get_unchecked_mut`` where the target may be
uninitialized a everywhere relevant in the ArrayVec implementation.
- 0.5.0
- Use ``MaybeUninit`` (now unconditionally) in the implementation of
``ArrayVec``
- Use ``MaybeUninit`` (now unconditionally) in the implementation of
``ArrayString``
- The crate feature for serde serialization is now named ``serde``.
- Updated the ``Array`` trait interface, and it is now easier to use for
users outside the crate.
- Add ``FromStr`` impl for ``ArrayString`` by @despawnerer
- Add method ``try_extend_from_slice`` to ``ArrayVec``, which is always
effecient by @Thomasdezeeuw.
- Add method ``remaining_capacity`` by @Thomasdezeeuw
- Improve performance of the ``extend`` method.
- The index type of zero capacity vectors is now itself zero size, by
@clarfon
- Use ``drop_in_place`` for truncate and clear methods. This affects drop order
and resume from panic during drop.
- Use Rust 2018 edition for the implementation
- Require Rust 1.36 or later, for the unconditional ``MaybeUninit``
improvements.
- 0.4.11
- In Rust 1.36 or later, use newly stable MaybeUninit. This extends the

View File

@ -2,21 +2,17 @@
extern crate arrayvec;
#[macro_use] extern crate bencher;
use std::io::Write;
use arrayvec::ArrayVec;
use bencher::Bencher;
use bencher::black_box;
fn extend_with_constant(b: &mut Bencher) {
let mut v = ArrayVec::<[u8; 512]>::new();
let cap = v.capacity();
b.iter(|| {
v.clear();
let constant = black_box(1);
v.extend((0..cap).map(move |_| constant));
v[511]
v.extend((0..cap).map(|_| 1));
v[0]
});
b.bytes = v.capacity() as u64;
}
@ -26,9 +22,8 @@ fn extend_with_range(b: &mut Bencher) {
let cap = v.capacity();
b.iter(|| {
v.clear();
let range = 0..cap;
v.extend(range.map(|x| black_box(x as _)));
v[511]
v.extend((0..cap).map(|x| x as _));
v[0]
});
b.bytes = v.capacity() as u64;
}
@ -38,41 +33,11 @@ fn extend_with_slice(b: &mut Bencher) {
let data = [1; 512];
b.iter(|| {
v.clear();
let iter = data.iter().map(|&x| x);
v.extend(iter);
v[511]
v.extend(data.iter().cloned());
v[0]
});
b.bytes = v.capacity() as u64;
}
fn extend_with_write(b: &mut Bencher) {
let mut v = ArrayVec::<[u8; 512]>::new();
let data = [1; 512];
b.iter(|| {
v.clear();
v.write(&data[..]).ok();
v[511]
});
b.bytes = v.capacity() as u64;
}
fn extend_from_slice(b: &mut Bencher) {
let mut v = ArrayVec::<[u8; 512]>::new();
let data = [1; 512];
b.iter(|| {
v.clear();
v.try_extend_from_slice(&data).ok();
v[511]
});
b.bytes = v.capacity() as u64;
}
benchmark_group!(benches,
extend_with_constant,
extend_with_range,
extend_with_slice,
extend_with_write,
extend_from_slice
);
benchmark_group!(benches, extend_with_constant, extend_with_range, extend_with_slice);
benchmark_main!(benches);

View File

@ -12,45 +12,37 @@
/// (a few in this range are included by default).
/// - `array-sizes-129-255`: All sizes 129 to 255 are implemented
/// (a few in this range are included by default).
///
/// ## Safety
///
/// This trait can *only* be implemented by fixed-size arrays or types with
/// *exactly* the representation of a fixed size array (of the right element
/// type and capacity).
///
/// Normally this trait is an implementation detail of arrayvec and doesnt
/// need implementing.
pub unsafe trait Array {
/// The arrays element type
type Item;
/// The smallest type that can index and tell the length of the array.
#[doc(hidden)]
/// The smallest index type that indexes the array.
type Index: Index;
/// The array's element capacity
const CAPACITY: usize;
fn as_slice(&self) -> &[Self::Item];
fn as_mut_slice(&mut self) -> &mut [Self::Item];
#[doc(hidden)]
fn as_ptr(&self) -> *const Self::Item;
#[doc(hidden)]
fn as_mut_ptr(&mut self) -> *mut Self::Item;
#[doc(hidden)]
fn capacity() -> usize;
}
pub trait Index : PartialEq + Copy {
fn to_usize(self) -> usize;
fn from(_: usize) -> Self;
fn from(usize) -> Self;
}
impl Index for () {
use std::slice::{from_raw_parts};
pub trait ArrayExt : Array {
#[inline(always)]
fn to_usize(self) -> usize { 0 }
#[inline(always)]
fn from(_ix: usize) -> Self { () }
fn as_slice(&self) -> &[Self::Item] {
unsafe {
from_raw_parts(self.as_ptr(), Self::capacity())
}
}
}
impl Index for bool {
#[inline(always)]
fn to_usize(self) -> usize { self as usize }
#[inline(always)]
fn from(ix: usize) -> Self { ix != 0 }
}
impl<A> ArrayExt for A where A: Array { }
impl Index for u8 {
#[inline(always)]
@ -85,11 +77,15 @@ macro_rules! fix_array_impl {
unsafe impl<T> Array for [T; $len] {
type Item = T;
type Index = $index_type;
const CAPACITY: usize = $len;
#[doc(hidden)]
fn as_slice(&self) -> &[Self::Item] { self }
#[inline(always)]
fn as_ptr(&self) -> *const T { self as *const _ as *const _ }
#[doc(hidden)]
fn as_mut_slice(&mut self) -> &mut [Self::Item] { self }
#[inline(always)]
fn as_mut_ptr(&mut self) -> *mut T { self as *mut _ as *mut _}
#[doc(hidden)]
#[inline(always)]
fn capacity() -> usize { $len }
}
)
}
@ -101,10 +97,7 @@ macro_rules! fix_array_impl_recursive {
);
}
fix_array_impl_recursive!((), 0,);
fix_array_impl_recursive!(bool, 1,);
fix_array_impl_recursive!(u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
fix_array_impl_recursive!(u8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
28, 29, 30, 31, );

View File

@ -2,23 +2,21 @@ use std::borrow::Borrow;
use std::cmp;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::mem;
use std::ptr;
use std::ops::{Deref, DerefMut};
use std::str;
use std::str::FromStr;
use std::str::Utf8Error;
use std::slice;
use crate::array::Array;
use crate::array::Index;
use crate::CapacityError;
use crate::char::encode_utf8;
use array::{Array, ArrayExt};
use array::Index;
use CapacityError;
use char::encode_utf8;
#[cfg(feature="serde")]
#[cfg(feature="serde-1")]
use serde::{Serialize, Deserialize, Serializer, Deserializer};
use super::MaybeUninit as MaybeUninitCopy;
/// A string with a fixed capacity.
///
/// The `ArrayString` is a string backed by a fixed size array. It keeps track
@ -27,25 +25,20 @@ use super::MaybeUninit as MaybeUninitCopy;
/// The string is a contiguous value that you can store directly on the stack
/// if needed.
#[derive(Copy)]
pub struct ArrayString<A>
where A: Array<Item=u8> + Copy
{
xs: MaybeUninitCopy<A>,
pub struct ArrayString<A: Array<Item=u8>> {
// FIXME: Use Copyable union for xs when we can
xs: A,
len: A::Index,
}
impl<A> Default for ArrayString<A>
where A: Array<Item=u8> + Copy
{
impl<A: Array<Item=u8>> Default for ArrayString<A> {
/// Return an empty `ArrayString`
fn default() -> ArrayString<A> {
ArrayString::new()
}
}
impl<A> ArrayString<A>
where A: Array<Item=u8> + Copy
{
impl<A: Array<Item=u8>> ArrayString<A> {
/// Create a new empty `ArrayString`.
///
/// Capacity is inferred from the type parameter.
@ -61,16 +54,13 @@ impl<A> ArrayString<A>
pub fn new() -> ArrayString<A> {
unsafe {
ArrayString {
xs: MaybeUninitCopy::uninitialized(),
// FIXME: Use Copyable union for xs when we can
xs: mem::zeroed(),
len: Index::from(0),
}
}
}
/// Return the length of the string.
#[inline]
pub fn len(&self) -> usize { self.len.to_usize() }
/// Create a new `ArrayString` from a `str`.
///
/// Capacity is inferred from the type parameter.
@ -101,12 +91,11 @@ impl<A> ArrayString<A>
/// let string = ArrayString::from_byte_string(b"hello world").unwrap();
/// ```
pub fn from_byte_string(b: &A) -> Result<Self, Utf8Error> {
let len = str::from_utf8(b.as_slice())?.len();
debug_assert_eq!(len, A::CAPACITY);
Ok(ArrayString {
xs: MaybeUninitCopy::from(*b),
len: Index::from(A::CAPACITY),
})
let mut arraystr = Self::new();
let s = try!(str::from_utf8(b.as_slice()));
let _result = arraystr.try_push_str(s);
debug_assert!(_result.is_ok());
Ok(arraystr)
}
/// Return the capacity of the `ArrayString`.
@ -117,8 +106,8 @@ impl<A> ArrayString<A>
/// let string = ArrayString::<[_; 3]>::new();
/// assert_eq!(string.capacity(), 3);
/// ```
#[inline(always)]
pub fn capacity(&self) -> usize { A::CAPACITY }
#[inline]
pub fn capacity(&self) -> usize { A::capacity() }
/// Return if the `ArrayString` is completely filled.
///
@ -171,9 +160,7 @@ impl<A> ArrayString<A>
pub fn try_push(&mut self, c: char) -> Result<(), CapacityError<char>> {
let len = self.len();
unsafe {
let ptr = self.xs.ptr_mut().add(len);
let remaining_cap = self.capacity() - len;
match encode_utf8(c, ptr, remaining_cap) {
match encode_utf8(c, &mut self.raw_mut_bytes()[len..]) {
Ok(n) => {
self.set_len(len + n);
Ok(())
@ -226,7 +213,7 @@ impl<A> ArrayString<A>
return Err(CapacityError::new(s));
}
unsafe {
let dst = self.xs.ptr_mut().offset(self.len() as isize);
let dst = self.xs.as_mut_ptr().offset(self.len() as isize);
let src = s.as_ptr();
ptr::copy_nonoverlapping(src, dst, s.len());
let newl = self.len() + s.len();
@ -250,6 +237,7 @@ impl<A> ArrayString<A>
///
/// assert_eq!(s.pop(), None);
/// ```
#[inline]
pub fn pop(&mut self) -> Option<char> {
let ch = match self.chars().rev().next() {
Some(ch) => ch,
@ -278,6 +266,7 @@ impl<A> ArrayString<A>
/// string.truncate(4);
/// assert_eq!(&string[..], "foo");
/// ```
#[inline]
pub fn truncate(&mut self, new_len: usize) {
if new_len <= self.len() {
assert!(self.is_char_boundary(new_len));
@ -308,6 +297,7 @@ impl<A> ArrayString<A>
/// assert_eq!(s.remove(1), 'o');
/// assert_eq!(s.remove(0), 'o');
/// ```
#[inline]
pub fn remove(&mut self, idx: usize) -> char {
let ch = match self[idx..].chars().next() {
Some(ch) => ch,
@ -317,8 +307,8 @@ impl<A> ArrayString<A>
let next = idx + ch.len_utf8();
let len = self.len();
unsafe {
ptr::copy(self.xs.ptr().offset(next as isize),
self.xs.ptr_mut().offset(idx as isize),
ptr::copy(self.xs.as_ptr().offset(next as isize),
self.xs.as_mut_ptr().offset(idx as isize),
len - next);
self.set_len(len - (next - idx));
}
@ -339,6 +329,7 @@ impl<A> ArrayString<A>
///
/// This method uses *debug assertions* to check the validity of `length`
/// and may use other debug assertions.
#[inline]
pub unsafe fn set_len(&mut self, length: usize) {
debug_assert!(length <= self.capacity());
self.len = Index::from(length);
@ -348,97 +339,79 @@ impl<A> ArrayString<A>
pub fn as_str(&self) -> &str {
self
}
/// Return a mutable slice of the whole strings buffer
unsafe fn raw_mut_bytes(&mut self) -> &mut [u8] {
slice::from_raw_parts_mut(self.xs.as_mut_ptr(), self.capacity())
}
}
impl<A> Deref for ArrayString<A>
where A: Array<Item=u8> + Copy
{
impl<A: Array<Item=u8>> Deref for ArrayString<A> {
type Target = str;
#[inline]
fn deref(&self) -> &str {
unsafe {
let sl = slice::from_raw_parts(self.xs.ptr(), self.len.to_usize());
let sl = slice::from_raw_parts(self.xs.as_ptr(), self.len.to_usize());
str::from_utf8_unchecked(sl)
}
}
}
impl<A> DerefMut for ArrayString<A>
where A: Array<Item=u8> + Copy
{
impl<A: Array<Item=u8>> DerefMut for ArrayString<A> {
#[inline]
fn deref_mut(&mut self) -> &mut str {
unsafe {
let sl = slice::from_raw_parts_mut(self.xs.ptr_mut(), self.len.to_usize());
str::from_utf8_unchecked_mut(sl)
let sl = slice::from_raw_parts_mut(self.xs.as_mut_ptr(), self.len.to_usize());
// FIXME: Nothing but transmute to do this right now
mem::transmute(sl)
}
}
}
impl<A> PartialEq for ArrayString<A>
where A: Array<Item=u8> + Copy
{
impl<A: Array<Item=u8>> PartialEq for ArrayString<A> {
fn eq(&self, rhs: &Self) -> bool {
**self == **rhs
}
}
impl<A> PartialEq<str> for ArrayString<A>
where A: Array<Item=u8> + Copy
{
impl<A: Array<Item=u8>> PartialEq<str> for ArrayString<A> {
fn eq(&self, rhs: &str) -> bool {
&**self == rhs
}
}
impl<A> PartialEq<ArrayString<A>> for str
where A: Array<Item=u8> + Copy
{
impl<A: Array<Item=u8>> PartialEq<ArrayString<A>> for str {
fn eq(&self, rhs: &ArrayString<A>) -> bool {
self == &**rhs
}
}
impl<A> Eq for ArrayString<A>
where A: Array<Item=u8> + Copy
{ }
impl<A: Array<Item=u8>> Eq for ArrayString<A> { }
impl<A> Hash for ArrayString<A>
where A: Array<Item=u8> + Copy
{
impl<A: Array<Item=u8>> Hash for ArrayString<A> {
fn hash<H: Hasher>(&self, h: &mut H) {
(**self).hash(h)
}
}
impl<A> Borrow<str> for ArrayString<A>
where A: Array<Item=u8> + Copy
{
impl<A: Array<Item=u8>> Borrow<str> for ArrayString<A> {
fn borrow(&self) -> &str { self }
}
impl<A> AsRef<str> for ArrayString<A>
where A: Array<Item=u8> + Copy
{
impl<A: Array<Item=u8>> AsRef<str> for ArrayString<A> {
fn as_ref(&self) -> &str { self }
}
impl<A> fmt::Debug for ArrayString<A>
where A: Array<Item=u8> + Copy
{
impl<A: Array<Item=u8>> fmt::Debug for ArrayString<A> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) }
}
impl<A> fmt::Display for ArrayString<A>
where A: Array<Item=u8> + Copy
{
impl<A: Array<Item=u8>> fmt::Display for ArrayString<A> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) }
}
/// `Write` appends written data to the end of the string.
impl<A> fmt::Write for ArrayString<A>
where A: Array<Item=u8> + Copy
{
impl<A: Array<Item=u8>> fmt::Write for ArrayString<A> {
fn write_char(&mut self, c: char) -> fmt::Result {
self.try_push(c).map_err(|_| fmt::Error)
}
@ -448,9 +421,7 @@ impl<A> fmt::Write for ArrayString<A>
}
}
impl<A> Clone for ArrayString<A>
where A: Array<Item=u8> + Copy
{
impl<A: Array<Item=u8> + Copy> Clone for ArrayString<A> {
fn clone(&self) -> ArrayString<A> {
*self
}
@ -461,9 +432,7 @@ impl<A> Clone for ArrayString<A>
}
}
impl<A> PartialOrd for ArrayString<A>
where A: Array<Item=u8> + Copy
{
impl<A: Array<Item=u8>> PartialOrd for ArrayString<A> {
fn partial_cmp(&self, rhs: &Self) -> Option<cmp::Ordering> {
(**self).partial_cmp(&**rhs)
}
@ -473,9 +442,7 @@ impl<A> PartialOrd for ArrayString<A>
fn ge(&self, rhs: &Self) -> bool { **self >= **rhs }
}
impl<A> PartialOrd<str> for ArrayString<A>
where A: Array<Item=u8> + Copy
{
impl<A: Array<Item=u8>> PartialOrd<str> for ArrayString<A> {
fn partial_cmp(&self, rhs: &str) -> Option<cmp::Ordering> {
(**self).partial_cmp(rhs)
}
@ -485,9 +452,7 @@ impl<A> PartialOrd<str> for ArrayString<A>
fn ge(&self, rhs: &str) -> bool { &**self >= rhs }
}
impl<A> PartialOrd<ArrayString<A>> for str
where A: Array<Item=u8> + Copy
{
impl<A: Array<Item=u8>> PartialOrd<ArrayString<A>> for str {
fn partial_cmp(&self, rhs: &ArrayString<A>) -> Option<cmp::Ordering> {
self.partial_cmp(&**rhs)
}
@ -497,29 +462,15 @@ impl<A> PartialOrd<ArrayString<A>> for str
fn ge(&self, rhs: &ArrayString<A>) -> bool { self >= &**rhs }
}
impl<A> Ord for ArrayString<A>
where A: Array<Item=u8> + Copy
{
impl<A: Array<Item=u8>> Ord for ArrayString<A> {
fn cmp(&self, rhs: &Self) -> cmp::Ordering {
(**self).cmp(&**rhs)
}
}
impl<A> FromStr for ArrayString<A>
where A: Array<Item=u8> + Copy
{
type Err = CapacityError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::from(s).map_err(CapacityError::simplify)
}
}
#[cfg(feature="serde")]
/// Requires crate feature `"serde"`
impl<A> Serialize for ArrayString<A>
where A: Array<Item=u8> + Copy
{
#[cfg(feature="serde-1")]
/// Requires crate feature `"serde-1"`
impl<A: Array<Item=u8>> Serialize for ArrayString<A> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
@ -527,11 +478,9 @@ impl<A> Serialize for ArrayString<A>
}
}
#[cfg(feature="serde")]
/// Requires crate feature `"serde"`
impl<'de, A> Deserialize<'de> for ArrayString<A>
where A: Array<Item=u8> + Copy
{
#[cfg(feature="serde-1")]
/// Requires crate feature `"serde-1"`
impl<'de, A: Array<Item=u8>> Deserialize<'de> for ArrayString<A> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>
{
@ -540,11 +489,11 @@ impl<'de, A> Deserialize<'de> for ArrayString<A>
struct ArrayStringVisitor<A: Array<Item=u8>>(PhantomData<A>);
impl<'de, A: Copy + Array<Item=u8>> Visitor<'de> for ArrayStringVisitor<A> {
impl<'de, A: Array<Item=u8>> Visitor<'de> for ArrayStringVisitor<A> {
type Value = ArrayString<A>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a string no more than {} bytes long", A::CAPACITY)
write!(formatter, "a string no more than {} bytes long", A::capacity())
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
@ -556,7 +505,7 @@ impl<'de, A> Deserialize<'de> for ArrayString<A>
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where E: de::Error,
{
let s = str::from_utf8(v).map_err(|_| E::invalid_value(de::Unexpected::Bytes(v), &self))?;
let s = try!(str::from_utf8(v).map_err(|_| E::invalid_value(de::Unexpected::Bytes(v), &self)));
ArrayString::from(s).map_err(|_| E::invalid_length(s.len(), &self))
}

View File

@ -10,8 +10,6 @@
//
// Original authors: alexchrichton, bluss
use std::ptr;
// UTF-8 ranges and tags for encoding characters
const TAG_CONT: u8 = 0b1000_0000;
const TAG_TWO_B: u8 = 0b1100_0000;
@ -24,75 +22,33 @@ const MAX_THREE_B: u32 = 0x10000;
/// Placeholder
pub struct EncodeUtf8Error;
#[inline]
unsafe fn write(ptr: *mut u8, index: usize, byte: u8) {
ptr::write(ptr.add(index), byte)
}
/// Encode a char into buf using UTF-8.
///
/// On success, return the byte length of the encoding (1, 2, 3 or 4).<br>
/// On error, return `EncodeUtf8Error` if the buffer was too short for the char.
///
/// Safety: `ptr` must be writable for `len` bytes.
#[inline]
pub unsafe fn encode_utf8(ch: char, ptr: *mut u8, len: usize) -> Result<usize, EncodeUtf8Error>
pub fn encode_utf8(ch: char, buf: &mut [u8]) -> Result<usize, EncodeUtf8Error>
{
let code = ch as u32;
if code < MAX_ONE_B && len >= 1 {
write(ptr, 0, code as u8);
if code < MAX_ONE_B && buf.len() >= 1 {
buf[0] = code as u8;
return Ok(1);
} else if code < MAX_TWO_B && len >= 2 {
write(ptr, 0, (code >> 6 & 0x1F) as u8 | TAG_TWO_B);
write(ptr, 1, (code & 0x3F) as u8 | TAG_CONT);
} else if code < MAX_TWO_B && buf.len() >= 2 {
buf[0] = (code >> 6 & 0x1F) as u8 | TAG_TWO_B;
buf[1] = (code & 0x3F) as u8 | TAG_CONT;
return Ok(2);
} else if code < MAX_THREE_B && len >= 3 {
write(ptr, 0, (code >> 12 & 0x0F) as u8 | TAG_THREE_B);
write(ptr, 1, (code >> 6 & 0x3F) as u8 | TAG_CONT);
write(ptr, 2, (code & 0x3F) as u8 | TAG_CONT);
} else if code < MAX_THREE_B && buf.len() >= 3 {
buf[0] = (code >> 12 & 0x0F) as u8 | TAG_THREE_B;
buf[1] = (code >> 6 & 0x3F) as u8 | TAG_CONT;
buf[2] = (code & 0x3F) as u8 | TAG_CONT;
return Ok(3);
} else if len >= 4 {
write(ptr, 0, (code >> 18 & 0x07) as u8 | TAG_FOUR_B);
write(ptr, 1, (code >> 12 & 0x3F) as u8 | TAG_CONT);
write(ptr, 2, (code >> 6 & 0x3F) as u8 | TAG_CONT);
write(ptr, 3, (code & 0x3F) as u8 | TAG_CONT);
} else if buf.len() >= 4 {
buf[0] = (code >> 18 & 0x07) as u8 | TAG_FOUR_B;
buf[1] = (code >> 12 & 0x3F) as u8 | TAG_CONT;
buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT;
buf[3] = (code & 0x3F) as u8 | TAG_CONT;
return Ok(4);
};
Err(EncodeUtf8Error)
}
#[test]
fn test_encode_utf8() {
// Test that all codepoints are encoded correctly
let mut data = [0u8; 16];
for codepoint in 0..=(std::char::MAX as u32) {
if let Some(ch) = std::char::from_u32(codepoint) {
for elt in &mut data { *elt = 0; }
let ptr = data.as_mut_ptr();
let len = data.len();
unsafe {
let res = encode_utf8(ch, ptr, len).ok().unwrap();
assert_eq!(res, ch.len_utf8());
}
let string = std::str::from_utf8(&data).unwrap();
assert_eq!(string.chars().next(), Some(ch));
}
}
}
#[test]
fn test_encode_utf8_oob() {
// test that we report oob if the buffer is too short
let mut data = [0u8; 16];
let chars = ['a', 'α', '<27>', '𐍈'];
for (len, &ch) in (1..=4).zip(&chars) {
assert_eq!(len, ch.len_utf8(), "Len of ch={}", ch);
let ptr = data.as_mut_ptr();
unsafe {
assert!(matches::matches!(encode_utf8(ch, ptr, len - 1), Err(_)));
assert!(matches::matches!(encode_utf8(ch, ptr, len), Ok(_)));
}
}
}

View File

@ -7,31 +7,38 @@
//! - Optional, enabled by default
//! - Use libstd; disable to use `no_std` instead.
//!
//! - `serde`
//! - `serde-1`
//! - Optional
//! - Enable serialization for ArrayVec and ArrayString using serde 1.x
//! - Enable serialization for ArrayVec and ArrayString using serde 1.0
//! - `array-sizes-33-128`, `array-sizes-129-255`
//! - Optional
//! - Enable more array sizes (see [Array] for more information)
//!
//! ## Rust Version
//!
//! This version of arrayvec requires Rust 1.36 or later.
//! This version of arrayvec requires Rust 1.13 or later.
//!
#![doc(html_root_url="https://docs.rs/arrayvec/0.4/")]
#![cfg_attr(not(feature="std"), no_std)]
#![cfg_attr(has_union_feature, feature(untagged_unions))]
#[cfg(feature="serde")]
#[cfg(feature="serde-1")]
extern crate serde;
#[cfg(not(feature="std"))]
extern crate core as std;
#[cfg(not(has_manually_drop_in_union))]
extern crate nodrop;
use std::cmp;
use std::iter;
use std::mem;
use std::ops::{Bound, Deref, DerefMut, RangeBounds};
use std::ptr;
use std::ops::{
Deref,
DerefMut,
};
use std::slice;
// extra traits
@ -43,21 +50,31 @@ use std::fmt;
use std::io;
#[cfg(has_stable_maybe_uninit)]
#[path="maybe_uninit_stable.rs"]
mod maybe_uninit;
#[cfg(all(not(has_stable_maybe_uninit), has_manually_drop_in_union))]
mod maybe_uninit;
#[cfg(all(not(has_stable_maybe_uninit), not(has_manually_drop_in_union)))]
#[path="maybe_uninit_nodrop.rs"]
mod maybe_uninit;
use crate::maybe_uninit::MaybeUninit;
#[cfg(feature="serde")]
use maybe_uninit::MaybeUninit;
#[cfg(feature="serde-1")]
use serde::{Serialize, Deserialize, Serializer, Deserializer};
mod array;
mod array_string;
mod char;
mod range;
mod errors;
pub use crate::array::Array;
use crate::array::Index;
pub use crate::array_string::ArrayString;
pub use crate::errors::CapacityError;
pub use array::Array;
pub use range::RangeArgument;
use array::Index;
pub use array_string::ArrayString;
pub use errors::CapacityError;
/// A vector with a fixed capacity.
@ -134,8 +151,8 @@ impl<A: Array> ArrayVec<A> {
/// let array = ArrayVec::from([1, 2, 3]);
/// assert_eq!(array.capacity(), 3);
/// ```
#[inline(always)]
pub fn capacity(&self) -> usize { A::CAPACITY }
#[inline]
pub fn capacity(&self) -> usize { A::capacity() }
/// Return if the `ArrayVec` is completely filled.
///
@ -149,19 +166,6 @@ impl<A: Array> ArrayVec<A> {
/// ```
pub fn is_full(&self) -> bool { self.len() == self.capacity() }
/// Returns the capacity left in the `ArrayVec`.
///
/// ```
/// use arrayvec::ArrayVec;
///
/// let mut array = ArrayVec::from([1, 2, 3]);
/// array.pop();
/// assert_eq!(array.remaining_capacity(), 1);
/// ```
pub fn remaining_capacity(&self) -> usize {
self.capacity() - self.len()
}
/// Push `element` to the end of the vector.
///
/// ***Panics*** if the vector is already full.
@ -203,7 +207,7 @@ impl<A: Array> ArrayVec<A> {
/// assert!(overflow.is_err());
/// ```
pub fn try_push(&mut self, element: A::Item) -> Result<(), CapacityError<A::Item>> {
if self.len() < A::CAPACITY {
if self.len() < A::capacity() {
unsafe {
self.push_unchecked(element);
}
@ -235,18 +239,14 @@ impl<A: Array> ArrayVec<A> {
///
/// assert_eq!(&array[..], &[1, 2]);
/// ```
#[inline]
pub unsafe fn push_unchecked(&mut self, element: A::Item) {
let len = self.len();
debug_assert!(len < A::CAPACITY);
ptr::write(self.get_unchecked_ptr(len), element);
debug_assert!(len < A::capacity());
ptr::write(self.get_unchecked_mut(len), element);
self.set_len(len + 1);
}
/// Get pointer to where element at `index` would be
unsafe fn get_unchecked_ptr(&mut self, index: usize) -> *mut A::Item {
self.xs.ptr_mut().add(index)
}
/// Insert `element` at position `index`.
///
/// Shift up all elements after `index`.
@ -304,7 +304,7 @@ impl<A: Array> ArrayVec<A> {
unsafe { // infallible
// The spot to put the new value
{
let p: *mut _ = self.get_unchecked_ptr(index);
let p: *mut _ = self.get_unchecked_mut(index);
// Shift everything over to make space. (Duplicating the
// `index`th element into two consecutive places.)
ptr::copy(p, p.offset(1), len - index);
@ -333,12 +333,12 @@ impl<A: Array> ArrayVec<A> {
/// ```
pub fn pop(&mut self) -> Option<A::Item> {
if self.len() == 0 {
return None;
return None
}
unsafe {
let new_len = self.len() - 1;
self.set_len(new_len);
Some(ptr::read(self.get_unchecked_ptr(new_len)))
Some(ptr::read(self.get_unchecked_mut(new_len)))
}
}
@ -455,19 +455,13 @@ impl<A: Array> ArrayVec<A> {
/// array.truncate(4);
/// assert_eq!(&array[..], &[1, 2, 3]);
/// ```
pub fn truncate(&mut self, new_len: usize) {
unsafe {
if new_len < self.len() {
let tail: *mut [_] = &mut self[new_len..];
self.len = Index::from(new_len);
ptr::drop_in_place(tail);
}
}
pub fn truncate(&mut self, len: usize) {
while self.len() > len { self.pop(); }
}
/// Remove all elements in the vector.
pub fn clear(&mut self) {
self.truncate(0)
while let Some(_) = self.pop() { }
}
/// Retains only the elements specified by the predicate.
@ -509,49 +503,14 @@ impl<A: Array> ArrayVec<A> {
/// This method is `unsafe` because it changes the notion of the
/// number of “valid” elements in the vector. Use with care.
///
/// This method uses *debug assertions* to check that `length` is
/// This method uses *debug assertions* to check that check that `length` is
/// not greater than the capacity.
#[inline]
pub unsafe fn set_len(&mut self, length: usize) {
debug_assert!(length <= self.capacity());
self.len = Index::from(length);
}
/// Copy and appends all elements in a slice to the `ArrayVec`.
///
/// ```
/// use arrayvec::ArrayVec;
///
/// let mut vec: ArrayVec<[usize; 10]> = ArrayVec::new();
/// vec.push(1);
/// vec.try_extend_from_slice(&[2, 3]).unwrap();
/// assert_eq!(&vec[..], &[1, 2, 3]);
/// ```
///
/// # Errors
///
/// This method will return an error if the capacity left (see
/// [`remaining_capacity`]) is smaller then the length of the provided
/// slice.
///
/// [`remaining_capacity`]: #method.remaining_capacity
pub fn try_extend_from_slice(&mut self, other: &[A::Item]) -> Result<(), CapacityError>
where A::Item: Copy,
{
if self.remaining_capacity() < other.len() {
return Err(CapacityError::new(()));
}
let self_len = self.len();
let other_len = other.len();
unsafe {
let dst = self.xs.ptr_mut().offset(self_len as isize);
ptr::copy_nonoverlapping(other.as_ptr(), dst, other_len);
self.set_len(self_len + other_len);
}
Ok(())
}
/// Create a draining iterator that removes the specified range in the vector
/// and yields the removed items from start to end. The element range is
/// removed even if the iterator is not consumed until the end.
@ -570,13 +529,11 @@ impl<A: Array> ArrayVec<A> {
/// assert_eq!(&v[..], &[3]);
/// assert_eq!(&u[..], &[1, 2]);
/// ```
pub fn drain<R>(&mut self, range: R) -> Drain<A>
where R: RangeBounds<usize>
{
pub fn drain<R: RangeArgument>(&mut self, range: R) -> Drain<A> {
// Memory safety
//
// When the Drain is first created, it shortens the length of
// the source vector to make sure no uninitialized or moved-from elements
// the source vector to make sure no uninitalized or moved-from elements
// are accessible at all if the Drain's destructor never gets to run.
//
// Drain will ptr::read out the values to remove.
@ -584,22 +541,8 @@ impl<A: Array> ArrayVec<A> {
// the hole, and the vector length is restored to the new length.
//
let len = self.len();
let start = match range.start_bound() {
Bound::Unbounded => 0,
Bound::Included(&i) => i,
Bound::Excluded(&i) => i.saturating_add(1),
};
let end = match range.end_bound() {
Bound::Excluded(&j) => j,
Bound::Included(&j) => j.saturating_add(1),
Bound::Unbounded => len,
};
self.drain_range(start, end)
}
fn drain_range(&mut self, start: usize, end: usize) -> Drain<A>
{
let len = self.len();
let start = range.start().unwrap_or(0);
let end = range.end().unwrap_or(len);
// bounds check happens here
let range_slice: *const _ = &self[start..end];
@ -619,6 +562,9 @@ impl<A: Array> ArrayVec<A> {
///
/// Return an `Ok` value with the array if length equals capacity,
/// return an `Err` with self otherwise.
///
/// `Note:` This function may incur unproportionally large overhead
/// to move the array out, its performance is not optimal.
pub fn into_inner(self) -> Result<A, Self> {
if self.len() < self.capacity() {
Err(self)
@ -631,8 +577,7 @@ impl<A: Array> ArrayVec<A> {
}
}
/// Dispose of `self` (same as drop)
#[deprecated="Use std::mem::drop instead, if at all needed."]
/// Dispose of `self` without the overwriting that is needed in Drop.
pub fn dispose(mut self) {
self.clear();
mem::forget(self);
@ -647,16 +592,6 @@ impl<A: Array> ArrayVec<A> {
pub fn as_mut_slice(&mut self) -> &mut [A::Item] {
self
}
/// Return a raw pointer to the vector's buffer.
pub fn as_ptr(&self) -> *const A::Item {
self.xs.ptr()
}
/// Return a raw mutable pointer to the vector's buffer.
pub fn as_mut_ptr(&mut self) -> *mut A::Item {
self.xs.ptr_mut()
}
}
impl<A: Array> Deref for ArrayVec<A> {
@ -690,7 +625,7 @@ impl<A: Array> DerefMut for ArrayVec<A> {
/// ```
impl<A: Array> From<A> for ArrayVec<A> {
fn from(array: A) -> Self {
ArrayVec { xs: MaybeUninit::from(array), len: Index::from(A::CAPACITY) }
ArrayVec { xs: MaybeUninit::from(array), len: Index::from(A::capacity()) }
}
}
@ -758,6 +693,7 @@ pub struct IntoIter<A: Array> {
impl<A: Array> Iterator for IntoIter<A> {
type Item = A::Item;
#[inline]
fn next(&mut self) -> Option<A::Item> {
if self.index == self.v.len {
None
@ -765,7 +701,7 @@ impl<A: Array> Iterator for IntoIter<A> {
unsafe {
let index = self.index.to_usize();
self.index = Index::from(index + 1);
Some(ptr::read(self.v.get_unchecked_ptr(index)))
Some(ptr::read(self.v.get_unchecked_mut(index)))
}
}
}
@ -777,6 +713,7 @@ impl<A: Array> Iterator for IntoIter<A> {
}
impl<A: Array> DoubleEndedIterator for IntoIter<A> {
#[inline]
fn next_back(&mut self) -> Option<A::Item> {
if self.index == self.v.len {
None
@ -784,7 +721,7 @@ impl<A: Array> DoubleEndedIterator for IntoIter<A> {
unsafe {
let new_len = self.v.len() - 1;
self.v.set_len(new_len);
Some(ptr::read(self.v.get_unchecked_ptr(new_len)))
Some(ptr::read(self.v.get_unchecked_mut(new_len)))
}
}
}
@ -800,7 +737,7 @@ impl<A: Array> Drop for IntoIter<A> {
unsafe {
self.v.set_len(0);
let elements = slice::from_raw_parts_mut(
self.v.get_unchecked_ptr(index),
self.v.get_unchecked_mut(index),
len - index);
ptr::drop_in_place(elements);
}
@ -853,6 +790,7 @@ impl<'a, A: Array> Iterator for Drain<'a, A>
{
type Item = A::Item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|elt|
unsafe {
@ -861,6 +799,7 @@ impl<'a, A: Array> Iterator for Drain<'a, A>
)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
@ -869,6 +808,7 @@ impl<'a, A: Array> Iterator for Drain<'a, A>
impl<'a, A: Array> DoubleEndedIterator for Drain<'a, A>
where A::Item: 'a,
{
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back().map(|elt|
unsafe {
@ -931,52 +871,27 @@ impl<A: Array> Extend<A::Item> for ArrayVec<A> {
let take = self.capacity() - self.len();
unsafe {
let len = self.len();
let mut ptr = raw_ptr_add(self.as_mut_ptr(), len);
let end_ptr = raw_ptr_add(ptr, take);
let mut ptr = self.as_mut_ptr().offset(len as isize);
// Keep the length in a separate variable, write it back on scope
// exit. To help the compiler with alias analysis and stuff.
// We update the length to handle panic in the iteration of the
// user's iterator, without dropping any elements on the floor.
let mut guard = ScopeExitGuard {
value: &mut self.len,
value: self,
data: len,
f: move |&len, self_len| {
**self_len = Index::from(len);
f: |&len, self_| {
self_.set_len(len)
}
};
let mut iter = iter.into_iter();
loop {
if ptr == end_ptr { break; }
if let Some(elt) = iter.next() {
raw_ptr_write(ptr, elt);
ptr = raw_ptr_add(ptr, 1);
guard.data += 1;
} else {
break;
}
for elt in iter.into_iter().take(take) {
ptr::write(ptr, elt);
ptr = ptr.offset(1);
guard.data += 1;
}
}
}
}
/// Rawptr add but uses arithmetic distance for ZST
unsafe fn raw_ptr_add<T>(ptr: *mut T, offset: usize) -> *mut T {
if mem::size_of::<T>() == 0 {
// Special case for ZST
(ptr as usize).wrapping_add(offset) as _
} else {
ptr.offset(offset as isize)
}
}
unsafe fn raw_ptr_write<T>(ptr: *mut T, value: T) {
if mem::size_of::<T>() == 0 {
/* nothing */
} else {
ptr::write(ptr, value)
}
}
/// Create an `ArrayVec` from an iterator.
///
/// Does not extract more items than there is space for. No error
@ -1067,22 +982,27 @@ impl<A: Array> Default for ArrayVec<A> {
}
impl<A: Array> PartialOrd for ArrayVec<A> where A::Item: PartialOrd {
#[inline]
fn partial_cmp(&self, other: &ArrayVec<A>) -> Option<cmp::Ordering> {
(**self).partial_cmp(other)
}
#[inline]
fn lt(&self, other: &Self) -> bool {
(**self).lt(other)
}
#[inline]
fn le(&self, other: &Self) -> bool {
(**self).le(other)
}
#[inline]
fn ge(&self, other: &Self) -> bool {
(**self).ge(other)
}
#[inline]
fn gt(&self, other: &Self) -> bool {
(**self).gt(other)
}
@ -1100,16 +1020,22 @@ impl<A: Array> Ord for ArrayVec<A> where A::Item: Ord {
/// Requires `features="std"`.
impl<A: Array<Item=u8>> io::Write for ArrayVec<A> {
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
let len = cmp::min(self.remaining_capacity(), data.len());
let _result = self.try_extend_from_slice(&data[..len]);
debug_assert!(_result.is_ok());
Ok(len)
unsafe {
let len = self.len();
let mut tail = slice::from_raw_parts_mut(self.get_unchecked_mut(len),
A::capacity() - len);
let result = tail.write(data);
if let Ok(written) = result {
self.set_len(len + written);
}
result
}
}
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
#[cfg(feature="serde")]
/// Requires crate feature `"serde"`
#[cfg(feature="serde-1")]
/// Requires crate feature `"serde-1"`
impl<T: Serialize, A: Array<Item=T>> Serialize for ArrayVec<A> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
@ -1118,8 +1044,8 @@ impl<T: Serialize, A: Array<Item=T>> Serialize for ArrayVec<A> {
}
}
#[cfg(feature="serde")]
/// Requires crate feature `"serde"`
#[cfg(feature="serde-1")]
/// Requires crate feature `"serde-1"`
impl<'de, T: Deserialize<'de>, A: Array<Item=T>> Deserialize<'de> for ArrayVec<A> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>
@ -1133,7 +1059,7 @@ impl<'de, T: Deserialize<'de>, A: Array<Item=T>> Deserialize<'de> for ArrayVec<A
type Value = ArrayVec<A>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "an array with no more than {} items", A::CAPACITY)
write!(formatter, "an array with no more than {} items", A::capacity())
}
fn visit_seq<SA>(self, mut seq: SA) -> Result<Self::Value, SA::Error>
@ -1141,9 +1067,9 @@ impl<'de, T: Deserialize<'de>, A: Array<Item=T>> Deserialize<'de> for ArrayVec<A
{
let mut values = ArrayVec::<A>::new();
while let Some(value) = seq.next_element()? {
while let Some(value) = try!(seq.next_element()) {
if let Err(_) = values.try_push(value) {
return Err(SA::Error::invalid_length(A::CAPACITY + 1, &self));
return Err(SA::Error::invalid_length(A::capacity() + 1, &self));
}
}

View File

@ -1,28 +1,27 @@
use crate::array::Array;
use std::mem::MaybeUninit as StdMaybeUninit;
use array::Array;
use std::mem::ManuallyDrop;
#[derive(Copy)]
pub struct MaybeUninit<T> {
inner: StdMaybeUninit<T>,
}
impl<T> Clone for MaybeUninit<T>
where T: Copy
{
fn clone(&self) -> Self { *self }
/// A combination of ManuallyDrop and “maybe uninitialized”;
/// this wraps a value that can be wholly or partially uninitialized;
/// it also has no drop regardless of the type of T.
#[repr(C)] // for cast from self ptr to value
pub union MaybeUninit<T> {
empty: (),
value: ManuallyDrop<T>,
}
// Why we don't use std's MaybeUninit on nightly? See the ptr method
impl<T> MaybeUninit<T> {
/// Create a new MaybeUninit with uninitialized interior
pub unsafe fn uninitialized() -> Self {
MaybeUninit { inner: StdMaybeUninit::uninit() }
MaybeUninit { empty: () }
}
/// Create a new MaybeUninit from the value `v`.
pub fn from(v: T) -> Self {
MaybeUninit { inner: StdMaybeUninit::new(v) }
MaybeUninit { value: ManuallyDrop::new(v) }
}
// Raw pointer casts written so that we don't reference or access the
@ -32,13 +31,16 @@ impl<T> MaybeUninit<T> {
pub fn ptr(&self) -> *const T::Item
where T: Array
{
self.inner.as_ptr() as *const T::Item
// std MaybeUninit creates a &self.value reference here which is
// not guaranteed to be sound in our case - we will partially
// initialize the value, not always wholly.
self as *const _ as *const T::Item
}
/// Return a mut raw pointer to the start of the interior array
pub fn ptr_mut(&mut self) -> *mut T::Item
where T: Array
{
self.inner.as_mut_ptr() as *mut T::Item
self as *mut _ as *mut T::Item
}
}

View File

@ -1,4 +1,4 @@
#![cfg(feature = "serde")]
#![cfg(feature = "serde-1")]
extern crate arrayvec;
extern crate serde_test;

View File

@ -27,44 +27,6 @@ fn test_simple() {
assert_eq!(sum_len, 8);
}
#[test]
fn test_capacity_left() {
let mut vec: ArrayVec<[usize; 4]> = ArrayVec::new();
assert_eq!(vec.remaining_capacity(), 4);
vec.push(1);
assert_eq!(vec.remaining_capacity(), 3);
vec.push(2);
assert_eq!(vec.remaining_capacity(), 2);
vec.push(3);
assert_eq!(vec.remaining_capacity(), 1);
vec.push(4);
assert_eq!(vec.remaining_capacity(), 0);
}
#[test]
fn test_extend_from_slice() {
let mut vec: ArrayVec<[usize; 10]> = ArrayVec::new();
vec.try_extend_from_slice(&[1, 2, 3]).unwrap();
assert_eq!(vec.len(), 3);
assert_eq!(&vec[..], &[1, 2, 3]);
assert_eq!(vec.pop(), Some(3));
assert_eq!(&vec[..], &[1, 2]);
}
#[test]
fn test_extend_from_slice_error() {
let mut vec: ArrayVec<[usize; 10]> = ArrayVec::new();
vec.try_extend_from_slice(&[1, 2, 3]).unwrap();
let res = vec.try_extend_from_slice(&[0; 8]);
assert_matches!(res, Err(_));
let mut vec: ArrayVec<[usize; 0]> = ArrayVec::new();
let res = vec.try_extend_from_slice(&[0; 1]);
assert_matches!(res, Err(_));
}
#[test]
fn test_u16_index() {
const N: usize = 4096;
@ -164,80 +126,6 @@ fn test_drop() {
}
}
#[test]
fn test_drop_panics() {
use std::cell::Cell;
use std::panic::catch_unwind;
use std::panic::AssertUnwindSafe;
let flag = &Cell::new(0);
struct Bump<'a>(&'a Cell<i32>);
// Panic in the first drop
impl<'a> Drop for Bump<'a> {
fn drop(&mut self) {
let n = self.0.get();
self.0.set(n + 1);
if n == 0 {
panic!("Panic in Bump's drop");
}
}
}
// check if rust is new enough
flag.set(0);
{
let array = vec![Bump(flag), Bump(flag)];
let res = catch_unwind(AssertUnwindSafe(|| {
drop(array);
}));
assert!(res.is_err());
}
if flag.get() != 2 {
println!("test_drop_panics: skip, this version of Rust doesn't continue in drop_in_place");
return;
}
flag.set(0);
{
let mut array = ArrayVec::<[Bump; 128]>::new();
array.push(Bump(flag));
array.push(Bump(flag));
array.push(Bump(flag));
let res = catch_unwind(AssertUnwindSafe(|| {
drop(array);
}));
assert!(res.is_err());
}
// Check that all the elements drop, even if the first drop panics.
assert_eq!(flag.get(), 3);
flag.set(0);
{
let mut array = ArrayVec::<[Bump; 16]>::new();
array.push(Bump(flag));
array.push(Bump(flag));
array.push(Bump(flag));
array.push(Bump(flag));
array.push(Bump(flag));
let i = 2;
let tail_len = array.len() - i;
let res = catch_unwind(AssertUnwindSafe(|| {
array.truncate(i);
}));
assert!(res.is_err());
// Check that all the tail elements drop, even if the first drop panics.
assert_eq!(flag.get(), tail_len as i32);
}
}
#[test]
fn test_extend() {
let mut range = 0..10;
@ -258,8 +146,8 @@ fn test_extend() {
#[test]
fn test_is_send_sync() {
let data = ArrayVec::<[Vec<i32>; 5]>::new();
&data as &dyn Send;
&data as &dyn Sync;
&data as &Send;
&data as &Sync;
}
#[test]
@ -270,11 +158,6 @@ fn test_compact_size() {
println!("{}", mem::size_of::<ByteArray>());
assert!(mem::size_of::<ByteArray>() <= 8);
// 1 enum tag + 1 drop flag
type EmptyArray = ArrayVec<[u8; 0]>;
println!("{}", mem::size_of::<EmptyArray>());
assert!(mem::size_of::<EmptyArray>() <= 2);
// 12 element size + 1 enum tag + 3 padding + 1 len + 1 drop flag + 2 padding
type QuadArray = ArrayVec<[u32; 3]>;
println!("{}", mem::size_of::<QuadArray>());
@ -306,29 +189,6 @@ fn test_drain() {
assert_eq!(&v[..], &[]);
}
#[test]
fn test_drain_range_inclusive() {
let mut v = ArrayVec::from([0; 8]);
v.drain(0..=7);
assert_eq!(&v[..], &[]);
v.extend(0..);
v.drain(1..=4);
assert_eq!(&v[..], &[0, 5, 6, 7]);
let u: ArrayVec<[_; 3]> = v.drain(1..=2).rev().collect();
assert_eq!(&u[..], &[6, 5]);
assert_eq!(&v[..], &[0, 7]);
v.drain(..);
assert_eq!(&v[..], &[]);
}
#[test]
#[should_panic]
fn test_drain_range_inclusive_oob() {
let mut v = ArrayVec::from([0; 0]);
v.drain(0..=0);
}
#[test]
fn test_retain() {
let mut v = ArrayVec::from([0; 8]);
@ -434,7 +294,6 @@ fn test_into_inner_3_() {
assert_eq!(v.into_inner().unwrap(), [1, 2, 3, 4]);
}
#[cfg(feature="std")]
#[test]
fn test_write() {
use std::io::Write;
@ -469,7 +328,6 @@ fn array_clone_from() {
assert_eq!(&t, &reference[..]);
}
#[cfg(feature="std")]
#[test]
fn test_string() {
use std::error::Error;
@ -495,9 +353,9 @@ fn test_string() {
assert_eq!(tmut, "ab");
// Test Error trait / try
let t = || -> Result<(), Box<dyn Error>> {
let t = || -> Result<(), Box<Error>> {
let mut t = ArrayString::<[_; 2]>::new();
t.try_push_str(text)?;
try!(t.try_push_str(text));
Ok(())
}();
assert!(t.is_err());
@ -512,14 +370,6 @@ fn test_string_from() {
assert_eq!(u.len(), text.len());
}
#[test]
fn test_string_parse_from_str() {
let text = "hello world";
let u: ArrayString<[_; 11]> = text.parse().unwrap();
assert_eq!(&u, text);
assert_eq!(u.len(), text.len());
}
#[test]
fn test_string_from_bytes() {
let text = "hello world";
@ -658,22 +508,10 @@ fn test_sizes_129_255() {
ArrayVec::from([0u8; 255]);
}
#[test]
fn test_extend_zst() {
let mut range = 0..10;
#[derive(Copy, Clone, PartialEq, Debug)]
struct Z; // Zero sized type
let mut array: ArrayVec<[_; 5]> = range.by_ref().map(|_| Z).collect();
assert_eq!(&array[..], &[Z; 5]);
assert_eq!(range.next(), Some(5));
array.extend(range.by_ref().map(|_| Z));
assert_eq!(range.next(), Some(6));
let mut array: ArrayVec<[_; 10]> = (0..3).map(|_| Z).collect();
assert_eq!(&array[..], &[Z; 3]);
array.extend((3..5).map(|_| Z));
assert_eq!(&array[..], &[Z; 5]);
assert_eq!(array.len(), 5);
fn test_newish_stable_uses_maybe_uninit() {
if option_env!("ARRAYVECTEST_ENSURE_MAYBEUNINIT").map(|s| !s.is_empty()).unwrap_or(false) {
assert!(cfg!(has_stable_maybe_uninit));
}
}

View File

@ -1 +0,0 @@
{"files":{"Cargo.toml":"c1c67981635d76cb25b8e2d93bbf5ed521f2a436c8a3eb5c11673a1d6373cbbb","output":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","src/allocator.rs":"8defd2b41207b2049c2fdae62564148c969d92d5a724487bbc189e748b27fd5c","src/device.rs":"7349761540893b33a41eff1e922f846db494b8b9e6bf0dcfd48ce0bec00e5870","src/entry.rs":"2491a6f350f1c04bcb39e4f585d8549e2cf4bbd3e8a792145a6b0218f52b6e9b","src/extensions/experimental/amd.rs":"70652e2216811f0fcf2f0e748d0cf5c52c6eabfd613e3bd6da28cb1100cfd620","src/extensions/experimental/mod.rs":"41a5366e1c8bd0e1fa47e9cf6fddc8111ed0a6946813be4eefca81da969d1ee9","src/extensions/ext/debug_marker.rs":"2221980d611c8e9bdc9ca5186bf363ccbda22e6b5ea52572f3b7ed4ec5a752a3","src/extensions/ext/debug_report.rs":"affff85cefb68313a6d91489fba4c58e4adffca00d571e24a6818e72f94f4983","src/extensions/ext/debug_utils.rs":"8592be4c7dfbf13d4d224d79d16e4fc6ab746d1fa761178a781dc03caa63a53a","src/extensions/ext/mod.rs":"ccd7b9471c4bb356fc2fa309d58a847f9aff393b77fc08752123e19c801cbc65","src/extensions/khr/android_surface.rs":"5f9ff04add0661637258b32eea95c1eefcf86ab8686088e28a7369ab77df9456","src/extensions/khr/display_swapchain.rs":"cfd551cc2bb29d8e998938880de49d0142c1af6561360282820f6e32c1f9bc42","src/extensions/khr/mod.rs":"12a32c91a4b13972660dc997b59b38383b8059e6ff457d594731e828db6f2e1d","src/extensions/khr/surface.rs":"2e5a08e6a3f8903f40e643476eb48b0626054de606dfeed1e1e6ee3b8098c743","src/extensions/khr/swapchain.rs":"4dd73298a5d3e55c83d649a81aaf42384625ef53b7f13b24ad326a08627cf794","src/extensions/khr/wayland_surface.rs":"63233a95aa5f4c693f7322b6cf70789a9ac304a90bc3157a0855ce71872cf6e9","src/extensions/khr/win32_surface.rs":"4e27aaf236eba179eb0d2ad3a29a54ace21d7c4b5210ac36bc328e3d57cc8616","src/extensions/khr/xcb_surface.rs":"328e57312e261f55f13ed78a7c3bd8dcaab7d94d481910a6483b962d0f4da40d","src/extensions/khr/xlib_surface.rs":"44ee06032f0d3fe7f330c6542cbe81636523123355f8c10844abf7893bcb2503","src/extensions/mod.rs":"4a394c468a0fc824671b36c1390f6c34173d073ed0918a528a84f48667756d65","src/extensions/mvk/ios_surface.rs":"3c58810506841142a781df7ab76fe95a2eac5d7dc95ae6345ae93220d2647b7b","src/extensions/mvk/macos_surface.rs":"fcf3a34c164f0251293a50222f944e74fff4eeb797ad8521678031e69a26956c","src/extensions/mvk/mod.rs":"d03ac1a0144d1aca9ed1d0ce0c14b099f1fedb03b8108028b780a34f64de604c","src/extensions/nv/mesh_shader.rs":"c0450955eb36344b7e49acc58a021d04926dd918685b9fc6a655cd29a39afc72","src/extensions/nv/mod.rs":"175512de8528c3a90000cf9509c683761e9536dcb448877b7c7772b695aad258","src/extensions/nv/ray_tracing.rs":"a241936debf78f219de647b8392dc18c0542a82393eace4d25aaa49afef36b82","src/instance.rs":"fab133b311506eb38d8a3faa7f3e60a9e13b84760e08ad830e616262a6b46228","src/lib.rs":"801481c0cd8415f7f90ba1022128b440cc951cbd572a82f30cc1a142d34af405","src/prelude.rs":"ed6ee8e74131c232af2e3a780abe13f0c65acba1e6de61e3d1eec7f7aec7467a","src/util.rs":"bb50e11bc75058fb474bda5e34aa8978cb585ce3532ae2921c93692a13a25187","src/version.rs":"6f2d52ac2edd6f54c899763825954ac8b4c944aa9168d00885cf3955b5e4e454","src/vk.rs":"f946223870190a0060cf7b3c5baacae9ef1e4bcd12bc2d860344dc5c1567cf3d","tests/constant_size_arrays.rs":"6577f5c8d9810f9aea1d47862243e4d41a297d43e744be04fdb34d08021bac48","tests/display.rs":"13f341053efcfc104e6dae48c19e6092ffc2acf6ff3cbc4ed37dd1a03875cb17"},"package":"003d1fb2eb12eb06d4a03dbe02eea67a9fac910fa97932ab9e3a75b96a1ea5e5"}

View File

@ -1,29 +0,0 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies
#
# If you believe there's an error in this file please file an
# issue against the rust-lang/cargo repository. If you're
# editing this file be aware that the upstream Cargo.toml
# will likely look very different (and much more reasonable)
[package]
name = "ash"
version = "0.29.0"
authors = ["maik klein <maikklein@googlemail.com>"]
description = "Vulkan bindings for Rust"
documentation = "https://docs.rs/ash"
readme = "../README.md"
keywords = ["vulkan", "graphic"]
license = "MIT"
repository = "https://github.com/MaikKlein/ash"
[package.metadata.release]
no-dev-version = true
[dependencies.shared_library]
version = "0.1.9"
[features]
default = []

View File

Some files were not shown because too many files have changed in this diff Show More