зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1575008 - WebGPU implementation basis r=baku,bzbarsky
This change vendors `wgpu` library in-tree and hooks up the initialization bits. It implements adapter and device initialization and adds a simple test. Complementary ecosystem tracker - https://github.com/gfx-rs/wgpu/issues/374 Current status: - [x] General - [x] figure out the IPC story - [ ] move wgpu crates into a dedicated folder (postponed as https://bugzilla.mozilla.org/show_bug.cgi?id=1594182) - [x] neko rebasing disaster - [x] Linux - [x] avoid depending on spirv_cross - [x] macOS - [x] due to cross-compiling shaders - [x] need the dependency update - [x] stop using gcc - [x] unexpected SSL header collision - https://phabricator.services.mozilla.com/D51148 - [x] undefined Metal symbols - [x] missing webrtc headers for IPDL magic - https://phabricator.services.mozilla.com/D51558 - [x] spirv-cross linking failure in ASAN - https://phabricator.services.mozilla.com/D52688 - [x] Windows - [x] due to "ipc-channel" not supporting Windows yet - [x] due to some exceptional stuff - [x] undefined symbol: `D3D12CreateDevice` - [x] d3d12.dll is not found, dxgi1_4 doesn't present - [x] d3d11.dll and dxgi.dll need to be explicitly loaded on win32 mingw - [x] libbacktrace fails to link on win32 mingw - [x] cc mislinking C++ standard library - [x] Android - [x] spirv-cross fails to build due to exceptions Update-1: We decided to go with IPDL mechanism instead of Rust based ipc-channel (or any alternatives), which unblocks Windows build. Update-2: It appears that WebGPUThreading isn't needed any more as the child thread (and its event loop) is now managed by IPDL infrastructure. This PR removes it 🎉 . Update-3: InstanceProvider is also removed. Update-4: All set, the try is green, waiting for dependent changes to go in. Differential Revision: https://phabricator.services.mozilla.com/D49458 --HG-- rename : dom/webgpu/Adapter.cpp => dom/webgpu/ipc/WebGPUTypes.h rename : third_party/rust/blake2b_simd/Cargo.toml => third_party/rust/ash/Cargo.toml rename : third_party/rust/uluru/Cargo.toml => third_party/rust/atom/Cargo.toml rename : third_party/rust/core-graphics/Cargo.toml => third_party/rust/cocoa/Cargo.toml rename : third_party/rust/crossbeam-deque/LICENSE-MIT => third_party/rust/cocoa/LICENSE-MIT rename : third_party/rust/core-graphics/src/lib.rs => third_party/rust/cocoa/src/lib.rs rename : third_party/rust/uluru/Cargo.toml => third_party/rust/colorful/Cargo.toml rename : third_party/rust/uluru/Cargo.toml => third_party/rust/copyless/Cargo.toml rename : third_party/rust/crossbeam-utils/.cargo-checksum.json => third_party/rust/crossbeam-utils-0.6.5/.cargo-checksum.json rename : third_party/rust/crossbeam-utils/CHANGELOG.md => third_party/rust/crossbeam-utils-0.6.5/CHANGELOG.md rename : third_party/rust/crossbeam-utils/Cargo.toml => third_party/rust/crossbeam-utils-0.6.5/Cargo.toml rename : third_party/rust/crossbeam-deque/LICENSE-MIT => third_party/rust/crossbeam-utils-0.6.5/LICENSE-MIT rename : third_party/rust/crossbeam-utils/README.md => third_party/rust/crossbeam-utils-0.6.5/README.md rename : third_party/rust/crossbeam-utils/benches/atomic_cell.rs => third_party/rust/crossbeam-utils-0.6.5/benches/atomic_cell.rs rename : third_party/rust/crossbeam-utils/src/atomic/atomic_cell.rs => third_party/rust/crossbeam-utils-0.6.5/src/atomic/atomic_cell.rs rename : third_party/rust/crossbeam-utils/src/atomic/mod.rs => third_party/rust/crossbeam-utils-0.6.5/src/atomic/mod.rs rename : third_party/rust/crossbeam-utils/src/backoff.rs => third_party/rust/crossbeam-utils-0.6.5/src/backoff.rs rename : third_party/rust/crossbeam-utils/src/cache_padded.rs => third_party/rust/crossbeam-utils-0.6.5/src/cache_padded.rs rename : third_party/rust/crossbeam-utils/src/lib.rs => third_party/rust/crossbeam-utils-0.6.5/src/lib.rs rename : third_party/rust/crossbeam-utils/src/thread.rs => third_party/rust/crossbeam-utils-0.6.5/src/thread.rs rename : third_party/rust/crossbeam-utils/tests/atomic_cell.rs => third_party/rust/crossbeam-utils-0.6.5/tests/atomic_cell.rs rename : third_party/rust/crossbeam-utils/tests/parker.rs => third_party/rust/crossbeam-utils-0.6.5/tests/parker.rs rename : third_party/rust/crossbeam-utils/tests/sharded_lock.rs => third_party/rust/crossbeam-utils-0.6.5/tests/sharded_lock.rs rename : third_party/rust/crossbeam-utils/tests/thread.rs => third_party/rust/crossbeam-utils-0.6.5/tests/thread.rs rename : third_party/rust/blake2b_simd/Cargo.toml => third_party/rust/gfx-auxil/Cargo.toml rename : third_party/rust/blake2b_simd/Cargo.toml => third_party/rust/gfx-backend-empty/Cargo.toml rename : third_party/rust/blake2b_simd/Cargo.toml => third_party/rust/hibitset/Cargo.toml rename : third_party/rust/crossbeam-deque/LICENSE-MIT => third_party/rust/hibitset/LICENSE-MIT rename : third_party/rust/crossbeam-deque/LICENSE-MIT => third_party/rust/metal/LICENSE-MIT rename : third_party/rust/uluru/Cargo.toml => third_party/rust/range-alloc/Cargo.toml rename : third_party/rust/blake2b_simd/Cargo.toml => third_party/rust/raw-window-handle/Cargo.toml rename : third_party/rust/blake2b_simd/Cargo.toml => third_party/rust/relevant/Cargo.toml rename : third_party/rust/crossbeam-deque/LICENSE-MIT => third_party/rust/relevant/LICENSE-MIT rename : third_party/rust/blake2b_simd/Cargo.toml => third_party/rust/rendy-descriptor/Cargo.toml rename : third_party/rust/uluru/Cargo.toml => third_party/rust/shared_library/Cargo.toml rename : third_party/rust/crossbeam-deque/LICENSE-MIT => third_party/rust/shared_library/LICENSE-MIT rename : third_party/rust/blake2b_simd/Cargo.toml => third_party/rust/storage-map/Cargo.toml rename : third_party/rust/core-graphics/Cargo.toml => third_party/rust/x11/Cargo.toml extra : moz-landing-system : lando
This commit is contained in:
Родитель
bd713fe4ee
Коммит
1c5b01ed15
|
@ -17,6 +17,16 @@ git = "https://github.com/mozilla/neqo"
|
|||
replace-with = "vendored-sources"
|
||||
rev = "a17c1e83"
|
||||
|
||||
[source."https://github.com/kvark/spirv_cross"]
|
||||
branch = "wgpu"
|
||||
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"
|
||||
|
|
|
@ -38,6 +38,7 @@ 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
|
||||
|
|
|
@ -46,12 +46,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.4.11"
|
||||
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 = [
|
||||
"nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"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"
|
||||
|
@ -92,7 +102,7 @@ dependencies = [
|
|||
"audio_thread_priority 0.20.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cubeb 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -165,14 +175,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.9"
|
||||
version = "0.3.38"
|
||||
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.59 (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]]
|
||||
|
@ -180,7 +189,7 @@ name = "backtrace-sys"
|
|||
version = "0.1.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -335,14 +344,19 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "blake2b_simd"
|
||||
version = "0.5.8"
|
||||
version = "0.5.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"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"
|
||||
|
@ -411,7 +425,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.34"
|
||||
version = "1.0.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
@ -496,9 +510,28 @@ name = "cmake"
|
|||
version = "0.1.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.47 (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.59 (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"
|
||||
|
@ -522,6 +555,11 @@ 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"
|
||||
|
@ -538,7 +576,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "core-graphics"
|
||||
version = "0.17.1"
|
||||
version = "0.17.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -553,7 +591,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.1 (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.59 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
@ -673,21 +711,21 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.7.1"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.7.2"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -710,6 +748,16 @@ dependencies = [
|
|||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cssparser"
|
||||
version = "0.25.9"
|
||||
|
@ -816,6 +864,16 @@ 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"
|
||||
|
@ -1034,7 +1092,7 @@ name = "failure"
|
|||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"backtrace 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -1216,6 +1274,116 @@ dependencies = [
|
|||
"winapi 0.3.7 (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)",
|
||||
]
|
||||
|
||||
[[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)",
|
||||
"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)",
|
||||
"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)",
|
||||
"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"
|
||||
|
@ -1241,7 +1409,7 @@ dependencies = [
|
|||
name = "gkrust-shared"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"audio_thread_priority 0.20.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"audioipc-client 0.4.0",
|
||||
"audioipc-server 0.2.3",
|
||||
|
@ -1277,6 +1445,7 @@ 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",
|
||||
]
|
||||
|
@ -1390,6 +1559,14 @@ 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"
|
||||
|
@ -1612,7 +1789,7 @@ name = "libloading"
|
|||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -1638,7 +1815,7 @@ name = "libz-sys"
|
|||
version = "1.0.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -1674,7 +1851,7 @@ version = "0.9.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bindgen 0.51.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
@ -1716,7 +1893,7 @@ name = "lucet-runtime"
|
|||
version = "0.1.1"
|
||||
source = "git+https://github.com/PLSysSec/lucet_sandbox_compiler#5c22392b5b1aaa60e915c75e92b57391e1e61e6d"
|
||||
dependencies = [
|
||||
"cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lucet-module 0.1.1 (git+https://github.com/PLSysSec/lucet_sandbox_compiler)",
|
||||
"lucet-runtime-internals 0.1.1 (git+https://github.com/PLSysSec/lucet_sandbox_compiler)",
|
||||
|
@ -1732,7 +1909,7 @@ dependencies = [
|
|||
"bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"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)",
|
||||
"cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -1774,6 +1951,14 @@ dependencies = [
|
|||
"libc 0.2.59 (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.59 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "malloc_size_of"
|
||||
version = "0.0.1"
|
||||
|
@ -1847,6 +2032,20 @@ 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"
|
||||
|
@ -1869,7 +2068,7 @@ name = "miniz-sys"
|
|||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -2192,7 +2391,7 @@ version = "0.13.1"
|
|||
source = "git+https://github.com/shravanrn/nix/?branch=r0.13.1#4af6c367603869a30fddb5ffb0aba2b9477ba92e"
|
||||
dependencies = [
|
||||
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.47 (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.59 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -2303,6 +2502,23 @@ dependencies = [
|
|||
"libc 0.2.59 (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.47 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.14.0"
|
||||
|
@ -2701,12 +2917,25 @@ 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.59 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
@ -2716,7 +2945,7 @@ name = "rayon-core"
|
|||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -2772,6 +3001,15 @@ 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"
|
||||
|
@ -2780,6 +3018,31 @@ 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"
|
||||
|
@ -2870,7 +3133,7 @@ version = "0.5.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"blake2b_simd 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -2889,7 +3152,7 @@ dependencies = [
|
|||
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"murmurhash3 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3112,6 +3375,15 @@ 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.59 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shift_or_euc"
|
||||
version = "0.1.0"
|
||||
|
@ -3183,6 +3455,14 @@ 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#636677bad724797789239c16e6d332e9b4d97b86"
|
||||
dependencies = [
|
||||
"cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.0.0"
|
||||
|
@ -3203,6 +3483,14 @@ 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"
|
||||
|
@ -3228,7 +3516,7 @@ name = "style"
|
|||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bindgen 0.51.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -3272,7 +3560,7 @@ dependencies = [
|
|||
"to_shmem 0.0.1",
|
||||
"to_shmem_derive 0.0.1",
|
||||
"toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"uluru 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"uluru 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -3613,7 +3901,7 @@ name = "tokio-threadpool"
|
|||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -3686,10 +3974,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "uluru"
|
||||
version = "0.3.0"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3864,7 +4152,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.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core-graphics 0.17.3 (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)",
|
||||
|
@ -3902,7 +4190,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.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core-graphics 0.17.3 (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)",
|
||||
|
@ -3921,7 +4209,7 @@ dependencies = [
|
|||
"app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bincode 1.2.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.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"core-graphics 0.17.3 (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)",
|
||||
|
@ -3961,6 +4249,40 @@ 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"
|
||||
|
@ -4015,6 +4337,14 @@ 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"
|
||||
|
@ -4049,6 +4379,15 @@ 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.59 (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 = "xfailure"
|
||||
version = "0.1.0"
|
||||
|
@ -4136,14 +4475,16 @@ dependencies = [
|
|||
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
"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.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a"
|
||||
"checksum backtrace 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)" = "690a62be8920ccf773ee00ef0968649b0e724cda8bd5b12286302b4ae955fdf5"
|
||||
"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"
|
||||
|
@ -4154,7 +4495,8 @@ dependencies = [
|
|||
"checksum bit_reverse 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5e97e02db5a2899c0377f3d6031d5da8296ca2b47abef6ed699de51b9e40a28c"
|
||||
"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 blake2b_simd 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b83b7baab1e671718d78204225800d6b170e648188ac7dc992e9d6bddf87d0c0"
|
||||
"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"
|
||||
|
@ -4162,7 +4504,7 @@ dependencies = [
|
|||
"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb"
|
||||
"checksum bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e178b8e0e239e844b083d5a0d4a156b2654e67f9f80144d48398fcd736a24fb8"
|
||||
"checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427"
|
||||
"checksum cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)" = "30f813bf45048a18eda9190fd3c6b78644146056740c43172a5a3699118588fd"
|
||||
"checksum cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)" = "aa87058dce70a3ff5621797f1506cb837edd02ac4c0ae642b4542dce802908b8"
|
||||
"checksum cexpr 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8fc0086be9ca82f7fc89fc873435531cb898b86e850005850de1f820e2db6e9b"
|
||||
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
|
||||
"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878"
|
||||
|
@ -4170,12 +4512,15 @@ 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.1 (registry+https://github.com/rust-lang/crates.io-index)" = "62ceafe1622ffc9a332199096841d0ff9912ec8cf8f9cde01e254a7d5217cd10"
|
||||
"checksum core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)" = "56790968ab1c8a1202a102e6de05fc6e1ec87da99e4e93e9a7d13efbfc1e95a9"
|
||||
"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"
|
||||
|
@ -4189,10 +4534,11 @@ dependencies = [
|
|||
"checksum cranelift-frontend 0.46.1 (git+https://github.com/CraneStation/Cranelift?rev=da179e4fd83d49b7ad6c9f286b1ea04d4f64907e)" = "<none>"
|
||||
"checksum cranelift-wasm 0.46.1 (git+https://github.com/CraneStation/Cranelift?rev=da179e4fd83d49b7ad6c9f286b1ea04d4f64907e)" = "<none>"
|
||||
"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
|
||||
"checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71"
|
||||
"checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9"
|
||||
"checksum crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3aa945d63861bfe624b55d153a39684da1e8c0bc8fba932f7ee3a3c16cea3ca"
|
||||
"checksum crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5064ebdbf05ce3cb95e45c8b086f72263f4166b29b97f6baff7ef7fe047b55ac"
|
||||
"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b"
|
||||
"checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c"
|
||||
"checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4"
|
||||
"checksum cssparser 0.25.9 (registry+https://github.com/rust-lang/crates.io-index)" = "fbe18ca4efb9ba3716c6da66cc3d7e673bf59fa576353011f48c4cfddbdd740e"
|
||||
"checksum cssparser-macros 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "5bb1c84e87c717666564ec056105052331431803d606bd45529b28547b611eef"
|
||||
"checksum cstr 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b6557bdb1dc9647eae1cf7f5601b14cd45fc3c7ccf2df618387416fe542da6ea"
|
||||
|
@ -4201,6 +4547,7 @@ 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"
|
||||
|
@ -4238,6 +4585,13 @@ dependencies = [
|
|||
"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 getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8d1dffef07351aafe6ef177e4dd2b8dcf503e6bc765dea3b0de9ed149a3db1ec"
|
||||
"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"
|
||||
|
@ -4247,6 +4601,7 @@ 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"
|
||||
|
@ -4282,11 +4637,13 @@ dependencies = [
|
|||
"checksum lucet-wasi 0.1.1 (git+https://github.com/PLSysSec/lucet_sandbox_compiler)" = "<none>"
|
||||
"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-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9e3ae51cea1576ceba0dde3d484d30e6e5b86dee0b2d412fe3a16a15c98202"
|
||||
|
@ -4319,6 +4676,8 @@ 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"
|
||||
|
@ -4359,6 +4718,8 @@ 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"
|
||||
|
@ -4367,7 +4728,10 @@ 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 rkv 0.11.0 (git+https://github.com/mozilla/rkv?branch=safe-mode)" = "<none>"
|
||||
|
@ -4401,6 +4765,7 @@ 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"
|
||||
|
@ -4410,7 +4775,9 @@ 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)" = "<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"
|
||||
|
@ -4446,7 +4813,7 @@ dependencies = [
|
|||
"checksum toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7540f4ffc193e0d3c94121edb19b055670d369f77d5804db11ae053a45b6e7e"
|
||||
"checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382"
|
||||
"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
|
||||
"checksum uluru 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d2606e9192f308ddc4f0b3c5d1bf3400e28a70fff956e9d9f46d23b094746d9f"
|
||||
"checksum uluru 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d7b39d0c32eba57d52d334e4bdd150df6e755264eefaa1ae2e7cd125f35e1ca"
|
||||
"checksum unicase 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a84e5511b2a947f3ae965dcb29b13b7b1691b6e7332cf5dbc1744138d5acb7f6"
|
||||
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
|
||||
"checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f"
|
||||
|
@ -4477,8 +4844,10 @@ 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 xfailure 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da90eac47bf1d7871b75004b9b631d107df15f37669383b23f0b5297bc7516b6"
|
||||
"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"
|
||||
|
|
|
@ -63,6 +63,8 @@ libudev-sys = { path = "dom/webauthn/libudev-sys" }
|
|||
packed_simd = { git = "https://github.com/hsivonen/packed_simd", branch = "rust_1_32" }
|
||||
rlbox_lucet_sandbox = { git = "https://github.com/PLSysSec/rlbox_lucet_sandbox/", rev="997c648eb0eaeaaa7a00a9eee20431f750b4e190" }
|
||||
nix = { git = "https://github.com/shravanrn/nix/", branch = "r0.13.1", rev="4af6c367603869a30fddb5ffb0aba2b9477ba92e" }
|
||||
spirv_cross = { git = "https://github.com/kvark/spirv_cross", branch = "wgpu" }
|
||||
objc_exception = { git = "https://github.com/kvark/rust-objc-exception", branch = "cc" }
|
||||
|
||||
[patch.crates-io.cranelift-codegen]
|
||||
git = "https://github.com/CraneStation/Cranelift"
|
||||
|
|
|
@ -840,7 +840,6 @@ class PromiseDocumentFlushedResolver final {
|
|||
nsGlobalWindowInner::nsGlobalWindowInner(nsGlobalWindowOuter* aOuterWindow,
|
||||
WindowGlobalChild* aActor)
|
||||
: nsPIDOMWindowInner(aOuterWindow, aActor),
|
||||
mozilla::webgpu::InstanceProvider(this),
|
||||
mWasOffline(false),
|
||||
mHasHadSlowScript(false),
|
||||
mIsChrome(false),
|
||||
|
@ -1397,8 +1396,6 @@ 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)
|
||||
|
@ -1513,8 +1510,6 @@ 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
|
||||
|
||||
|
|
|
@ -47,7 +47,6 @@
|
|||
#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"
|
||||
|
@ -181,8 +180,7 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
|
|||
public nsSupportsWeakReference,
|
||||
public nsIInterfaceRequestor,
|
||||
public PRCListStr,
|
||||
public nsAPostRefreshObserver,
|
||||
public mozilla::webgpu::InstanceProvider {
|
||||
public nsAPostRefreshObserver {
|
||||
public:
|
||||
typedef mozilla::dom::BrowsingContext RemoteProxy;
|
||||
|
||||
|
|
|
@ -6,15 +6,41 @@
|
|||
#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 {
|
||||
|
||||
GPU_IMPL_CYCLE_COLLECTION(Adapter, mParent)
|
||||
GPU_IMPL_CYCLE_COLLECTION(Adapter, mBridge, mParent)
|
||||
GPU_IMPL_JS_WRAP(Adapter)
|
||||
|
||||
Adapter::Adapter(Instance* const aParent, RawId aId)
|
||||
: ChildOf(aParent), mBridge(aParent->GetBridge()), mId(aId) {}
|
||||
Adapter::~Adapter() = default;
|
||||
|
||||
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->MaybeRejectWithDOMException(NS_ERROR_DOM_NOT_SUPPORTED_ERR,
|
||||
"Unable to instanciate a Device");
|
||||
}
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
} // namespace webgpu
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#define GPU_Adapter_H_
|
||||
|
||||
#include "mozilla/AlreadyAddRefed.h"
|
||||
#include "mozilla/webgpu/WebGPUTypes.h"
|
||||
#include "nsString.h"
|
||||
#include "ObjectModel.h"
|
||||
|
||||
|
@ -21,20 +22,28 @@ 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(Instance* const aParent, RawId aId);
|
||||
void GetName(nsString& out) const { out = mName; }
|
||||
WebGPUChild* GetBridge() const;
|
||||
|
||||
already_AddRefed<dom::Promise> RequestDevice(
|
||||
const dom::GPUDeviceDescriptor& aDesc, ErrorResult& aRv);
|
||||
};
|
||||
|
||||
} // namespace webgpu
|
||||
|
|
|
@ -7,17 +7,27 @@
|
|||
#include "Device.h"
|
||||
|
||||
#include "Adapter.h"
|
||||
#include "ipc/WebGPUChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace webgpu {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(Device, DOMEventTargetHelper)
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(Device, DOMEventTargetHelper, mBridge)
|
||||
NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(Device, DOMEventTargetHelper)
|
||||
GPU_IMPL_JS_WRAP(Device)
|
||||
|
||||
Device::Device(nsIGlobalObject* aGlobal) : DOMEventTargetHelper(aGlobal) {}
|
||||
Device::Device(Adapter* const aParent, RawId aId)
|
||||
: DOMEventTargetHelper(aParent->GetParentObject()),
|
||||
mBridge(aParent->GetBridge()),
|
||||
mId(aId) {
|
||||
Unused << mId; // TODO: remove
|
||||
}
|
||||
|
||||
Device::~Device() = default;
|
||||
Device::~Device() {
|
||||
if (mBridge->IsOpen()) {
|
||||
mBridge->SendDeviceDestroy(mId);
|
||||
}
|
||||
}
|
||||
|
||||
void Device::GetLabel(nsAString& aValue) const { aValue = mLabel; }
|
||||
void Device::SetLabel(const nsAString& aLabel) { mLabel = aLabel; }
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#define GPU_DEVICE_H_
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
#include "mozilla/webgpu/WebGPUTypes.h"
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -55,6 +55,7 @@ class RenderPipeline;
|
|||
class Sampler;
|
||||
class ShaderModule;
|
||||
class Texture;
|
||||
class WebGPUChild;
|
||||
|
||||
class Device final : public DOMEventTargetHelper {
|
||||
public:
|
||||
|
@ -62,15 +63,16 @@ 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(Adapter* const aParent, RawId aId);
|
||||
void GetLabel(nsAString& aValue) const;
|
||||
void SetLabel(const nsAString& aLabel);
|
||||
|
||||
|
|
|
@ -6,20 +6,35 @@
|
|||
#include "Instance.h"
|
||||
|
||||
#include "Adapter.h"
|
||||
#include "InstanceProvider.h"
|
||||
#include "gfxConfig.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, mParent)
|
||||
GPU_IMPL_CYCLE_COLLECTION(Instance, mBridge, mOwner)
|
||||
|
||||
/*static*/
|
||||
RefPtr<Instance> Instance::Create(nsIGlobalObject* parent) {
|
||||
return new Instance(parent);
|
||||
already_AddRefed<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!");
|
||||
}
|
||||
|
||||
RefPtr<Instance> result = new Instance(aOwner, bridge);
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
Instance::Instance(nsIGlobalObject* parent) : mParent(parent) {}
|
||||
Instance::Instance(nsIGlobalObject* aOwner, WebGPUChild* aBridge)
|
||||
: mOwner(aOwner), mBridge(aBridge) {}
|
||||
|
||||
Instance::~Instance() = default;
|
||||
|
||||
|
@ -28,5 +43,36 @@ JSObject* Instance::WrapObject(JSContext* cx,
|
|||
return dom::GPU_Binding::Wrap(cx, this, givenProto);
|
||||
}
|
||||
|
||||
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) {
|
||||
if (aRv.isSome()) {
|
||||
promise->MaybeRejectWithDOMException(NS_ERROR_DOM_ABORT_ERR,
|
||||
"Internal communication error!");
|
||||
} else {
|
||||
promise->MaybeRejectWithDOMException(NS_ERROR_DOM_INVALID_STATE_ERR,
|
||||
"No matching adapter found!");
|
||||
}
|
||||
});
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
} // namespace webgpu
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -19,23 +19,29 @@ struct GPURequestAdapterOptions;
|
|||
|
||||
namespace webgpu {
|
||||
class Adapter;
|
||||
class InstanceProvider;
|
||||
class GPUAdapter;
|
||||
class WebGPUChild;
|
||||
|
||||
class Instance final : public nsWrapperCache {
|
||||
public:
|
||||
GPU_DECL_CYCLE_COLLECTION(Instance)
|
||||
GPU_DECL_JS_WRAP(Instance)
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> mParent;
|
||||
static already_AddRefed<Instance> Create(nsIGlobalObject* aOwner);
|
||||
|
||||
static RefPtr<Instance> Create(nsIGlobalObject* parent);
|
||||
already_AddRefed<dom::Promise> RequestAdapter(
|
||||
const dom::GPURequestAdapterOptions& aOptions, ErrorResult& aRv);
|
||||
|
||||
private:
|
||||
explicit Instance(nsIGlobalObject* parent);
|
||||
explicit Instance(nsIGlobalObject* aOwner, WebGPUChild* aBridge);
|
||||
virtual ~Instance();
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> mOwner;
|
||||
const RefPtr<WebGPUChild> mBridge;
|
||||
|
||||
public:
|
||||
nsIGlobalObject* GetParentObject() const { return mParent.get(); }
|
||||
nsIGlobalObject* GetParentObject() const { return mOwner; }
|
||||
WebGPUChild* GetBridge() const;
|
||||
};
|
||||
|
||||
} // namespace webgpu
|
||||
|
|
|
@ -1,38 +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/. */
|
||||
|
||||
#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
|
|
@ -1,55 +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 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_
|
|
@ -19,8 +19,8 @@ class ChildOf {
|
|||
public:
|
||||
const RefPtr<T> mParent;
|
||||
|
||||
explicit ChildOf(
|
||||
T* parent = nullptr); // TODO: This can't be nullptr eventually.
|
||||
explicit ChildOf(T* const parent);
|
||||
|
||||
protected:
|
||||
virtual ~ChildOf();
|
||||
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
# -*- 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'
|
|
@ -0,0 +1,31 @@
|
|||
/* -*- 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
|
|
@ -0,0 +1,38 @@
|
|||
/* -*- 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
|
|
@ -0,0 +1,84 @@
|
|||
/* -*- 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 {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION(WebGPUChild)
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGPUChild, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGPUChild, Release)
|
||||
|
||||
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
|
|
@ -0,0 +1,68 @@
|
|||
/* -*- 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 {
|
||||
public:
|
||||
friend class layers::CompositorBridgeChild;
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(WebGPUChild)
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGPUChild)
|
||||
|
||||
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_
|
|
@ -0,0 +1,57 @@
|
|||
/* -*- 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
|
|
@ -0,0 +1,43 @@
|
|||
/* -*- 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_
|
|
@ -0,0 +1,34 @@
|
|||
/* -*- 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 "ipc/IPCMessageUtils.h"
|
||||
#include "mozilla/dom/WebGPUBinding.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_
|
|
@ -0,0 +1,18 @@
|
|||
/* -*- 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_
|
|
@ -3,4 +3,4 @@ subsuite = webgl1-core
|
|||
prefs = dom.webgpu.enable=true
|
||||
|
||||
[test_enabled.html]
|
||||
|
||||
[test_device_creation.html]
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<!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>
|
||||
|
|
@ -13,7 +13,7 @@ MOCHITEST_MANIFESTS += [
|
|||
]
|
||||
|
||||
DIRS += [
|
||||
'thread',
|
||||
'ffi',
|
||||
]
|
||||
|
||||
h_and_cpp = [
|
||||
|
@ -30,7 +30,6 @@ h_and_cpp = [
|
|||
'DeviceLostInfo',
|
||||
'Fence',
|
||||
'Instance',
|
||||
'InstanceProvider',
|
||||
'ObjectModel',
|
||||
'OutOfMemoryError',
|
||||
'PipelineLayout',
|
||||
|
@ -51,4 +50,22 @@ 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'
|
||||
|
|
|
@ -1,61 +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/. */
|
||||
|
||||
#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
|
|
@ -1,42 +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 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
|
|
@ -1,18 +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/.
|
||||
|
||||
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'
|
|
@ -0,0 +1,53 @@
|
|||
[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" }
|
|
@ -0,0 +1,37 @@
|
|||
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"
|
|
@ -0,0 +1,132 @@
|
|||
/* 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
|
||||
}
|
||||
}
|
|
@ -0,0 +1,165 @@
|
|||
/* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,222 @@
|
|||
/* 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())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,316 @@
|
|||
/* 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))
|
||||
}
|
|
@ -0,0 +1,769 @@
|
|||
/* 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))
|
||||
}
|
|
@ -0,0 +1,848 @@
|
|||
/* 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!()
|
||||
}
|
|
@ -0,0 +1,421 @@
|
|||
/* 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))
|
||||
}
|
|
@ -0,0 +1,661 @@
|
|||
/* 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,
|
||||
}
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,556 @@
|
|||
/* 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
|
||||
}
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
/* 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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,563 @@
|
|||
/* 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))
|
||||
}
|
|
@ -0,0 +1,234 @@
|
|||
/* 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>>;
|
|
@ -0,0 +1,354 @@
|
|||
/* 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)>,
|
||||
}
|
|
@ -0,0 +1,373 @@
|
|||
/* 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
|
||||
}
|
||||
}
|
|
@ -0,0 +1,254 @@
|
|||
/* 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))
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
/* 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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,472 @@
|
|||
/* 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
|
||||
}
|
||||
}
|
|
@ -0,0 +1,411 @@
|
|||
/* 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)),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,301 @@
|
|||
/* 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,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
[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" }
|
|
@ -0,0 +1,46 @@
|
|||
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"
|
|
@ -0,0 +1,150 @@
|
|||
/* 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)
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/* 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))
|
||||
}
|
|
@ -57,8 +57,9 @@ dictionary GPUObjectDescriptorBase {
|
|||
Exposed=Window,
|
||||
]
|
||||
interface GPU {
|
||||
//[Exposed=Window]
|
||||
//Promise<GPUAdapter> requestAdapter(optional GPURequestAdapterOptions options = {});
|
||||
// May reject with DOMException
|
||||
[NewObject]
|
||||
Promise<GPUAdapter> requestAdapter(optional GPURequestAdapterOptions options = {});
|
||||
};
|
||||
|
||||
// Add a "webgpu" member to Navigator/Worker that contains the global instance of a "WebGPU"
|
||||
|
@ -82,8 +83,9 @@ interface GPUAdapter {
|
|||
//GPUExtensions getExtensions();
|
||||
//readonly attribute GPULimits limits; Don't expose higher limits for now.
|
||||
|
||||
// May reject with DOMException // TODO: DOMException("OperationError")?
|
||||
//Promise<GPUDevice> requestDevice(optional GPUDeviceDescriptor descriptor = {});
|
||||
// May reject with DOMException
|
||||
[NewObject]
|
||||
Promise<GPUDevice> requestDevice(optional GPUDeviceDescriptor descriptor = {});
|
||||
};
|
||||
GPUAdapter includes GPUObjectBase;
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#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"
|
||||
|
@ -272,10 +271,6 @@ 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;
|
||||
|
@ -559,10 +554,6 @@ 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();
|
||||
|
||||
|
|
|
@ -30,8 +30,10 @@
|
|||
#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
|
||||
|
@ -185,6 +187,12 @@ 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 =
|
||||
|
@ -958,6 +966,16 @@ 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) {
|
||||
|
@ -1048,6 +1066,18 @@ 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();
|
||||
|
|
|
@ -31,6 +31,11 @@ namespace dom {
|
|||
class BrowserChild;
|
||||
} // namespace dom
|
||||
|
||||
namespace webgpu {
|
||||
class PWebGPUChild;
|
||||
class WebGPUChild;
|
||||
} // namespace webgpu
|
||||
|
||||
namespace widget {
|
||||
class CompositorWidget;
|
||||
} // namespace widget
|
||||
|
@ -127,6 +132,8 @@ 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
|
||||
|
@ -221,6 +228,9 @@ 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();
|
||||
|
@ -399,6 +409,8 @@ class CompositorBridgeChild final : public PCompositorBridgeChild,
|
|||
uintptr_t mTotalFlushCount;
|
||||
|
||||
RefPtr<CanvasChild> mCanvasChild;
|
||||
|
||||
RefPtr<webgpu::WebGPUChild> mWebGPUChild;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
#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,6 +1924,22 @@ 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 =
|
||||
|
|
|
@ -53,6 +53,11 @@ namespace mozilla {
|
|||
|
||||
class CancelableRunnable;
|
||||
|
||||
namespace webgpu {
|
||||
class PWebGPUParent;
|
||||
class WebGPUParent;
|
||||
} // namespace webgpu
|
||||
|
||||
namespace gfx {
|
||||
class DrawTarget;
|
||||
class GPUProcessManager;
|
||||
|
@ -232,6 +237,9 @@ 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(
|
||||
|
@ -646,6 +654,9 @@ 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(
|
||||
|
@ -665,6 +676,8 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase,
|
|||
|
||||
WebRenderBridgeParent* GetWrBridge() { return mWrBridge; }
|
||||
|
||||
webgpu::WebGPUParent* GetWebGPUBridge() { return mWebGPUBridge; }
|
||||
|
||||
private:
|
||||
void Initialize();
|
||||
|
||||
|
@ -766,6 +779,7 @@ 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;
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#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
|
||||
|
@ -271,6 +272,19 @@ 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);
|
||||
|
|
|
@ -12,6 +12,10 @@
|
|||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace webgpu {
|
||||
class PWebGPUParent;
|
||||
} // namespace webgpu
|
||||
|
||||
namespace layers {
|
||||
|
||||
class CanvasParent;
|
||||
|
@ -206,6 +210,9 @@ 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;
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ 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";
|
||||
|
@ -101,6 +102,7 @@ sync refcounted protocol PCompositorBridge
|
|||
manages PTexture;
|
||||
manages PCompositorWidget;
|
||||
manages PWebRenderBridge;
|
||||
manages PWebGPU;
|
||||
|
||||
child:
|
||||
// The child should invalidate retained layers. This is used for local
|
||||
|
@ -166,6 +168,10 @@ 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.
|
||||
*/
|
||||
|
|
|
@ -986,6 +986,8 @@ 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
|
||||
|
|
|
@ -28,7 +28,7 @@ gecko_profiler = []
|
|||
|
||||
[dependencies]
|
||||
app_units = "0.7"
|
||||
arrayvec = "0.4.6"
|
||||
arrayvec = "0.5"
|
||||
atomic_refcell = "0.1"
|
||||
bitflags = "1.0"
|
||||
byteorder = "1.0"
|
||||
|
@ -76,7 +76,7 @@ thin-slice = "0.1.0"
|
|||
to_shmem = {path = "../to_shmem"}
|
||||
to_shmem_derive = {path = "../to_shmem_derive"}
|
||||
time = "0.1"
|
||||
uluru = "0.3"
|
||||
uluru = "0.4"
|
||||
unicode-bidi = "0.3"
|
||||
unicode-segmentation = "1.0"
|
||||
void = "1.0.2"
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"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"}
|
||||
{"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"}
|
|
@ -11,8 +11,9 @@
|
|||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
name = "arrayvec"
|
||||
version = "0.4.11"
|
||||
version = "0.5.1"
|
||||
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/"
|
||||
|
@ -21,10 +22,16 @@ categories = ["data-structures", "no-std"]
|
|||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/bluss/arrayvec"
|
||||
[package.metadata.docs.rs]
|
||||
features = ["serde-1"]
|
||||
features = ["serde"]
|
||||
|
||||
[package.metadata.release]
|
||||
no-dev-version = true
|
||||
tag-name = "{{version}}"
|
||||
[profile.bench]
|
||||
debug = true
|
||||
|
||||
[profile.release]
|
||||
debug = true
|
||||
|
||||
[[bench]]
|
||||
name = "extend"
|
||||
|
@ -33,10 +40,6 @@ harness = false
|
|||
[[bench]]
|
||||
name = "arraystring"
|
||||
harness = false
|
||||
[dependencies.nodrop]
|
||||
version = "0.1.12"
|
||||
default-features = false
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0"
|
||||
optional = true
|
||||
|
@ -56,6 +59,4 @@ version = "1.0"
|
|||
array-sizes-129-255 = []
|
||||
array-sizes-33-128 = []
|
||||
default = ["std"]
|
||||
serde-1 = ["serde"]
|
||||
std = []
|
||||
use_union = []
|
||||
|
|
|
@ -22,6 +22,46 @@ __ 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
|
||||
|
|
|
@ -2,17 +2,21 @@
|
|||
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();
|
||||
v.extend((0..cap).map(|_| 1));
|
||||
v[0]
|
||||
let constant = black_box(1);
|
||||
v.extend((0..cap).map(move |_| constant));
|
||||
v[511]
|
||||
});
|
||||
b.bytes = v.capacity() as u64;
|
||||
}
|
||||
|
@ -22,8 +26,9 @@ fn extend_with_range(b: &mut Bencher) {
|
|||
let cap = v.capacity();
|
||||
b.iter(|| {
|
||||
v.clear();
|
||||
v.extend((0..cap).map(|x| x as _));
|
||||
v[0]
|
||||
let range = 0..cap;
|
||||
v.extend(range.map(|x| black_box(x as _)));
|
||||
v[511]
|
||||
});
|
||||
b.bytes = v.capacity() as u64;
|
||||
}
|
||||
|
@ -33,11 +38,41 @@ fn extend_with_slice(b: &mut Bencher) {
|
|||
let data = [1; 512];
|
||||
b.iter(|| {
|
||||
v.clear();
|
||||
v.extend(data.iter().cloned());
|
||||
v[0]
|
||||
let iter = data.iter().map(|&x| x);
|
||||
v.extend(iter);
|
||||
v[511]
|
||||
});
|
||||
b.bytes = v.capacity() as u64;
|
||||
}
|
||||
|
||||
benchmark_group!(benches, extend_with_constant, extend_with_range, extend_with_slice);
|
||||
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_main!(benches);
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
|
||||
use std::env;
|
||||
use std::io::Write;
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
fn main() {
|
||||
// we need to output *some* file to opt out of the default
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
|
||||
detect_maybe_uninit();
|
||||
}
|
||||
|
||||
fn detect_maybe_uninit() {
|
||||
let has_stable_maybe_uninit = probe(&stable_maybe_uninit());
|
||||
if has_stable_maybe_uninit {
|
||||
println!("cargo:rustc-cfg=has_stable_maybe_uninit");
|
||||
return;
|
||||
}
|
||||
let has_unstable_union_with_md = probe(&maybe_uninit_code(true));
|
||||
if has_unstable_union_with_md {
|
||||
println!("cargo:rustc-cfg=has_manually_drop_in_union");
|
||||
println!("cargo:rustc-cfg=has_union_feature");
|
||||
}
|
||||
}
|
||||
|
||||
// To guard against changes in this currently unstable feature, use
|
||||
// a detection tests instead of a Rustc version and/or date test.
|
||||
fn stable_maybe_uninit() -> String {
|
||||
let code = "
|
||||
#![allow(warnings)]
|
||||
use std::mem::MaybeUninit;
|
||||
|
||||
fn main() { }
|
||||
";
|
||||
code.to_string()
|
||||
}
|
||||
|
||||
// To guard against changes in this currently unstable feature, use
|
||||
// a detection tests instead of a Rustc version and/or date test.
|
||||
fn maybe_uninit_code(use_feature: bool) -> String {
|
||||
let feature = if use_feature { "#![feature(untagged_unions)]" } else { "" };
|
||||
|
||||
let code = "
|
||||
#![allow(warnings)]
|
||||
use std::mem::ManuallyDrop;
|
||||
|
||||
#[derive(Copy)]
|
||||
pub union MaybeUninit<T> {
|
||||
empty: (),
|
||||
value: ManuallyDrop<T>,
|
||||
}
|
||||
|
||||
impl<T> Clone for MaybeUninit<T> where T: Copy
|
||||
{
|
||||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let value1 = MaybeUninit::<[i32; 3]> { empty: () };
|
||||
let value2 = MaybeUninit { value: ManuallyDrop::new([1, 2, 3]) };
|
||||
}
|
||||
";
|
||||
|
||||
|
||||
[feature, code].concat()
|
||||
}
|
||||
|
||||
/// Test if a code snippet can be compiled
|
||||
fn probe(code: &str) -> bool {
|
||||
let rustc = env::var_os("RUSTC").unwrap_or_else(|| "rustc".into());
|
||||
let out_dir = env::var_os("OUT_DIR").expect("environment variable OUT_DIR");
|
||||
|
||||
let mut child = Command::new(rustc)
|
||||
.arg("--out-dir")
|
||||
.arg(out_dir)
|
||||
.arg("--emit=obj")
|
||||
.arg("-")
|
||||
.stdin(Stdio::piped())
|
||||
.spawn()
|
||||
.expect("rustc probe");
|
||||
|
||||
child
|
||||
.stdin
|
||||
.as_mut()
|
||||
.expect("rustc stdin")
|
||||
.write_all(code.as_bytes())
|
||||
.expect("write rustc stdin");
|
||||
|
||||
child.wait().expect("rustc probe").success()
|
||||
}
|
|
@ -12,37 +12,45 @@
|
|||
/// (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 doesn’t
|
||||
/// need implementing.
|
||||
pub unsafe trait Array {
|
||||
/// The array’s 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;
|
||||
#[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;
|
||||
/// The array's element capacity
|
||||
const CAPACITY: usize;
|
||||
fn as_slice(&self) -> &[Self::Item];
|
||||
fn as_mut_slice(&mut self) -> &mut [Self::Item];
|
||||
}
|
||||
|
||||
pub trait Index : PartialEq + Copy {
|
||||
fn to_usize(self) -> usize;
|
||||
fn from(usize) -> Self;
|
||||
fn from(_: usize) -> Self;
|
||||
}
|
||||
|
||||
use std::slice::{from_raw_parts};
|
||||
|
||||
pub trait ArrayExt : Array {
|
||||
impl Index for () {
|
||||
#[inline(always)]
|
||||
fn as_slice(&self) -> &[Self::Item] {
|
||||
unsafe {
|
||||
from_raw_parts(self.as_ptr(), Self::capacity())
|
||||
}
|
||||
}
|
||||
fn to_usize(self) -> usize { 0 }
|
||||
#[inline(always)]
|
||||
fn from(_ix: usize) -> Self { () }
|
||||
}
|
||||
|
||||
impl<A> ArrayExt for A where A: Array { }
|
||||
impl Index for bool {
|
||||
#[inline(always)]
|
||||
fn to_usize(self) -> usize { self as usize }
|
||||
#[inline(always)]
|
||||
fn from(ix: usize) -> Self { ix != 0 }
|
||||
}
|
||||
|
||||
impl Index for u8 {
|
||||
#[inline(always)]
|
||||
|
@ -77,15 +85,11 @@ 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)]
|
||||
#[inline(always)]
|
||||
fn as_ptr(&self) -> *const T { self as *const _ as *const _ }
|
||||
fn as_slice(&self) -> &[Self::Item] { self }
|
||||
#[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 }
|
||||
fn as_mut_slice(&mut self) -> &mut [Self::Item] { self }
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -97,7 +101,10 @@ macro_rules! fix_array_impl_recursive {
|
|||
);
|
||||
}
|
||||
|
||||
fix_array_impl_recursive!(u8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
|
||||
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,
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
|
||||
28, 29, 30, 31, );
|
||||
|
||||
|
|
|
@ -2,21 +2,23 @@ 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 array::{Array, ArrayExt};
|
||||
use array::Index;
|
||||
use CapacityError;
|
||||
use char::encode_utf8;
|
||||
use crate::array::Array;
|
||||
use crate::array::Index;
|
||||
use crate::CapacityError;
|
||||
use crate::char::encode_utf8;
|
||||
|
||||
#[cfg(feature="serde-1")]
|
||||
#[cfg(feature="serde")]
|
||||
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
|
||||
|
@ -25,20 +27,25 @@ use serde::{Serialize, Deserialize, Serializer, Deserializer};
|
|||
/// 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,
|
||||
pub struct ArrayString<A>
|
||||
where A: Array<Item=u8> + Copy
|
||||
{
|
||||
xs: MaybeUninitCopy<A>,
|
||||
len: A::Index,
|
||||
}
|
||||
|
||||
impl<A: Array<Item=u8>> Default for ArrayString<A> {
|
||||
impl<A> Default for ArrayString<A>
|
||||
where A: Array<Item=u8> + Copy
|
||||
{
|
||||
/// Return an empty `ArrayString`
|
||||
fn default() -> ArrayString<A> {
|
||||
ArrayString::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Array<Item=u8>> ArrayString<A> {
|
||||
impl<A> ArrayString<A>
|
||||
where A: Array<Item=u8> + Copy
|
||||
{
|
||||
/// Create a new empty `ArrayString`.
|
||||
///
|
||||
/// Capacity is inferred from the type parameter.
|
||||
|
@ -54,13 +61,16 @@ impl<A: Array<Item=u8>> ArrayString<A> {
|
|||
pub fn new() -> ArrayString<A> {
|
||||
unsafe {
|
||||
ArrayString {
|
||||
// FIXME: Use Copyable union for xs when we can
|
||||
xs: mem::zeroed(),
|
||||
xs: MaybeUninitCopy::uninitialized(),
|
||||
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.
|
||||
|
@ -91,11 +101,12 @@ impl<A: Array<Item=u8>> ArrayString<A> {
|
|||
/// 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)
|
||||
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),
|
||||
})
|
||||
}
|
||||
|
||||
/// Return the capacity of the `ArrayString`.
|
||||
|
@ -106,8 +117,8 @@ impl<A: Array<Item=u8>> ArrayString<A> {
|
|||
/// let string = ArrayString::<[_; 3]>::new();
|
||||
/// assert_eq!(string.capacity(), 3);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn capacity(&self) -> usize { A::capacity() }
|
||||
#[inline(always)]
|
||||
pub fn capacity(&self) -> usize { A::CAPACITY }
|
||||
|
||||
/// Return if the `ArrayString` is completely filled.
|
||||
///
|
||||
|
@ -160,7 +171,9 @@ impl<A: Array<Item=u8>> ArrayString<A> {
|
|||
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..]) {
|
||||
let ptr = self.xs.ptr_mut().add(len);
|
||||
let remaining_cap = self.capacity() - len;
|
||||
match encode_utf8(c, ptr, remaining_cap) {
|
||||
Ok(n) => {
|
||||
self.set_len(len + n);
|
||||
Ok(())
|
||||
|
@ -213,7 +226,7 @@ impl<A: Array<Item=u8>> ArrayString<A> {
|
|||
return Err(CapacityError::new(s));
|
||||
}
|
||||
unsafe {
|
||||
let dst = self.xs.as_mut_ptr().offset(self.len() as isize);
|
||||
let dst = self.xs.ptr_mut().offset(self.len() as isize);
|
||||
let src = s.as_ptr();
|
||||
ptr::copy_nonoverlapping(src, dst, s.len());
|
||||
let newl = self.len() + s.len();
|
||||
|
@ -237,7 +250,6 @@ impl<A: Array<Item=u8>> 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,
|
||||
|
@ -266,7 +278,6 @@ impl<A: Array<Item=u8>> 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));
|
||||
|
@ -297,7 +308,6 @@ impl<A: Array<Item=u8>> 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,
|
||||
|
@ -307,8 +317,8 @@ impl<A: Array<Item=u8>> ArrayString<A> {
|
|||
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),
|
||||
ptr::copy(self.xs.ptr().offset(next as isize),
|
||||
self.xs.ptr_mut().offset(idx as isize),
|
||||
len - next);
|
||||
self.set_len(len - (next - idx));
|
||||
}
|
||||
|
@ -329,7 +339,6 @@ impl<A: Array<Item=u8>> 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);
|
||||
|
@ -339,79 +348,97 @@ impl<A: Array<Item=u8>> ArrayString<A> {
|
|||
pub fn as_str(&self) -> &str {
|
||||
self
|
||||
}
|
||||
|
||||
/// Return a mutable slice of the whole string’s 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> {
|
||||
impl<A> Deref for ArrayString<A>
|
||||
where A: Array<Item=u8> + Copy
|
||||
{
|
||||
type Target = str;
|
||||
#[inline]
|
||||
fn deref(&self) -> &str {
|
||||
unsafe {
|
||||
let sl = slice::from_raw_parts(self.xs.as_ptr(), self.len.to_usize());
|
||||
let sl = slice::from_raw_parts(self.xs.ptr(), self.len.to_usize());
|
||||
str::from_utf8_unchecked(sl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Array<Item=u8>> DerefMut for ArrayString<A> {
|
||||
impl<A> DerefMut for ArrayString<A>
|
||||
where A: Array<Item=u8> + Copy
|
||||
{
|
||||
#[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)
|
||||
let sl = slice::from_raw_parts_mut(self.xs.ptr_mut(), self.len.to_usize());
|
||||
str::from_utf8_unchecked_mut(sl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Array<Item=u8>> PartialEq for ArrayString<A> {
|
||||
impl<A> PartialEq for ArrayString<A>
|
||||
where A: Array<Item=u8> + Copy
|
||||
{
|
||||
fn eq(&self, rhs: &Self) -> bool {
|
||||
**self == **rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Array<Item=u8>> PartialEq<str> for ArrayString<A> {
|
||||
impl<A> PartialEq<str> for ArrayString<A>
|
||||
where A: Array<Item=u8> + Copy
|
||||
{
|
||||
fn eq(&self, rhs: &str) -> bool {
|
||||
&**self == rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Array<Item=u8>> PartialEq<ArrayString<A>> for str {
|
||||
impl<A> PartialEq<ArrayString<A>> for str
|
||||
where A: Array<Item=u8> + Copy
|
||||
{
|
||||
fn eq(&self, rhs: &ArrayString<A>) -> bool {
|
||||
self == &**rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Array<Item=u8>> Eq for ArrayString<A> { }
|
||||
impl<A> Eq for ArrayString<A>
|
||||
where A: Array<Item=u8> + Copy
|
||||
{ }
|
||||
|
||||
impl<A: Array<Item=u8>> Hash for ArrayString<A> {
|
||||
impl<A> Hash for ArrayString<A>
|
||||
where A: Array<Item=u8> + Copy
|
||||
{
|
||||
fn hash<H: Hasher>(&self, h: &mut H) {
|
||||
(**self).hash(h)
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Array<Item=u8>> Borrow<str> for ArrayString<A> {
|
||||
impl<A> Borrow<str> for ArrayString<A>
|
||||
where A: Array<Item=u8> + Copy
|
||||
{
|
||||
fn borrow(&self) -> &str { self }
|
||||
}
|
||||
|
||||
impl<A: Array<Item=u8>> AsRef<str> for ArrayString<A> {
|
||||
impl<A> AsRef<str> for ArrayString<A>
|
||||
where A: Array<Item=u8> + Copy
|
||||
{
|
||||
fn as_ref(&self) -> &str { self }
|
||||
}
|
||||
|
||||
impl<A: Array<Item=u8>> fmt::Debug for ArrayString<A> {
|
||||
impl<A> fmt::Debug for ArrayString<A>
|
||||
where A: Array<Item=u8> + Copy
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) }
|
||||
}
|
||||
|
||||
impl<A: Array<Item=u8>> fmt::Display for ArrayString<A> {
|
||||
impl<A> fmt::Display for ArrayString<A>
|
||||
where A: Array<Item=u8> + Copy
|
||||
{
|
||||
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> {
|
||||
impl<A> fmt::Write for ArrayString<A>
|
||||
where A: Array<Item=u8> + Copy
|
||||
{
|
||||
fn write_char(&mut self, c: char) -> fmt::Result {
|
||||
self.try_push(c).map_err(|_| fmt::Error)
|
||||
}
|
||||
|
@ -421,7 +448,9 @@ impl<A: Array<Item=u8>> fmt::Write for ArrayString<A> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<A: Array<Item=u8> + Copy> Clone for ArrayString<A> {
|
||||
impl<A> Clone for ArrayString<A>
|
||||
where A: Array<Item=u8> + Copy
|
||||
{
|
||||
fn clone(&self) -> ArrayString<A> {
|
||||
*self
|
||||
}
|
||||
|
@ -432,7 +461,9 @@ impl<A: Array<Item=u8> + Copy> Clone for ArrayString<A> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<A: Array<Item=u8>> PartialOrd for ArrayString<A> {
|
||||
impl<A> PartialOrd for ArrayString<A>
|
||||
where A: Array<Item=u8> + Copy
|
||||
{
|
||||
fn partial_cmp(&self, rhs: &Self) -> Option<cmp::Ordering> {
|
||||
(**self).partial_cmp(&**rhs)
|
||||
}
|
||||
|
@ -442,7 +473,9 @@ impl<A: Array<Item=u8>> PartialOrd for ArrayString<A> {
|
|||
fn ge(&self, rhs: &Self) -> bool { **self >= **rhs }
|
||||
}
|
||||
|
||||
impl<A: Array<Item=u8>> PartialOrd<str> for ArrayString<A> {
|
||||
impl<A> PartialOrd<str> for ArrayString<A>
|
||||
where A: Array<Item=u8> + Copy
|
||||
{
|
||||
fn partial_cmp(&self, rhs: &str) -> Option<cmp::Ordering> {
|
||||
(**self).partial_cmp(rhs)
|
||||
}
|
||||
|
@ -452,7 +485,9 @@ impl<A: Array<Item=u8>> PartialOrd<str> for ArrayString<A> {
|
|||
fn ge(&self, rhs: &str) -> bool { &**self >= rhs }
|
||||
}
|
||||
|
||||
impl<A: Array<Item=u8>> PartialOrd<ArrayString<A>> for str {
|
||||
impl<A> PartialOrd<ArrayString<A>> for str
|
||||
where A: Array<Item=u8> + Copy
|
||||
{
|
||||
fn partial_cmp(&self, rhs: &ArrayString<A>) -> Option<cmp::Ordering> {
|
||||
self.partial_cmp(&**rhs)
|
||||
}
|
||||
|
@ -462,15 +497,29 @@ impl<A: Array<Item=u8>> PartialOrd<ArrayString<A>> for str {
|
|||
fn ge(&self, rhs: &ArrayString<A>) -> bool { self >= &**rhs }
|
||||
}
|
||||
|
||||
impl<A: Array<Item=u8>> Ord for ArrayString<A> {
|
||||
impl<A> Ord for ArrayString<A>
|
||||
where A: Array<Item=u8> + Copy
|
||||
{
|
||||
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> {
|
||||
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
|
||||
{
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: Serializer
|
||||
{
|
||||
|
@ -478,9 +527,11 @@ impl<A: Array<Item=u8>> Serialize for ArrayString<A> {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature="serde-1")]
|
||||
/// Requires crate feature `"serde-1"`
|
||||
impl<'de, A: Array<Item=u8>> Deserialize<'de> for ArrayString<A> {
|
||||
#[cfg(feature="serde")]
|
||||
/// Requires crate feature `"serde"`
|
||||
impl<'de, A> Deserialize<'de> for ArrayString<A>
|
||||
where A: Array<Item=u8> + Copy
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where D: Deserializer<'de>
|
||||
{
|
||||
|
@ -489,11 +540,11 @@ impl<'de, A: Array<Item=u8>> Deserialize<'de> for ArrayString<A> {
|
|||
|
||||
struct ArrayStringVisitor<A: Array<Item=u8>>(PhantomData<A>);
|
||||
|
||||
impl<'de, A: Array<Item=u8>> Visitor<'de> for ArrayStringVisitor<A> {
|
||||
impl<'de, A: Copy + 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>
|
||||
|
@ -505,7 +556,7 @@ impl<'de, A: Array<Item=u8>> Deserialize<'de> for ArrayString<A> {
|
|||
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)));
|
||||
let s = 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))
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
//
|
||||
// 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;
|
||||
|
@ -22,33 +24,75 @@ 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 fn encode_utf8(ch: char, buf: &mut [u8]) -> Result<usize, EncodeUtf8Error>
|
||||
pub unsafe fn encode_utf8(ch: char, ptr: *mut u8, len: usize) -> Result<usize, EncodeUtf8Error>
|
||||
{
|
||||
let code = ch as u32;
|
||||
if code < MAX_ONE_B && buf.len() >= 1 {
|
||||
buf[0] = code as u8;
|
||||
if code < MAX_ONE_B && len >= 1 {
|
||||
write(ptr, 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;
|
||||
} 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);
|
||||
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;
|
||||
} 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);
|
||||
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;
|
||||
} 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);
|
||||
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(_)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,38 +7,31 @@
|
|||
//! - Optional, enabled by default
|
||||
//! - Use libstd; disable to use `no_std` instead.
|
||||
//!
|
||||
//! - `serde-1`
|
||||
//! - `serde`
|
||||
//! - Optional
|
||||
//! - Enable serialization for ArrayVec and ArrayString using serde 1.0
|
||||
//! - Enable serialization for ArrayVec and ArrayString using serde 1.x
|
||||
//! - `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.13 or later.
|
||||
//! This version of arrayvec requires Rust 1.36 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-1")]
|
||||
#[cfg(feature="serde")]
|
||||
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
|
||||
|
@ -50,31 +43,21 @@ 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;
|
||||
|
||||
use maybe_uninit::MaybeUninit;
|
||||
|
||||
#[cfg(feature="serde-1")]
|
||||
#[cfg(feature="serde")]
|
||||
use serde::{Serialize, Deserialize, Serializer, Deserializer};
|
||||
|
||||
mod array;
|
||||
mod array_string;
|
||||
mod char;
|
||||
mod range;
|
||||
mod errors;
|
||||
|
||||
pub use array::Array;
|
||||
pub use range::RangeArgument;
|
||||
use array::Index;
|
||||
pub use array_string::ArrayString;
|
||||
pub use errors::CapacityError;
|
||||
pub use crate::array::Array;
|
||||
use crate::array::Index;
|
||||
pub use crate::array_string::ArrayString;
|
||||
pub use crate::errors::CapacityError;
|
||||
|
||||
|
||||
/// A vector with a fixed capacity.
|
||||
|
@ -151,8 +134,8 @@ impl<A: Array> ArrayVec<A> {
|
|||
/// let array = ArrayVec::from([1, 2, 3]);
|
||||
/// assert_eq!(array.capacity(), 3);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn capacity(&self) -> usize { A::capacity() }
|
||||
#[inline(always)]
|
||||
pub fn capacity(&self) -> usize { A::CAPACITY }
|
||||
|
||||
/// Return if the `ArrayVec` is completely filled.
|
||||
///
|
||||
|
@ -166,6 +149,19 @@ 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.
|
||||
|
@ -207,7 +203,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);
|
||||
}
|
||||
|
@ -239,14 +235,18 @@ 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_mut(len), element);
|
||||
debug_assert!(len < A::CAPACITY);
|
||||
ptr::write(self.get_unchecked_ptr(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_mut(index);
|
||||
let p: *mut _ = self.get_unchecked_ptr(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_mut(new_len)))
|
||||
Some(ptr::read(self.get_unchecked_ptr(new_len)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -455,13 +455,19 @@ impl<A: Array> ArrayVec<A> {
|
|||
/// array.truncate(4);
|
||||
/// assert_eq!(&array[..], &[1, 2, 3]);
|
||||
/// ```
|
||||
pub fn truncate(&mut self, len: usize) {
|
||||
while self.len() > len { self.pop(); }
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove all elements in the vector.
|
||||
pub fn clear(&mut self) {
|
||||
while let Some(_) = self.pop() { }
|
||||
self.truncate(0)
|
||||
}
|
||||
|
||||
/// Retains only the elements specified by the predicate.
|
||||
|
@ -503,14 +509,49 @@ 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 check that `length` is
|
||||
/// This method uses *debug assertions* to 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.
|
||||
|
@ -529,11 +570,13 @@ impl<A: Array> ArrayVec<A> {
|
|||
/// assert_eq!(&v[..], &[3]);
|
||||
/// assert_eq!(&u[..], &[1, 2]);
|
||||
/// ```
|
||||
pub fn drain<R: RangeArgument>(&mut self, range: R) -> Drain<A> {
|
||||
pub fn drain<R>(&mut self, range: R) -> Drain<A>
|
||||
where R: RangeBounds<usize>
|
||||
{
|
||||
// Memory safety
|
||||
//
|
||||
// When the Drain is first created, it shortens the length of
|
||||
// the source vector to make sure no uninitalized or moved-from elements
|
||||
// the source vector to make sure no uninitialized 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.
|
||||
|
@ -541,8 +584,22 @@ impl<A: Array> ArrayVec<A> {
|
|||
// the hole, and the vector length is restored to the new length.
|
||||
//
|
||||
let len = self.len();
|
||||
let start = range.start().unwrap_or(0);
|
||||
let end = range.end().unwrap_or(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();
|
||||
// bounds check happens here
|
||||
let range_slice: *const _ = &self[start..end];
|
||||
|
||||
|
@ -562,9 +619,6 @@ 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)
|
||||
|
@ -577,7 +631,8 @@ impl<A: Array> ArrayVec<A> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Dispose of `self` without the overwriting that is needed in Drop.
|
||||
/// Dispose of `self` (same as drop)
|
||||
#[deprecated="Use std::mem::drop instead, if at all needed."]
|
||||
pub fn dispose(mut self) {
|
||||
self.clear();
|
||||
mem::forget(self);
|
||||
|
@ -592,6 +647,16 @@ 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> {
|
||||
|
@ -625,7 +690,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) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -693,7 +758,6 @@ 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
|
||||
|
@ -701,7 +765,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_mut(index)))
|
||||
Some(ptr::read(self.v.get_unchecked_ptr(index)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -713,7 +777,6 @@ 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
|
||||
|
@ -721,7 +784,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_mut(new_len)))
|
||||
Some(ptr::read(self.v.get_unchecked_ptr(new_len)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -737,7 +800,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_mut(index),
|
||||
self.v.get_unchecked_ptr(index),
|
||||
len - index);
|
||||
ptr::drop_in_place(elements);
|
||||
}
|
||||
|
@ -790,7 +853,6 @@ 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 {
|
||||
|
@ -799,7 +861,6 @@ impl<'a, A: Array> Iterator for Drain<'a, A>
|
|||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.iter.size_hint()
|
||||
}
|
||||
|
@ -808,7 +869,6 @@ 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 {
|
||||
|
@ -871,27 +931,52 @@ impl<A: Array> Extend<A::Item> for ArrayVec<A> {
|
|||
let take = self.capacity() - self.len();
|
||||
unsafe {
|
||||
let len = self.len();
|
||||
let mut ptr = self.as_mut_ptr().offset(len as isize);
|
||||
let mut ptr = raw_ptr_add(self.as_mut_ptr(), len);
|
||||
let end_ptr = raw_ptr_add(ptr, take);
|
||||
// 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: self,
|
||||
value: &mut self.len,
|
||||
data: len,
|
||||
f: |&len, self_| {
|
||||
self_.set_len(len)
|
||||
f: move |&len, self_len| {
|
||||
**self_len = Index::from(len);
|
||||
}
|
||||
};
|
||||
for elt in iter.into_iter().take(take) {
|
||||
ptr::write(ptr, elt);
|
||||
ptr = ptr.offset(1);
|
||||
guard.data += 1;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
|
@ -982,27 +1067,22 @@ 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)
|
||||
}
|
||||
|
@ -1020,22 +1100,16 @@ 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> {
|
||||
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
|
||||
}
|
||||
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)
|
||||
}
|
||||
fn flush(&mut self) -> io::Result<()> { Ok(()) }
|
||||
}
|
||||
|
||||
#[cfg(feature="serde-1")]
|
||||
/// Requires crate feature `"serde-1"`
|
||||
#[cfg(feature="serde")]
|
||||
/// Requires crate feature `"serde"`
|
||||
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
|
||||
|
@ -1044,8 +1118,8 @@ impl<T: Serialize, A: Array<Item=T>> Serialize for ArrayVec<A> {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature="serde-1")]
|
||||
/// Requires crate feature `"serde-1"`
|
||||
#[cfg(feature="serde")]
|
||||
/// Requires crate feature `"serde"`
|
||||
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>
|
||||
|
@ -1059,7 +1133,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>
|
||||
|
@ -1067,9 +1141,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) = try!(seq.next_element()) {
|
||||
while let Some(value) = 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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,27 +1,28 @@
|
|||
|
||||
|
||||
use array::Array;
|
||||
use std::mem::ManuallyDrop;
|
||||
use crate::array::Array;
|
||||
use std::mem::MaybeUninit as StdMaybeUninit;
|
||||
|
||||
/// 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>,
|
||||
#[derive(Copy)]
|
||||
pub struct MaybeUninit<T> {
|
||||
inner: StdMaybeUninit<T>,
|
||||
}
|
||||
|
||||
impl<T> Clone for MaybeUninit<T>
|
||||
where T: Copy
|
||||
{
|
||||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
// 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: () }
|
||||
MaybeUninit { inner: StdMaybeUninit::uninit() }
|
||||
}
|
||||
|
||||
/// Create a new MaybeUninit from the value `v`.
|
||||
pub fn from(v: T) -> Self {
|
||||
MaybeUninit { value: ManuallyDrop::new(v) }
|
||||
MaybeUninit { inner: StdMaybeUninit::new(v) }
|
||||
}
|
||||
|
||||
// Raw pointer casts written so that we don't reference or access the
|
||||
|
@ -31,16 +32,13 @@ impl<T> MaybeUninit<T> {
|
|||
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
|
||||
self.inner.as_ptr() 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
|
||||
self.inner.as_mut_ptr() as *mut T::Item
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
|
||||
use array::Array;
|
||||
use nodrop::NoDrop;
|
||||
use std::mem::uninitialized;
|
||||
|
||||
/// A combination of NoDrop and “maybe uninitialized”;
|
||||
/// this wraps a value that can be wholly or partially uninitialized.
|
||||
///
|
||||
/// NOTE: This is known to not be a good solution, but it's the one we have kept
|
||||
/// working on stable Rust. Stable improvements are encouraged, in any form,
|
||||
/// but of course we are waiting for a real, stable, MaybeUninit.
|
||||
pub struct MaybeUninit<T>(NoDrop<T>);
|
||||
// why don't we use ManuallyDrop here: It doesn't inhibit
|
||||
// enum layout optimizations that depend on T, and we support older Rust.
|
||||
|
||||
impl<T> MaybeUninit<T> {
|
||||
/// Create a new MaybeUninit with uninitialized interior
|
||||
pub unsafe fn uninitialized() -> Self {
|
||||
Self::from(uninitialized())
|
||||
}
|
||||
|
||||
/// Create a new MaybeUninit from the value `v`.
|
||||
pub fn from(v: T) -> Self {
|
||||
MaybeUninit(NoDrop::new(v))
|
||||
}
|
||||
|
||||
/// Return a raw pointer to the start of the interior array
|
||||
pub fn ptr(&self) -> *const T::Item
|
||||
where T: Array
|
||||
{
|
||||
&*self.0 as *const T as *const _
|
||||
}
|
||||
|
||||
/// Return a mut raw pointer to the start of the interior array
|
||||
pub fn ptr_mut(&mut self) -> *mut T::Item
|
||||
where T: Array
|
||||
{
|
||||
&mut *self.0 as *mut T as *mut _
|
||||
}
|
||||
}
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
|
||||
|
||||
use array::Array;
|
||||
use std::mem::MaybeUninit as StdMaybeUninit;
|
||||
|
||||
pub struct MaybeUninit<T> {
|
||||
inner: StdMaybeUninit<T>,
|
||||
}
|
||||
|
||||
impl<T> MaybeUninit<T> {
|
||||
/// Create a new MaybeUninit with uninitialized interior
|
||||
pub unsafe fn uninitialized() -> Self {
|
||||
MaybeUninit { inner: StdMaybeUninit::uninit() }
|
||||
}
|
||||
|
||||
/// Create a new MaybeUninit from the value `v`.
|
||||
pub fn from(v: T) -> Self {
|
||||
MaybeUninit { inner: StdMaybeUninit::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.inner.as_ptr() 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
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
|
||||
use std::ops::{
|
||||
RangeFull,
|
||||
RangeFrom,
|
||||
RangeTo,
|
||||
Range,
|
||||
};
|
||||
|
||||
/// `RangeArgument` is implemented by Rust's built-in range types, produced
|
||||
/// by range syntax like `..`, `a..`, `..b` or `c..d`.
|
||||
///
|
||||
/// Note: This is arrayvec's provisional trait, waiting for stable Rust to
|
||||
/// provide an equivalent.
|
||||
pub trait RangeArgument {
|
||||
#[inline]
|
||||
/// Start index (inclusive)
|
||||
fn start(&self) -> Option<usize> { None }
|
||||
#[inline]
|
||||
/// End index (exclusive)
|
||||
fn end(&self) -> Option<usize> { None }
|
||||
}
|
||||
|
||||
|
||||
impl RangeArgument for RangeFull {}
|
||||
|
||||
impl RangeArgument for RangeFrom<usize> {
|
||||
#[inline]
|
||||
fn start(&self) -> Option<usize> { Some(self.start) }
|
||||
}
|
||||
|
||||
impl RangeArgument for RangeTo<usize> {
|
||||
#[inline]
|
||||
fn end(&self) -> Option<usize> { Some(self.end) }
|
||||
}
|
||||
|
||||
impl RangeArgument for Range<usize> {
|
||||
#[inline]
|
||||
fn start(&self) -> Option<usize> { Some(self.start) }
|
||||
#[inline]
|
||||
fn end(&self) -> Option<usize> { Some(self.end) }
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#![cfg(feature = "serde-1")]
|
||||
#![cfg(feature = "serde")]
|
||||
extern crate arrayvec;
|
||||
extern crate serde_test;
|
||||
|
||||
|
|
|
@ -27,6 +27,44 @@ 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;
|
||||
|
@ -126,6 +164,80 @@ 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;
|
||||
|
@ -146,8 +258,8 @@ fn test_extend() {
|
|||
#[test]
|
||||
fn test_is_send_sync() {
|
||||
let data = ArrayVec::<[Vec<i32>; 5]>::new();
|
||||
&data as &Send;
|
||||
&data as &Sync;
|
||||
&data as &dyn Send;
|
||||
&data as &dyn Sync;
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -158,6 +270,11 @@ 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>());
|
||||
|
@ -189,6 +306,29 @@ 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]);
|
||||
|
@ -294,6 +434,7 @@ 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;
|
||||
|
@ -328,6 +469,7 @@ fn array_clone_from() {
|
|||
assert_eq!(&t, &reference[..]);
|
||||
}
|
||||
|
||||
#[cfg(feature="std")]
|
||||
#[test]
|
||||
fn test_string() {
|
||||
use std::error::Error;
|
||||
|
@ -353,9 +495,9 @@ fn test_string() {
|
|||
assert_eq!(tmut, "ab");
|
||||
|
||||
// Test Error trait / try
|
||||
let t = || -> Result<(), Box<Error>> {
|
||||
let t = || -> Result<(), Box<dyn Error>> {
|
||||
let mut t = ArrayString::<[_; 2]>::new();
|
||||
try!(t.try_push_str(text));
|
||||
t.try_push_str(text)?;
|
||||
Ok(())
|
||||
}();
|
||||
assert!(t.is_err());
|
||||
|
@ -370,6 +512,14 @@ 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";
|
||||
|
@ -508,10 +658,22 @@ fn test_sizes_129_255() {
|
|||
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));
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
{"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"}
|
|
@ -0,0 +1,29 @@
|
|||
# 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 = []
|
|
@ -0,0 +1,120 @@
|
|||
#![allow(dead_code)]
|
||||
use vk;
|
||||
use std::os::raw::c_void;
|
||||
use std::ptr;
|
||||
pub trait VkAllocation {
|
||||
unsafe extern "system" fn allocation(
|
||||
*mut (),
|
||||
usize,
|
||||
usize,
|
||||
vk::SystemAllocationScope,
|
||||
) -> *mut ();
|
||||
unsafe extern "system" fn reallocation(
|
||||
*mut c_void,
|
||||
*mut c_void,
|
||||
usize,
|
||||
usize,
|
||||
vk::SystemAllocationScope,
|
||||
) -> *mut c_void;
|
||||
unsafe extern "system" fn free(*mut c_void, *mut c_void);
|
||||
unsafe extern "system" fn internal_allocation(
|
||||
*mut c_void,
|
||||
usize,
|
||||
vk::InternalAllocationType,
|
||||
vk::SystemAllocationScope,
|
||||
);
|
||||
unsafe extern "system" fn internal_free(
|
||||
*mut c_void,
|
||||
usize,
|
||||
vk::InternalAllocationType,
|
||||
vk::SystemAllocationScope,
|
||||
);
|
||||
fn create_allocation_callback() -> Option<vk::AllocationCallbacks> {
|
||||
let alloc = vk::AllocationCallbacks {
|
||||
p_user_data: ptr::null_mut(),
|
||||
pfn_allocation: Self::allocation,
|
||||
pfn_reallocation: Self::reallocation,
|
||||
pfn_free: Self::free,
|
||||
pfn_internal_allocation: Self::internal_allocation,
|
||||
pfn_internal_free: Self::internal_free,
|
||||
};
|
||||
Some(alloc)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DefaultAllocatorCallback;
|
||||
pub struct TestAlloc;
|
||||
|
||||
impl VkAllocation for TestAlloc {
|
||||
unsafe extern "system" fn allocation(
|
||||
_: *mut (),
|
||||
_: usize,
|
||||
_: usize,
|
||||
_: vk::SystemAllocationScope,
|
||||
) -> *mut () {
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
unsafe extern "system" fn reallocation(
|
||||
_: *mut c_void,
|
||||
_: *mut c_void,
|
||||
_: usize,
|
||||
_: usize,
|
||||
_: vk::SystemAllocationScope,
|
||||
) -> *mut c_void {
|
||||
ptr::null_mut()
|
||||
}
|
||||
unsafe extern "system" fn free(_: *mut c_void, _: *mut c_void) {}
|
||||
unsafe extern "system" fn internal_allocation(
|
||||
_: *mut c_void,
|
||||
_: usize,
|
||||
_: vk::InternalAllocationType,
|
||||
_: vk::SystemAllocationScope,
|
||||
) {
|
||||
}
|
||||
unsafe extern "system" fn internal_free(
|
||||
_: *mut c_void,
|
||||
_: usize,
|
||||
_: vk::InternalAllocationType,
|
||||
_: vk::SystemAllocationScope,
|
||||
) {
|
||||
}
|
||||
}
|
||||
impl VkAllocation for DefaultAllocatorCallback {
|
||||
unsafe extern "system" fn allocation(
|
||||
_: *mut (),
|
||||
_: usize,
|
||||
_: usize,
|
||||
_: vk::SystemAllocationScope,
|
||||
) -> *mut () {
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
unsafe extern "system" fn reallocation(
|
||||
_: *mut c_void,
|
||||
_: *mut c_void,
|
||||
_: usize,
|
||||
_: usize,
|
||||
_: vk::SystemAllocationScope,
|
||||
) -> *mut c_void {
|
||||
ptr::null_mut()
|
||||
}
|
||||
unsafe extern "system" fn free(_: *mut c_void, _: *mut c_void) {}
|
||||
unsafe extern "system" fn internal_allocation(
|
||||
_: *mut c_void,
|
||||
_: usize,
|
||||
_: vk::InternalAllocationType,
|
||||
_: vk::SystemAllocationScope,
|
||||
) {
|
||||
}
|
||||
unsafe extern "system" fn internal_free(
|
||||
_: *mut c_void,
|
||||
_: usize,
|
||||
_: vk::InternalAllocationType,
|
||||
_: vk::SystemAllocationScope,
|
||||
) {
|
||||
}
|
||||
fn create_allocation_callback() -> Option<vk::AllocationCallbacks> {
|
||||
None
|
||||
}
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,281 @@
|
|||
use instance::Instance;
|
||||
use prelude::*;
|
||||
use shared_library::dynamic_library::DynamicLibrary;
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use std::mem;
|
||||
use std::os::raw::c_char;
|
||||
use std::os::raw::c_void;
|
||||
use std::path::Path;
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
use vk;
|
||||
use RawPtr;
|
||||
|
||||
#[cfg(windows)]
|
||||
const LIB_PATH: &'static str = "vulkan-1.dll";
|
||||
|
||||
#[cfg(all(
|
||||
unix,
|
||||
not(any(target_os = "macos", target_os = "ios", target_os = "android"))
|
||||
))]
|
||||
const LIB_PATH: &'static str = "libvulkan.so.1";
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
const LIB_PATH: &'static str = "libvulkan.so";
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
const LIB_PATH: &'static str = "libvulkan.dylib";
|
||||
|
||||
/// Function loader
|
||||
pub type Entry = EntryCustom<Arc<DynamicLibrary>>;
|
||||
|
||||
/// Function loader
|
||||
#[derive(Clone)]
|
||||
pub struct EntryCustom<L> {
|
||||
static_fn: vk::StaticFn,
|
||||
entry_fn_1_0: vk::EntryFnV1_0,
|
||||
entry_fn_1_1: vk::EntryFnV1_1,
|
||||
lib: L,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum LoadingError {
|
||||
LibraryLoadError(String),
|
||||
}
|
||||
|
||||
impl fmt::Display for LoadingError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
LoadingError::LibraryLoadError(e) => write!(f, "{}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for LoadingError {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum InstanceError {
|
||||
LoadError(Vec<&'static str>),
|
||||
VkError(vk::Result),
|
||||
}
|
||||
|
||||
impl fmt::Display for InstanceError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
InstanceError::LoadError(e) => write!(f, "{}", e.join("; ")),
|
||||
InstanceError::VkError(e) => write!(f, "{}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for InstanceError {}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub trait EntryV1_0 {
|
||||
type Instance;
|
||||
fn fp_v1_0(&self) -> &vk::EntryFnV1_0;
|
||||
fn static_fn(&self) -> &vk::StaticFn;
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkCreateInstance.html>"]
|
||||
unsafe fn create_instance(
|
||||
&self,
|
||||
create_info: &vk::InstanceCreateInfo,
|
||||
allocation_callbacks: Option<&vk::AllocationCallbacks>,
|
||||
) -> Result<Self::Instance, InstanceError>;
|
||||
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkEnumerateInstanceLayerProperties.html>"]
|
||||
fn enumerate_instance_layer_properties(&self) -> VkResult<Vec<vk::LayerProperties>> {
|
||||
unsafe {
|
||||
let mut num = 0;
|
||||
self.fp_v1_0()
|
||||
.enumerate_instance_layer_properties(&mut num, ptr::null_mut());
|
||||
|
||||
let mut v = Vec::with_capacity(num as usize);
|
||||
let err_code = self
|
||||
.fp_v1_0()
|
||||
.enumerate_instance_layer_properties(&mut num, v.as_mut_ptr());
|
||||
v.set_len(num as usize);
|
||||
match err_code {
|
||||
vk::Result::SUCCESS => Ok(v),
|
||||
_ => Err(err_code),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkEnumerateInstanceExtensionProperties.html>"]
|
||||
fn enumerate_instance_extension_properties(&self) -> VkResult<Vec<vk::ExtensionProperties>> {
|
||||
unsafe {
|
||||
let mut num = 0;
|
||||
self.fp_v1_0().enumerate_instance_extension_properties(
|
||||
ptr::null(),
|
||||
&mut num,
|
||||
ptr::null_mut(),
|
||||
);
|
||||
let mut data = Vec::with_capacity(num as usize);
|
||||
let err_code = self.fp_v1_0().enumerate_instance_extension_properties(
|
||||
ptr::null(),
|
||||
&mut num,
|
||||
data.as_mut_ptr(),
|
||||
);
|
||||
data.set_len(num as usize);
|
||||
match err_code {
|
||||
vk::Result::SUCCESS => Ok(data),
|
||||
_ => Err(err_code),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkGetInstanceProcAddr.html>"]
|
||||
fn get_instance_proc_addr(
|
||||
&self,
|
||||
instance: vk::Instance,
|
||||
p_name: *const c_char,
|
||||
) -> vk::PFN_vkVoidFunction {
|
||||
unsafe { self.static_fn().get_instance_proc_addr(instance, p_name) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<L> EntryV1_0 for EntryCustom<L> {
|
||||
type Instance = Instance;
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkCreateInstance.html>"]
|
||||
unsafe fn create_instance(
|
||||
&self,
|
||||
create_info: &vk::InstanceCreateInfo,
|
||||
allocation_callbacks: Option<&vk::AllocationCallbacks>,
|
||||
) -> Result<Self::Instance, InstanceError> {
|
||||
let mut instance: vk::Instance = mem::uninitialized();
|
||||
let err_code = self.fp_v1_0().create_instance(
|
||||
create_info,
|
||||
allocation_callbacks.as_raw_ptr(),
|
||||
&mut instance,
|
||||
);
|
||||
if err_code != vk::Result::SUCCESS {
|
||||
return Err(InstanceError::VkError(err_code));
|
||||
}
|
||||
Ok(Instance::load(&self.static_fn, instance))
|
||||
}
|
||||
fn fp_v1_0(&self) -> &vk::EntryFnV1_0 {
|
||||
&self.entry_fn_1_0
|
||||
}
|
||||
fn static_fn(&self) -> &vk::StaticFn {
|
||||
&self.static_fn
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub trait EntryV1_1: EntryV1_0 {
|
||||
fn fp_v1_1(&self) -> &vk::EntryFnV1_1;
|
||||
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkEnumerateInstanceVersion.html>"]
|
||||
fn enumerate_instance_version(&self) -> VkResult<u32> {
|
||||
unsafe {
|
||||
let mut api_version = 0;
|
||||
let err_code = self.fp_v1_1().enumerate_instance_version(&mut api_version);
|
||||
match err_code {
|
||||
vk::Result::SUCCESS => Ok(api_version),
|
||||
_ => Err(err_code),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EntryCustom<Arc<DynamicLibrary>> {
|
||||
/// ```rust,no_run
|
||||
/// # #[macro_use]
|
||||
/// # extern crate ash;
|
||||
/// use ash::{vk, Entry, version::EntryV1_0};
|
||||
/// # fn main() -> Result<(), Box<std::error::Error>> {
|
||||
/// let entry = Entry::new()?;
|
||||
/// let app_info = vk::ApplicationInfo {
|
||||
/// api_version: vk_make_version!(1, 0, 0),
|
||||
/// ..Default::default()
|
||||
/// };
|
||||
/// let create_info = vk::InstanceCreateInfo {
|
||||
/// p_application_info: &app_info,
|
||||
/// ..Default::default()
|
||||
/// };
|
||||
/// let instance = unsafe { entry.create_instance(&create_info, None)? };
|
||||
/// # Ok(()) }
|
||||
/// ```
|
||||
pub fn new() -> Result<Entry, LoadingError> {
|
||||
Self::new_custom(
|
||||
|| {
|
||||
DynamicLibrary::open(Some(&Path::new(LIB_PATH)))
|
||||
.map_err(|err| LoadingError::LibraryLoadError(err.clone()))
|
||||
.map(|dl| Arc::new(dl))
|
||||
},
|
||||
|vk_lib, name| unsafe {
|
||||
vk_lib
|
||||
.symbol(&*name.to_string_lossy())
|
||||
.unwrap_or(ptr::null_mut())
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<L> EntryCustom<L> {
|
||||
pub fn new_custom<Open, Load>(open: Open, mut load: Load) -> Result<Self, LoadingError>
|
||||
where
|
||||
Open: FnOnce() -> Result<L, LoadingError>,
|
||||
Load: FnMut(&mut L, &::std::ffi::CStr) -> *const c_void,
|
||||
{
|
||||
let mut lib = open()?;
|
||||
let static_fn = vk::StaticFn::load(|name| load(&mut lib, name));
|
||||
|
||||
let entry_fn_1_0 = vk::EntryFnV1_0::load(|name| unsafe {
|
||||
mem::transmute(static_fn.get_instance_proc_addr(vk::Instance::null(), name.as_ptr()))
|
||||
});
|
||||
|
||||
let entry_fn_1_1 = vk::EntryFnV1_1::load(|name| unsafe {
|
||||
mem::transmute(static_fn.get_instance_proc_addr(vk::Instance::null(), name.as_ptr()))
|
||||
});
|
||||
|
||||
Ok(EntryCustom {
|
||||
static_fn,
|
||||
entry_fn_1_0,
|
||||
entry_fn_1_1,
|
||||
lib,
|
||||
})
|
||||
}
|
||||
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkEnumerateInstanceVersion.html>"]
|
||||
/// ```rust,no_run
|
||||
/// # #[macro_use]
|
||||
/// # extern crate ash;
|
||||
/// # use ash::Entry;
|
||||
/// # fn main() -> Result<(), Box<std::error::Error>> {
|
||||
/// let entry = Entry::new()?;
|
||||
/// match entry.try_enumerate_instance_version()? {
|
||||
/// // Vulkan 1.1+
|
||||
/// Some(version) => {
|
||||
/// let major = vk_version_major!(version);
|
||||
/// let minor = vk_version_minor!(version);
|
||||
/// let patch = vk_version_patch!(version);
|
||||
/// },
|
||||
/// // Vulkan 1.0
|
||||
/// None => {},
|
||||
/// }
|
||||
/// # Ok(()) }
|
||||
/// ```
|
||||
pub fn try_enumerate_instance_version(&self) -> VkResult<Option<u32>> {
|
||||
unsafe {
|
||||
let mut api_version = 0;
|
||||
let enumerate_instance_version: Option<vk::PFN_vkEnumerateInstanceVersion> = {
|
||||
let name = b"vkEnumerateInstanceVersion\0".as_ptr() as *const _;
|
||||
mem::transmute(
|
||||
self.static_fn()
|
||||
.get_instance_proc_addr(vk::Instance::null(), name),
|
||||
)
|
||||
};
|
||||
if let Some(enumerate_instance_version) = enumerate_instance_version {
|
||||
let err_code = (enumerate_instance_version)(&mut api_version);
|
||||
match err_code {
|
||||
vk::Result::SUCCESS => Ok(Some(api_version)),
|
||||
_ => Err(err_code),
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,701 @@
|
|||
/*
|
||||
***********************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2014-2019 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
|
||||
use std::fmt;
|
||||
use std::os::raw::*;
|
||||
use vk::*;
|
||||
|
||||
// Extension: `VK_AMD_gpa_interface`
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct GpaSqShaderStageFlags(pub(crate) Flags);
|
||||
vk_bitflags_wrapped!(
|
||||
GpaSqShaderStageFlags,
|
||||
0b1111111111111111111111111111111,
|
||||
Flags
|
||||
);
|
||||
impl fmt::Debug for GpaSqShaderStageFlags {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
const KNOWN: &[(Flags, &str)] = &[
|
||||
(GpaSqShaderStageFlags::PS.0, "PS"),
|
||||
(GpaSqShaderStageFlags::VS.0, "VS"),
|
||||
(GpaSqShaderStageFlags::GS.0, "GS"),
|
||||
(GpaSqShaderStageFlags::ES.0, "ES"),
|
||||
(GpaSqShaderStageFlags::HS.0, "HS"),
|
||||
(GpaSqShaderStageFlags::LS.0, "LS"),
|
||||
(GpaSqShaderStageFlags::CS.0, "CS"),
|
||||
];
|
||||
debug_flags(f, KNOWN, self.0)
|
||||
}
|
||||
}
|
||||
impl GpaSqShaderStageFlags {
|
||||
pub const PS: Self = GpaSqShaderStageFlags(0b1);
|
||||
pub const VS: Self = GpaSqShaderStageFlags(0b10);
|
||||
pub const GS: Self = GpaSqShaderStageFlags(0b100);
|
||||
pub const ES: Self = GpaSqShaderStageFlags(0b1000);
|
||||
pub const HS: Self = GpaSqShaderStageFlags(0b10000);
|
||||
pub const LS: Self = GpaSqShaderStageFlags(0b100000);
|
||||
pub const CS: Self = GpaSqShaderStageFlags(0b1000000);
|
||||
}
|
||||
|
||||
impl StructureType {
|
||||
pub const PHYSICAL_DEVICE_GPA_FEATURES_AMD: Self = StructureType(1000133000);
|
||||
pub const PHYSICAL_DEVICE_GPA_PROPERTIES_AMD: Self = StructureType(1000133001);
|
||||
pub const GPA_SAMPLE_BEGIN_INFO_AMD: Self = StructureType(1000133002);
|
||||
pub const GPA_SESSION_CREATE_INFO_AMD: Self = StructureType(1000133003);
|
||||
pub const GPA_DEVICE_CLOCK_MODE_INFO_AMD: Self = StructureType(1000133004);
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||
#[repr(transparent)]
|
||||
pub struct GpaDeviceClockModeAmd(pub(crate) i32);
|
||||
impl GpaDeviceClockModeAmd {
|
||||
pub fn from_raw(x: i32) -> Self {
|
||||
GpaDeviceClockModeAmd(x)
|
||||
}
|
||||
pub fn as_raw(self) -> i32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
impl GpaDeviceClockModeAmd {
|
||||
pub const DEFAULT: Self = GpaDeviceClockModeAmd(0);
|
||||
pub const QUERY: Self = GpaDeviceClockModeAmd(1);
|
||||
pub const PROFILING: Self = GpaDeviceClockModeAmd(2);
|
||||
pub const MIN_MEMORY: Self = GpaDeviceClockModeAmd(3);
|
||||
pub const MIN_ENGINE: Self = GpaDeviceClockModeAmd(4);
|
||||
pub const PEAK: Self = GpaDeviceClockModeAmd(5);
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||
#[repr(transparent)]
|
||||
pub struct GpaPerfBlockAmd(pub(crate) i32);
|
||||
impl GpaPerfBlockAmd {
|
||||
pub fn from_raw(x: i32) -> Self {
|
||||
GpaPerfBlockAmd(x)
|
||||
}
|
||||
pub fn as_raw(self) -> i32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
impl GpaPerfBlockAmd {
|
||||
pub const CPF: Self = GpaPerfBlockAmd(0);
|
||||
pub const IA: Self = GpaPerfBlockAmd(1);
|
||||
pub const VGT: Self = GpaPerfBlockAmd(2);
|
||||
pub const PA: Self = GpaPerfBlockAmd(3);
|
||||
pub const SC: Self = GpaPerfBlockAmd(4);
|
||||
pub const SPI: Self = GpaPerfBlockAmd(5);
|
||||
pub const SQ: Self = GpaPerfBlockAmd(6);
|
||||
pub const SX: Self = GpaPerfBlockAmd(7);
|
||||
pub const TA: Self = GpaPerfBlockAmd(8);
|
||||
pub const TD: Self = GpaPerfBlockAmd(9);
|
||||
pub const TCP: Self = GpaPerfBlockAmd(10);
|
||||
pub const TCC: Self = GpaPerfBlockAmd(11);
|
||||
pub const TCA: Self = GpaPerfBlockAmd(12);
|
||||
pub const DB: Self = GpaPerfBlockAmd(13);
|
||||
pub const CB: Self = GpaPerfBlockAmd(14);
|
||||
pub const GDS: Self = GpaPerfBlockAmd(15);
|
||||
pub const SRBM: Self = GpaPerfBlockAmd(16);
|
||||
pub const GRBM: Self = GpaPerfBlockAmd(17);
|
||||
pub const GRBM_SE: Self = GpaPerfBlockAmd(18);
|
||||
pub const RLC: Self = GpaPerfBlockAmd(19);
|
||||
pub const DMA: Self = GpaPerfBlockAmd(20);
|
||||
pub const MC: Self = GpaPerfBlockAmd(21);
|
||||
pub const CPG: Self = GpaPerfBlockAmd(22);
|
||||
pub const CPC: Self = GpaPerfBlockAmd(23);
|
||||
pub const WD: Self = GpaPerfBlockAmd(24);
|
||||
pub const TCS: Self = GpaPerfBlockAmd(25);
|
||||
pub const ATC: Self = GpaPerfBlockAmd(26);
|
||||
pub const ATC_L2: Self = GpaPerfBlockAmd(27);
|
||||
pub const MC_VM_L2: Self = GpaPerfBlockAmd(28);
|
||||
pub const EA: Self = GpaPerfBlockAmd(29);
|
||||
pub const RPB: Self = GpaPerfBlockAmd(30);
|
||||
pub const RMI: Self = GpaPerfBlockAmd(31);
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||
#[repr(transparent)]
|
||||
pub struct GpaSampleTypeAmd(pub(crate) i32);
|
||||
impl GpaSampleTypeAmd {
|
||||
pub fn from_raw(x: i32) -> Self {
|
||||
GpaSampleTypeAmd(x)
|
||||
}
|
||||
pub fn as_raw(self) -> i32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
impl GpaSampleTypeAmd {
|
||||
pub const CUMULATIVE: Self = GpaSampleTypeAmd(0);
|
||||
pub const TRACE: Self = GpaSampleTypeAmd(1);
|
||||
pub const TIMING: Self = GpaSampleTypeAmd(2);
|
||||
}
|
||||
|
||||
handle_nondispatchable!(GpaSessionAmd, UNKNOWN);
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct GpaSessionCreateInfoAmd {
|
||||
pub s_type: StructureType,
|
||||
pub p_next: *const c_void,
|
||||
pub secondary_copy_source: GpaSessionAmd,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct GpaPerfBlockPropertiesAmd {
|
||||
pub block_type: GpaPerfBlockAmd,
|
||||
pub flags: Flags,
|
||||
pub instance_count: u32,
|
||||
pub max_event_id: u32,
|
||||
pub max_global_only_counters: u32,
|
||||
pub max_global_shared_counters: u32,
|
||||
pub max_streaming_counters: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct PhysicalDeviceGpaFeaturesAmd {
|
||||
pub s_type: StructureType,
|
||||
pub p_next: *const c_void,
|
||||
pub perf_counters: Bool32,
|
||||
pub streaming_perf_counters: Bool32,
|
||||
pub sq_thread_tracing: Bool32,
|
||||
pub clock_modes: Bool32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct PhysicalDeviceGpaPropertiesAmd {
|
||||
pub s_type: StructureType,
|
||||
pub p_next: *const c_void,
|
||||
pub flags: Flags,
|
||||
pub max_sqtt_se_buffer_size: DeviceSize,
|
||||
pub shader_engine_count: u32,
|
||||
pub perf_block_count: u32,
|
||||
pub p_perf_block_properties: *mut GpaPerfBlockPropertiesAmd,
|
||||
}
|
||||
|
||||
impl ::std::default::Default for PhysicalDeviceGpaPropertiesAmd {
|
||||
fn default() -> PhysicalDeviceGpaPropertiesAmd {
|
||||
PhysicalDeviceGpaPropertiesAmd {
|
||||
s_type: StructureType::PHYSICAL_DEVICE_GPA_PROPERTIES_AMD,
|
||||
p_next: ::std::ptr::null_mut(),
|
||||
flags: Flags::default(),
|
||||
max_sqtt_se_buffer_size: DeviceSize::default(),
|
||||
shader_engine_count: u32::default(),
|
||||
perf_block_count: u32::default(),
|
||||
p_perf_block_properties: ::std::ptr::null_mut(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl PhysicalDeviceGpaPropertiesAmd {
|
||||
pub fn builder<'a>() -> PhysicalDeviceGpaPropertiesAmdBuilder<'a> {
|
||||
PhysicalDeviceGpaPropertiesAmdBuilder {
|
||||
inner: PhysicalDeviceGpaPropertiesAmd::default(),
|
||||
marker: ::std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
pub struct PhysicalDeviceGpaPropertiesAmdBuilder<'a> {
|
||||
inner: PhysicalDeviceGpaPropertiesAmd,
|
||||
marker: ::std::marker::PhantomData<&'a ()>,
|
||||
}
|
||||
pub unsafe trait ExtendsPhysicalDeviceGpaPropertiesAmd {}
|
||||
unsafe impl ExtendsPhysicalDeviceProperties2 for PhysicalDeviceGpaPropertiesAmd {}
|
||||
impl<'a> ::std::ops::Deref for PhysicalDeviceGpaPropertiesAmdBuilder<'a> {
|
||||
type Target = PhysicalDeviceGpaPropertiesAmd;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
impl<'a> PhysicalDeviceGpaPropertiesAmdBuilder<'a> {
|
||||
pub fn next<T>(mut self, next: &'a mut T) -> PhysicalDeviceGpaPropertiesAmdBuilder<'a>
|
||||
where
|
||||
T: ExtendsPhysicalDeviceGpaPropertiesAmd,
|
||||
{
|
||||
self.inner.p_next = next as *mut T as *mut c_void;
|
||||
self
|
||||
}
|
||||
pub fn build(self) -> PhysicalDeviceGpaPropertiesAmd {
|
||||
self.inner
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct GpaPerfCounterAmd {
|
||||
pub block_type: GpaPerfBlockAmd,
|
||||
pub block_instance: u32,
|
||||
pub event_id: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct GpaSampleBeginInfoAmd {
|
||||
pub s_type: StructureType,
|
||||
pub p_next: *const c_void,
|
||||
pub sample_type: GpaSampleTypeAmd,
|
||||
pub sample_internal_operations: Bool32,
|
||||
pub cache_flush_on_counter_collection: Bool32,
|
||||
pub sq_shader_mask_enable: Bool32,
|
||||
pub sq_shader_mask: GpaSqShaderStageFlags,
|
||||
pub perf_counter_count: u32,
|
||||
pub p_perf_counters: *const GpaPerfCounterAmd,
|
||||
pub streaming_perf_trace_sample_interval: u32,
|
||||
pub perf_counter_device_memory_limit: DeviceSize,
|
||||
pub sq_thread_trace_enable: Bool32,
|
||||
pub sq_thread_trace_suppress_instruction_tokens: Bool32,
|
||||
pub sq_thread_trace_device_memory_limit: DeviceSize,
|
||||
pub timing_pre_sample: PipelineStageFlags,
|
||||
pub timing_post_sample: PipelineStageFlags,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct GpaDeviceClockModeInfoAmd {
|
||||
pub s_type: StructureType,
|
||||
pub p_next: *const c_void,
|
||||
pub clock_mode: GpaDeviceClockModeAmd,
|
||||
pub memory_clock_ratio_to_peak: f32,
|
||||
pub engine_clock_ratio_to_peak: f32,
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type PFN_vkCreateGpaSessionAMD = extern "system" fn(
|
||||
device: Device,
|
||||
p_create_info: *const GpaSessionCreateInfoAmd,
|
||||
p_allocator: *const AllocationCallbacks,
|
||||
p_gpa_session: *mut GpaSessionAmd,
|
||||
) -> Result;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type PFN_vkDestroyGpaSessionAMD = extern "system" fn(
|
||||
device: Device,
|
||||
gpa_session: GpaSessionAmd,
|
||||
p_allocator: *const AllocationCallbacks,
|
||||
) -> c_void;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type PFN_vkSetGpaDeviceClockModeAMD =
|
||||
extern "system" fn(device: Device, p_info: *mut GpaDeviceClockModeInfoAmd) -> Result;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type PFN_vkCmdBeginGpaSessionAMD =
|
||||
extern "system" fn(commandBuffer: CommandBuffer, gpa_session: GpaSessionAmd) -> Result;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type PFN_vkCmdEndGpaSessionAMD =
|
||||
extern "system" fn(commandBuffer: CommandBuffer, gpa_session: GpaSessionAmd) -> Result;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type PFN_vkCmdBeginGpaSampleAMD = extern "system" fn(
|
||||
commandBuffer: CommandBuffer,
|
||||
gpa_session: GpaSessionAmd,
|
||||
p_gpa_sample_begin_info: *const GpaSampleBeginInfoAmd,
|
||||
p_sample_id: *mut u32,
|
||||
) -> Result;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type PFN_vkCmdEndGpaSampleAMD = extern "system" fn(
|
||||
commandBuffer: CommandBuffer,
|
||||
gpa_session: GpaSessionAmd,
|
||||
sample_id: u32,
|
||||
) -> c_void;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type PFN_vkGetGpaSessionStatusAMD =
|
||||
extern "system" fn(device: Device, gpaSession: GpaSessionAmd) -> Result;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type PFN_vkGetGpaSessionResultsAMD = extern "system" fn(
|
||||
device: Device,
|
||||
gpaSession: GpaSessionAmd,
|
||||
sample_id: u32,
|
||||
p_size_in_bytes: *mut usize,
|
||||
p_data: *mut c_void,
|
||||
) -> Result;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type PFN_vkResetGpaSessionAMD =
|
||||
extern "system" fn(device: Device, gpaSession: GpaSessionAmd) -> Result;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type PFN_vkCmdCopyGpaSessionResultsAMD =
|
||||
extern "system" fn(commandBuffer: CommandBuffer, gpaSession: GpaSessionAmd) -> c_void;
|
||||
|
||||
pub struct AmdGpaInterfaceFn {
|
||||
pub create_gpa_session: PFN_vkCreateGpaSessionAMD,
|
||||
pub destroy_gpa_session: PFN_vkDestroyGpaSessionAMD,
|
||||
pub set_gpa_device_clock_mode: PFN_vkSetGpaDeviceClockModeAMD,
|
||||
pub cmd_begin_gpa_session: PFN_vkCmdBeginGpaSessionAMD,
|
||||
pub cmd_end_gpa_session: PFN_vkCmdEndGpaSessionAMD,
|
||||
pub cmd_begin_gpa_sample: PFN_vkCmdBeginGpaSampleAMD,
|
||||
pub cmd_end_gpa_sample: PFN_vkCmdEndGpaSampleAMD,
|
||||
pub get_gpa_session_status: PFN_vkGetGpaSessionStatusAMD,
|
||||
pub get_gpa_session_results: PFN_vkGetGpaSessionResultsAMD,
|
||||
pub reset_gpa_session: PFN_vkResetGpaSessionAMD,
|
||||
pub cmd_copy_gpa_session_results: PFN_vkCmdCopyGpaSessionResultsAMD,
|
||||
}
|
||||
unsafe impl Send for AmdGpaInterfaceFn {}
|
||||
unsafe impl Sync for AmdGpaInterfaceFn {}
|
||||
|
||||
impl ::std::clone::Clone for AmdGpaInterfaceFn {
|
||||
fn clone(&self) -> Self {
|
||||
AmdGpaInterfaceFn {
|
||||
create_gpa_session: self.create_gpa_session,
|
||||
destroy_gpa_session: self.destroy_gpa_session,
|
||||
set_gpa_device_clock_mode: self.set_gpa_device_clock_mode,
|
||||
cmd_begin_gpa_session: self.cmd_begin_gpa_session,
|
||||
cmd_end_gpa_session: self.cmd_end_gpa_session,
|
||||
cmd_begin_gpa_sample: self.cmd_begin_gpa_sample,
|
||||
cmd_end_gpa_sample: self.cmd_end_gpa_sample,
|
||||
get_gpa_session_status: self.get_gpa_session_status,
|
||||
get_gpa_session_results: self.get_gpa_session_results,
|
||||
reset_gpa_session: self.reset_gpa_session,
|
||||
cmd_copy_gpa_session_results: self.cmd_copy_gpa_session_results,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AmdGpaInterfaceFn {
|
||||
pub fn load<F>(mut _f: F) -> Self
|
||||
where
|
||||
F: FnMut(&::std::ffi::CStr) -> *const c_void,
|
||||
{
|
||||
AmdGpaInterfaceFn {
|
||||
create_gpa_session: unsafe {
|
||||
extern "system" fn create_gpa_session_amd(
|
||||
_device: Device,
|
||||
_p_create_info: *const GpaSessionCreateInfoAmd,
|
||||
_p_allocator: *const AllocationCallbacks,
|
||||
_p_gpa_session: *mut GpaSessionAmd,
|
||||
) -> Result {
|
||||
panic!(concat!(
|
||||
"Unable to load ",
|
||||
stringify!(create_gpa_session_amd)
|
||||
))
|
||||
}
|
||||
let raw_name = stringify!(vkCreateGpaSessionAMD);
|
||||
let cname = ::std::ffi::CString::new(raw_name).unwrap();
|
||||
let val = _f(&cname);
|
||||
if val.is_null() {
|
||||
create_gpa_session_amd
|
||||
} else {
|
||||
::std::mem::transmute(val)
|
||||
}
|
||||
},
|
||||
destroy_gpa_session: unsafe {
|
||||
extern "system" fn destroy_gpa_session_amd(
|
||||
_device: Device,
|
||||
_gpa_session: GpaSessionAmd,
|
||||
_p_allocator: *const AllocationCallbacks,
|
||||
) -> c_void {
|
||||
panic!(concat!(
|
||||
"Unable to load ",
|
||||
stringify!(destroy_gpa_session_amd)
|
||||
))
|
||||
}
|
||||
let raw_name = stringify!(vkDestroyGpaSessionAMD);
|
||||
let cname = ::std::ffi::CString::new(raw_name).unwrap();
|
||||
let val = _f(&cname);
|
||||
if val.is_null() {
|
||||
destroy_gpa_session_amd
|
||||
} else {
|
||||
::std::mem::transmute(val)
|
||||
}
|
||||
},
|
||||
set_gpa_device_clock_mode: unsafe {
|
||||
extern "system" fn set_gpa_device_clock_mode_amd(
|
||||
_device: Device,
|
||||
_p_info: *mut GpaDeviceClockModeInfoAmd,
|
||||
) -> Result {
|
||||
panic!(concat!(
|
||||
"Unable to load ",
|
||||
stringify!(set_gpa_device_clock_mode_amd)
|
||||
))
|
||||
}
|
||||
let raw_name = stringify!(vkSetGpaDeviceClockModeAMD);
|
||||
let cname = ::std::ffi::CString::new(raw_name).unwrap();
|
||||
let val = _f(&cname);
|
||||
if val.is_null() {
|
||||
set_gpa_device_clock_mode_amd
|
||||
} else {
|
||||
::std::mem::transmute(val)
|
||||
}
|
||||
},
|
||||
cmd_begin_gpa_session: unsafe {
|
||||
extern "system" fn cmd_begin_gpa_session_amd(
|
||||
_command_buffer: CommandBuffer,
|
||||
_gpa_session: GpaSessionAmd,
|
||||
) -> Result {
|
||||
panic!(concat!(
|
||||
"Unable to load ",
|
||||
stringify!(cmd_begin_gpa_session_amd)
|
||||
))
|
||||
}
|
||||
let raw_name = stringify!(vkCmdBeginGpaSessionAMD);
|
||||
let cname = ::std::ffi::CString::new(raw_name).unwrap();
|
||||
let val = _f(&cname);
|
||||
if val.is_null() {
|
||||
cmd_begin_gpa_session_amd
|
||||
} else {
|
||||
::std::mem::transmute(val)
|
||||
}
|
||||
},
|
||||
cmd_end_gpa_session: unsafe {
|
||||
extern "system" fn cmd_end_gpa_session_amd(
|
||||
_command_buffer: CommandBuffer,
|
||||
_gpa_session: GpaSessionAmd,
|
||||
) -> Result {
|
||||
panic!(concat!(
|
||||
"Unable to load ",
|
||||
stringify!(cmd_end_gpa_session_amd)
|
||||
))
|
||||
}
|
||||
let raw_name = stringify!(vkCmdEndGpaSessionAMD);
|
||||
let cname = ::std::ffi::CString::new(raw_name).unwrap();
|
||||
let val = _f(&cname);
|
||||
if val.is_null() {
|
||||
cmd_end_gpa_session_amd
|
||||
} else {
|
||||
::std::mem::transmute(val)
|
||||
}
|
||||
},
|
||||
cmd_begin_gpa_sample: unsafe {
|
||||
extern "system" fn cmd_begin_gpa_sample_amd(
|
||||
_command_buffer: CommandBuffer,
|
||||
_gpa_session: GpaSessionAmd,
|
||||
_p_gpa_sample_begin_info: *const GpaSampleBeginInfoAmd,
|
||||
_p_sample_id: *mut u32,
|
||||
) -> Result {
|
||||
panic!(concat!(
|
||||
"Unable to load ",
|
||||
stringify!(cmd_begin_gpa_sample_amd)
|
||||
))
|
||||
}
|
||||
let raw_name = stringify!(vkCmdBeginGpaSampleAMD);
|
||||
let cname = ::std::ffi::CString::new(raw_name).unwrap();
|
||||
let val = _f(&cname);
|
||||
if val.is_null() {
|
||||
cmd_begin_gpa_sample_amd
|
||||
} else {
|
||||
::std::mem::transmute(val)
|
||||
}
|
||||
},
|
||||
cmd_end_gpa_sample: unsafe {
|
||||
extern "system" fn cmd_end_gpa_sample_amd(
|
||||
_command_buffer: CommandBuffer,
|
||||
_gpa_session: GpaSessionAmd,
|
||||
_sample_id: u32,
|
||||
) -> c_void {
|
||||
panic!(concat!(
|
||||
"Unable to load ",
|
||||
stringify!(cmd_end_gpa_sample_amd)
|
||||
))
|
||||
}
|
||||
let raw_name = stringify!(vkCmdEndGpaSampleAMD);
|
||||
let cname = ::std::ffi::CString::new(raw_name).unwrap();
|
||||
let val = _f(&cname);
|
||||
if val.is_null() {
|
||||
cmd_end_gpa_sample_amd
|
||||
} else {
|
||||
::std::mem::transmute(val)
|
||||
}
|
||||
},
|
||||
get_gpa_session_status: unsafe {
|
||||
extern "system" fn get_gpa_session_status_amd(
|
||||
_device: Device,
|
||||
_gpa_session: GpaSessionAmd,
|
||||
) -> Result {
|
||||
panic!(concat!(
|
||||
"Unable to load ",
|
||||
stringify!(get_gpa_session_status_amd)
|
||||
))
|
||||
}
|
||||
let raw_name = stringify!(vkGetGpaSessionStatusAMD);
|
||||
let cname = ::std::ffi::CString::new(raw_name).unwrap();
|
||||
let val = _f(&cname);
|
||||
if val.is_null() {
|
||||
get_gpa_session_status_amd
|
||||
} else {
|
||||
::std::mem::transmute(val)
|
||||
}
|
||||
},
|
||||
get_gpa_session_results: unsafe {
|
||||
extern "system" fn get_gpa_session_results_amd(
|
||||
_device: Device,
|
||||
_gpa_session: GpaSessionAmd,
|
||||
_sample_id: u32,
|
||||
_p_size_in_bytes: *mut usize,
|
||||
_p_data: *mut c_void,
|
||||
) -> Result {
|
||||
panic!(concat!(
|
||||
"Unable to load ",
|
||||
stringify!(get_gpa_session_results_amd)
|
||||
))
|
||||
}
|
||||
let raw_name = stringify!(vkGetGpaSessionResultsAMD);
|
||||
let cname = ::std::ffi::CString::new(raw_name).unwrap();
|
||||
let val = _f(&cname);
|
||||
if val.is_null() {
|
||||
get_gpa_session_results_amd
|
||||
} else {
|
||||
::std::mem::transmute(val)
|
||||
}
|
||||
},
|
||||
reset_gpa_session: unsafe {
|
||||
extern "system" fn reset_gpa_session_amd(
|
||||
_device: Device,
|
||||
_gpa_session: GpaSessionAmd,
|
||||
) -> Result {
|
||||
panic!(concat!(
|
||||
"Unable to load ",
|
||||
stringify!(reset_gpa_session_amd)
|
||||
))
|
||||
}
|
||||
let raw_name = stringify!(vkCmdEndGpaSampleAMD);
|
||||
let cname = ::std::ffi::CString::new(raw_name).unwrap();
|
||||
let val = _f(&cname);
|
||||
if val.is_null() {
|
||||
reset_gpa_session_amd
|
||||
} else {
|
||||
::std::mem::transmute(val)
|
||||
}
|
||||
},
|
||||
cmd_copy_gpa_session_results: unsafe {
|
||||
extern "system" fn cmd_copy_gpa_session_results_amd(
|
||||
_command_buffer: CommandBuffer,
|
||||
_gpa_session: GpaSessionAmd,
|
||||
) -> c_void {
|
||||
panic!(concat!(
|
||||
"Unable to load ",
|
||||
stringify!(cmd_copy_gpa_session_results_amd)
|
||||
))
|
||||
}
|
||||
let raw_name = stringify!(vkCmdCopyGpaSessionResultsAMD);
|
||||
let cname = ::std::ffi::CString::new(raw_name).unwrap();
|
||||
let val = _f(&cname);
|
||||
if val.is_null() {
|
||||
cmd_copy_gpa_session_results_amd
|
||||
} else {
|
||||
::std::mem::transmute(val)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
pub unsafe fn create_gpa_session(
|
||||
&self,
|
||||
device: Device,
|
||||
create_info: *const GpaSessionCreateInfoAmd,
|
||||
allocator: *const AllocationCallbacks,
|
||||
gpa_session: *mut GpaSessionAmd,
|
||||
) -> Result {
|
||||
(self.create_gpa_session)(device, create_info, allocator, gpa_session)
|
||||
}
|
||||
pub unsafe fn destroy_gpa_session(
|
||||
&self,
|
||||
device: Device,
|
||||
gpa_session: GpaSessionAmd,
|
||||
allocator: *const AllocationCallbacks,
|
||||
) -> c_void {
|
||||
(self.destroy_gpa_session)(device, gpa_session, allocator)
|
||||
}
|
||||
}
|
||||
|
||||
// Extension: `VK_AMD_wave_limits`
|
||||
|
||||
impl StructureType {
|
||||
pub const WAVE_LIMIT_AMD: Self = StructureType(1000045000);
|
||||
pub const PHYSICAL_DEVICE_WAVE_LIMIT_PROPERTIES_AMD: Self = StructureType(1000045001);
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct PhysicalDeviceWaveLimitPropertiesAmd {
|
||||
pub s_type: StructureType,
|
||||
pub p_next: *const c_void,
|
||||
pub cu_count: u32,
|
||||
pub max_waves_per_cu: u32,
|
||||
}
|
||||
|
||||
impl ::std::default::Default for PhysicalDeviceWaveLimitPropertiesAmd {
|
||||
fn default() -> PhysicalDeviceWaveLimitPropertiesAmd {
|
||||
PhysicalDeviceWaveLimitPropertiesAmd {
|
||||
s_type: StructureType::PHYSICAL_DEVICE_WAVE_LIMIT_PROPERTIES_AMD,
|
||||
p_next: ::std::ptr::null_mut(),
|
||||
cu_count: u32::default(),
|
||||
max_waves_per_cu: u32::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl PhysicalDeviceWaveLimitPropertiesAmd {
|
||||
pub fn builder<'a>() -> PhysicalDeviceWaveLimitPropertiesAmdBuilder<'a> {
|
||||
PhysicalDeviceWaveLimitPropertiesAmdBuilder {
|
||||
inner: PhysicalDeviceWaveLimitPropertiesAmd::default(),
|
||||
marker: ::std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
pub struct PhysicalDeviceWaveLimitPropertiesAmdBuilder<'a> {
|
||||
inner: PhysicalDeviceWaveLimitPropertiesAmd,
|
||||
marker: ::std::marker::PhantomData<&'a ()>,
|
||||
}
|
||||
pub unsafe trait ExtendsPhysicalDeviceWaveLimitPropertiesAmd {}
|
||||
unsafe impl ExtendsPhysicalDeviceProperties2 for PhysicalDeviceWaveLimitPropertiesAmd {}
|
||||
impl<'a> ::std::ops::Deref for PhysicalDeviceWaveLimitPropertiesAmdBuilder<'a> {
|
||||
type Target = PhysicalDeviceWaveLimitPropertiesAmd;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
impl<'a> PhysicalDeviceWaveLimitPropertiesAmdBuilder<'a> {
|
||||
pub fn push_next<T>(
|
||||
mut self,
|
||||
next: &'a mut T,
|
||||
) -> PhysicalDeviceWaveLimitPropertiesAmdBuilder<'a>
|
||||
where
|
||||
T: ExtendsPhysicalDeviceWaveLimitPropertiesAmd,
|
||||
{
|
||||
unsafe {
|
||||
let next_ptr = next as *mut T as *mut BaseOutStructure;
|
||||
let last_next = ptr_chain_iter(next).last().unwrap();
|
||||
(*last_next).p_next = self.inner.p_next as _;
|
||||
self.inner.p_next = next_ptr as _;
|
||||
}
|
||||
self
|
||||
}
|
||||
pub fn build(self) -> PhysicalDeviceWaveLimitPropertiesAmd {
|
||||
self.inner
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct PipelineShaderStageCreateInfoWaveLimitAmd {
|
||||
pub s_type: StructureType,
|
||||
pub p_next: *const c_void,
|
||||
pub waves_per_cu: f32,
|
||||
pub cu_enable_mask: *mut u32,
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
pub mod amd;
|
|
@ -0,0 +1,67 @@
|
|||
#![allow(dead_code)]
|
||||
use prelude::*;
|
||||
use std::ffi::CStr;
|
||||
use std::mem;
|
||||
use version::{DeviceV1_0, InstanceV1_0};
|
||||
use vk;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DebugMarker {
|
||||
debug_marker_fn: vk::ExtDebugMarkerFn,
|
||||
}
|
||||
|
||||
impl DebugMarker {
|
||||
pub fn new<I: InstanceV1_0, D: DeviceV1_0>(instance: &I, device: &D) -> DebugMarker {
|
||||
let debug_marker_fn = vk::ExtDebugMarkerFn::load(|name| unsafe {
|
||||
mem::transmute(instance.get_device_proc_addr(device.handle(), name.as_ptr()))
|
||||
});
|
||||
DebugMarker {
|
||||
debug_marker_fn: debug_marker_fn,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name() -> &'static CStr {
|
||||
vk::ExtDebugMarkerFn::name()
|
||||
}
|
||||
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkDebugMarkerSetObjectNameEXT.html>"]
|
||||
pub unsafe fn debug_marker_set_object_name(
|
||||
&self,
|
||||
device: vk::Device,
|
||||
name_info: &vk::DebugMarkerObjectNameInfoEXT,
|
||||
) -> VkResult<()> {
|
||||
let err_code = self
|
||||
.debug_marker_fn
|
||||
.debug_marker_set_object_name_ext(device, name_info);
|
||||
match err_code {
|
||||
vk::Result::SUCCESS => Ok(()),
|
||||
_ => Err(err_code),
|
||||
}
|
||||
}
|
||||
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkCmdDebugMarkerBeginEXT.html>"]
|
||||
pub unsafe fn cmd_debug_marker_begin(
|
||||
&self,
|
||||
command_buffer: vk::CommandBuffer,
|
||||
marker_info: &vk::DebugMarkerMarkerInfoEXT,
|
||||
) {
|
||||
self.debug_marker_fn
|
||||
.cmd_debug_marker_begin_ext(command_buffer, marker_info);
|
||||
}
|
||||
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkCmdDebugMarkerEndEXT.html>"]
|
||||
pub unsafe fn cmd_debug_marker_end(&self, command_buffer: vk::CommandBuffer) {
|
||||
self.debug_marker_fn
|
||||
.cmd_debug_marker_end_ext(command_buffer);
|
||||
}
|
||||
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkCmdDebugMarkerInsertEXT.html>"]
|
||||
pub unsafe fn cmd_debug_marker_insert(
|
||||
&self,
|
||||
command_buffer: vk::CommandBuffer,
|
||||
marker_info: &vk::DebugMarkerMarkerInfoEXT,
|
||||
) {
|
||||
self.debug_marker_fn
|
||||
.cmd_debug_marker_insert_ext(command_buffer, marker_info);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
#![allow(dead_code)]
|
||||
use prelude::*;
|
||||
use std::ffi::CStr;
|
||||
use std::mem;
|
||||
use version::{EntryV1_0, InstanceV1_0};
|
||||
use vk;
|
||||
use RawPtr;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DebugReport {
|
||||
handle: vk::Instance,
|
||||
debug_report_fn: vk::ExtDebugReportFn,
|
||||
}
|
||||
|
||||
impl DebugReport {
|
||||
pub fn new<E: EntryV1_0, I: InstanceV1_0>(entry: &E, instance: &I) -> DebugReport {
|
||||
let debug_report_fn = vk::ExtDebugReportFn::load(|name| unsafe {
|
||||
mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr()))
|
||||
});
|
||||
DebugReport {
|
||||
handle: instance.handle(),
|
||||
debug_report_fn,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name() -> &'static CStr {
|
||||
vk::ExtDebugReportFn::name()
|
||||
}
|
||||
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkDestroyDebugReportCallbackEXT.html>"]
|
||||
pub unsafe fn destroy_debug_report_callback(
|
||||
&self,
|
||||
debug: vk::DebugReportCallbackEXT,
|
||||
allocation_callbacks: Option<&vk::AllocationCallbacks>,
|
||||
) {
|
||||
self.debug_report_fn.destroy_debug_report_callback_ext(
|
||||
self.handle,
|
||||
debug,
|
||||
allocation_callbacks.as_raw_ptr(),
|
||||
);
|
||||
}
|
||||
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkCreateDebugReportCallbackEXT.html>"]
|
||||
pub unsafe fn create_debug_report_callback(
|
||||
&self,
|
||||
create_info: &vk::DebugReportCallbackCreateInfoEXT,
|
||||
allocation_callbacks: Option<&vk::AllocationCallbacks>,
|
||||
) -> VkResult<vk::DebugReportCallbackEXT> {
|
||||
let mut debug_cb = mem::uninitialized();
|
||||
let err_code = self.debug_report_fn.create_debug_report_callback_ext(
|
||||
self.handle,
|
||||
create_info,
|
||||
allocation_callbacks.as_raw_ptr(),
|
||||
&mut debug_cb,
|
||||
);
|
||||
match err_code {
|
||||
vk::Result::SUCCESS => Ok(debug_cb),
|
||||
_ => Err(err_code),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
#![allow(dead_code)]
|
||||
use prelude::*;
|
||||
use std::ffi::CStr;
|
||||
use std::mem;
|
||||
use version::{EntryV1_0, InstanceV1_0};
|
||||
use {vk, RawPtr};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DebugUtils {
|
||||
handle: vk::Instance,
|
||||
debug_utils_fn: vk::ExtDebugUtilsFn,
|
||||
}
|
||||
|
||||
impl DebugUtils {
|
||||
pub fn new<E: EntryV1_0, I: InstanceV1_0>(entry: &E, instance: &I) -> DebugUtils {
|
||||
let debug_utils_fn = vk::ExtDebugUtilsFn::load(|name| unsafe {
|
||||
mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr()))
|
||||
});
|
||||
DebugUtils {
|
||||
handle: instance.handle(),
|
||||
debug_utils_fn,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name() -> &'static CStr {
|
||||
vk::ExtDebugUtilsFn::name()
|
||||
}
|
||||
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkSetDebugUtilsObjectNameEXT.html>"]
|
||||
pub unsafe fn debug_utils_set_object_name(
|
||||
&self,
|
||||
device: vk::Device,
|
||||
name_info: &vk::DebugUtilsObjectNameInfoEXT,
|
||||
) -> VkResult<()> {
|
||||
let err_code = self
|
||||
.debug_utils_fn
|
||||
.set_debug_utils_object_name_ext(device, name_info);
|
||||
match err_code {
|
||||
vk::Result::SUCCESS => Ok(()),
|
||||
_ => Err(err_code),
|
||||
}
|
||||
}
|
||||
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkSetDebugUtilsObjectTagEXT.html>"]
|
||||
pub unsafe fn debug_utils_set_object_tag(
|
||||
&self,
|
||||
device: vk::Device,
|
||||
tag_info: &vk::DebugUtilsObjectTagInfoEXT,
|
||||
) -> VkResult<()> {
|
||||
let err_code = self
|
||||
.debug_utils_fn
|
||||
.set_debug_utils_object_tag_ext(device, tag_info);
|
||||
match err_code {
|
||||
vk::Result::SUCCESS => Ok(()),
|
||||
_ => Err(err_code),
|
||||
}
|
||||
}
|
||||
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkCmdBeginDebugUtilsLabelEXT.html>"]
|
||||
pub unsafe fn cmd_begin_debug_utils_label(
|
||||
&self,
|
||||
command_buffer: vk::CommandBuffer,
|
||||
label: &vk::DebugUtilsLabelEXT,
|
||||
) {
|
||||
self.debug_utils_fn
|
||||
.cmd_begin_debug_utils_label_ext(command_buffer, label);
|
||||
}
|
||||
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkCmdEndDebugUtilsLabelEXT.html>"]
|
||||
pub unsafe fn cmd_end_debug_utils_label(&self, command_buffer: vk::CommandBuffer) {
|
||||
self.debug_utils_fn
|
||||
.cmd_end_debug_utils_label_ext(command_buffer);
|
||||
}
|
||||
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkCmdInsertDebugUtilsLabelEXT.html>"]
|
||||
pub unsafe fn cmd_insert_debug_utils_label(
|
||||
&self,
|
||||
command_buffer: vk::CommandBuffer,
|
||||
label: &vk::DebugUtilsLabelEXT,
|
||||
) {
|
||||
self.debug_utils_fn
|
||||
.cmd_insert_debug_utils_label_ext(command_buffer, label);
|
||||
}
|
||||
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkQueueBeginDebugUtilsLabelEXT.html>"]
|
||||
pub unsafe fn queue_begin_debug_utils_label(
|
||||
&self,
|
||||
queue: vk::Queue,
|
||||
label: &vk::DebugUtilsLabelEXT,
|
||||
) {
|
||||
self.debug_utils_fn
|
||||
.queue_begin_debug_utils_label_ext(queue, label);
|
||||
}
|
||||
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkQueueEndDebugUtilsLabelEXT.html>"]
|
||||
pub unsafe fn queue_end_debug_utils_label(&self, queue: vk::Queue) {
|
||||
self.debug_utils_fn.queue_end_debug_utils_label_ext(queue);
|
||||
}
|
||||
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkQueueInsertDebugUtilsLabelEXT.html>"]
|
||||
pub unsafe fn queue_insert_debug_utils_label(
|
||||
&self,
|
||||
queue: vk::Queue,
|
||||
label: &vk::DebugUtilsLabelEXT,
|
||||
) {
|
||||
self.debug_utils_fn
|
||||
.queue_insert_debug_utils_label_ext(queue, label);
|
||||
}
|
||||
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkCreateDebugUtilsMessengerEXT.html>"]
|
||||
pub unsafe fn create_debug_utils_messenger(
|
||||
&self,
|
||||
create_info: &vk::DebugUtilsMessengerCreateInfoEXT,
|
||||
allocator: Option<&vk::AllocationCallbacks>,
|
||||
) -> VkResult<vk::DebugUtilsMessengerEXT> {
|
||||
let mut messenger = mem::uninitialized();
|
||||
let err_code = self.debug_utils_fn.create_debug_utils_messenger_ext(
|
||||
self.handle,
|
||||
create_info,
|
||||
allocator.as_raw_ptr(),
|
||||
&mut messenger,
|
||||
);
|
||||
match err_code {
|
||||
vk::Result::SUCCESS => Ok(messenger),
|
||||
_ => Err(err_code),
|
||||
}
|
||||
}
|
||||
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkDestroyDebugUtilsMessengerEXT.html>"]
|
||||
pub unsafe fn destroy_debug_utils_messenger(
|
||||
&self,
|
||||
messenger: vk::DebugUtilsMessengerEXT,
|
||||
allocator: Option<&vk::AllocationCallbacks>,
|
||||
) {
|
||||
self.debug_utils_fn.destroy_debug_utils_messenger_ext(
|
||||
self.handle,
|
||||
messenger,
|
||||
allocator.as_raw_ptr(),
|
||||
);
|
||||
}
|
||||
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkSubmitDebugUtilsMessageEXT.html>"]
|
||||
pub unsafe fn submit_debug_utils_message(
|
||||
&self,
|
||||
instance: vk::Instance,
|
||||
message_severity: vk::DebugUtilsMessageSeverityFlagsEXT,
|
||||
message_types: vk::DebugUtilsMessageTypeFlagsEXT,
|
||||
callback_data: &vk::DebugUtilsMessengerCallbackDataEXT,
|
||||
) {
|
||||
self.debug_utils_fn.submit_debug_utils_message_ext(
|
||||
instance,
|
||||
message_severity,
|
||||
message_types,
|
||||
callback_data,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
pub use self::debug_marker::DebugMarker;
|
||||
pub use self::debug_report::DebugReport;
|
||||
pub use self::debug_utils::DebugUtils;
|
||||
|
||||
mod debug_marker;
|
||||
mod debug_report;
|
||||
mod debug_utils;
|
|
@ -0,0 +1,48 @@
|
|||
#![allow(dead_code)]
|
||||
use prelude::*;
|
||||
use std::ffi::CStr;
|
||||
use std::mem;
|
||||
use version::{EntryV1_0, InstanceV1_0};
|
||||
use vk;
|
||||
use RawPtr;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AndroidSurface {
|
||||
handle: vk::Instance,
|
||||
android_surface_fn: vk::KhrAndroidSurfaceFn,
|
||||
}
|
||||
|
||||
impl AndroidSurface {
|
||||
pub fn new<E: EntryV1_0, I: InstanceV1_0>(entry: &E, instance: &I) -> AndroidSurface {
|
||||
let surface_fn = vk::KhrAndroidSurfaceFn::load(|name| unsafe {
|
||||
mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr()))
|
||||
});
|
||||
AndroidSurface {
|
||||
handle: instance.handle(),
|
||||
android_surface_fn: surface_fn,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name() -> &'static CStr {
|
||||
vk::KhrAndroidSurfaceFn::name()
|
||||
}
|
||||
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkCreateAndroidSurfaceKHR.html>"]
|
||||
pub unsafe fn create_android_surface(
|
||||
&self,
|
||||
create_info: &vk::AndroidSurfaceCreateInfoKHR,
|
||||
allocation_callbacks: Option<&vk::AllocationCallbacks>,
|
||||
) -> VkResult<vk::SurfaceKHR> {
|
||||
let mut surface = mem::uninitialized();
|
||||
let err_code = self.android_surface_fn.create_android_surface_khr(
|
||||
self.handle,
|
||||
create_info,
|
||||
allocation_callbacks.as_raw_ptr(),
|
||||
&mut surface,
|
||||
);
|
||||
match err_code {
|
||||
vk::Result::SUCCESS => Ok(surface),
|
||||
_ => Err(err_code),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
#![allow(dead_code)]
|
||||
use prelude::*;
|
||||
use std::ffi::CStr;
|
||||
use std::mem;
|
||||
use version::{DeviceV1_0, InstanceV1_0};
|
||||
use vk;
|
||||
use RawPtr;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DisplaySwapchain {
|
||||
handle: vk::Device,
|
||||
swapchain_fn: vk::KhrDisplaySwapchainFn,
|
||||
}
|
||||
|
||||
impl DisplaySwapchain {
|
||||
pub fn new<I: InstanceV1_0, D: DeviceV1_0>(instance: &I, device: &D) -> DisplaySwapchain {
|
||||
let swapchain_fn = vk::KhrDisplaySwapchainFn::load(|name| unsafe {
|
||||
mem::transmute(instance.get_device_proc_addr(device.handle(), name.as_ptr()))
|
||||
});
|
||||
DisplaySwapchain {
|
||||
handle: device.handle(),
|
||||
swapchain_fn: swapchain_fn,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name() -> &'static CStr {
|
||||
vk::KhrDisplaySwapchainFn::name()
|
||||
}
|
||||
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkCreateSharedSwapchainsKHR.html>"]
|
||||
pub unsafe fn create_shared_swapchains(
|
||||
&self,
|
||||
create_infos: &[vk::SwapchainCreateInfoKHR],
|
||||
allocation_callbacks: Option<&vk::AllocationCallbacks>,
|
||||
) -> VkResult<Vec<vk::SwapchainKHR>> {
|
||||
let mut swapchains = Vec::with_capacity(create_infos.len());
|
||||
let err_code = self.swapchain_fn.create_shared_swapchains_khr(
|
||||
self.handle,
|
||||
create_infos.len() as u32,
|
||||
create_infos.as_ptr(),
|
||||
allocation_callbacks.as_raw_ptr(),
|
||||
swapchains.as_mut_ptr(),
|
||||
);
|
||||
swapchains.set_len(create_infos.len());
|
||||
match err_code {
|
||||
vk::Result::SUCCESS => Ok(swapchains),
|
||||
_ => Err(err_code),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
pub use self::android_surface::AndroidSurface;
|
||||
pub use self::display_swapchain::DisplaySwapchain;
|
||||
pub use self::surface::Surface;
|
||||
pub use self::swapchain::Swapchain;
|
||||
pub use self::wayland_surface::WaylandSurface;
|
||||
pub use self::win32_surface::Win32Surface;
|
||||
pub use self::xcb_surface::XcbSurface;
|
||||
pub use self::xlib_surface::XlibSurface;
|
||||
|
||||
mod android_surface;
|
||||
mod display_swapchain;
|
||||
mod surface;
|
||||
mod swapchain;
|
||||
mod wayland_surface;
|
||||
mod win32_surface;
|
||||
mod xcb_surface;
|
||||
mod xlib_surface;
|
|
@ -0,0 +1,137 @@
|
|||
#![allow(dead_code)]
|
||||
use prelude::*;
|
||||
use std::ffi::CStr;
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
use version::{EntryV1_0, InstanceV1_0};
|
||||
use vk;
|
||||
use RawPtr;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Surface {
|
||||
handle: vk::Instance,
|
||||
surface_fn: vk::KhrSurfaceFn,
|
||||
}
|
||||
|
||||
impl Surface {
|
||||
pub fn new<E: EntryV1_0, I: InstanceV1_0>(entry: &E, instance: &I) -> Surface {
|
||||
let surface_fn = vk::KhrSurfaceFn::load(|name| unsafe {
|
||||
mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr()))
|
||||
});
|
||||
Surface {
|
||||
handle: instance.handle(),
|
||||
surface_fn: surface_fn,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name() -> &'static CStr {
|
||||
vk::KhrSurfaceFn::name()
|
||||
}
|
||||
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkGetPhysicalDeviceSurfaceSupportKHR.html>"]
|
||||
pub unsafe fn get_physical_device_surface_support(
|
||||
&self,
|
||||
physical_device: vk::PhysicalDevice,
|
||||
queue_index: u32,
|
||||
surface: vk::SurfaceKHR,
|
||||
) -> bool {
|
||||
let mut b = mem::uninitialized();
|
||||
self.surface_fn.get_physical_device_surface_support_khr(
|
||||
physical_device,
|
||||
queue_index,
|
||||
surface,
|
||||
&mut b,
|
||||
);
|
||||
b > 0
|
||||
}
|
||||
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkGetPhysicalDeviceSurfacePresentModesKHR.html>"]
|
||||
pub unsafe fn get_physical_device_surface_present_modes(
|
||||
&self,
|
||||
physical_device: vk::PhysicalDevice,
|
||||
surface: vk::SurfaceKHR,
|
||||
) -> VkResult<Vec<vk::PresentModeKHR>> {
|
||||
let mut count = 0;
|
||||
self.surface_fn
|
||||
.get_physical_device_surface_present_modes_khr(
|
||||
physical_device,
|
||||
surface,
|
||||
&mut count,
|
||||
ptr::null_mut(),
|
||||
);
|
||||
let mut v = Vec::with_capacity(count as usize);
|
||||
let err_code = self
|
||||
.surface_fn
|
||||
.get_physical_device_surface_present_modes_khr(
|
||||
physical_device,
|
||||
surface,
|
||||
&mut count,
|
||||
v.as_mut_ptr(),
|
||||
);
|
||||
v.set_len(count as usize);
|
||||
match err_code {
|
||||
vk::Result::SUCCESS => Ok(v),
|
||||
_ => Err(err_code),
|
||||
}
|
||||
}
|
||||
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkGetPhysicalDeviceSurfaceCapabilitiesKHR.html>"]
|
||||
pub unsafe fn get_physical_device_surface_capabilities(
|
||||
&self,
|
||||
physical_device: vk::PhysicalDevice,
|
||||
surface: vk::SurfaceKHR,
|
||||
) -> VkResult<vk::SurfaceCapabilitiesKHR> {
|
||||
let mut surface_capabilities = mem::uninitialized();
|
||||
let err_code = self
|
||||
.surface_fn
|
||||
.get_physical_device_surface_capabilities_khr(
|
||||
physical_device,
|
||||
surface,
|
||||
&mut surface_capabilities,
|
||||
);
|
||||
match err_code {
|
||||
vk::Result::SUCCESS => Ok(surface_capabilities),
|
||||
_ => Err(err_code),
|
||||
}
|
||||
}
|
||||
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkGetPhysicalDeviceSurfaceFormatsKHR.html>"]
|
||||
pub unsafe fn get_physical_device_surface_formats(
|
||||
&self,
|
||||
physical_device: vk::PhysicalDevice,
|
||||
surface: vk::SurfaceKHR,
|
||||
) -> VkResult<Vec<vk::SurfaceFormatKHR>> {
|
||||
let mut count = 0;
|
||||
self.surface_fn.get_physical_device_surface_formats_khr(
|
||||
physical_device,
|
||||
surface,
|
||||
&mut count,
|
||||
ptr::null_mut(),
|
||||
);
|
||||
let mut v = Vec::with_capacity(count as usize);
|
||||
let err_code = self.surface_fn.get_physical_device_surface_formats_khr(
|
||||
physical_device,
|
||||
surface,
|
||||
&mut count,
|
||||
v.as_mut_ptr(),
|
||||
);
|
||||
v.set_len(count as usize);
|
||||
match err_code {
|
||||
vk::Result::SUCCESS => Ok(v),
|
||||
_ => Err(err_code),
|
||||
}
|
||||
}
|
||||
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkDestroySurfaceKHR.html>"]
|
||||
pub unsafe fn destroy_surface(
|
||||
&self,
|
||||
surface: vk::SurfaceKHR,
|
||||
allocation_callbacks: Option<&vk::AllocationCallbacks>,
|
||||
) {
|
||||
self.surface_fn.destroy_surface_khr(
|
||||
self.handle,
|
||||
surface,
|
||||
allocation_callbacks.as_raw_ptr(),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
#![allow(dead_code)]
|
||||
use prelude::*;
|
||||
use std::ffi::CStr;
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
use version::{DeviceV1_0, InstanceV1_0};
|
||||
use vk;
|
||||
use RawPtr;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Swapchain {
|
||||
handle: vk::Device,
|
||||
swapchain_fn: vk::KhrSwapchainFn,
|
||||
}
|
||||
|
||||
impl Swapchain {
|
||||
pub fn new<I: InstanceV1_0, D: DeviceV1_0>(instance: &I, device: &D) -> Swapchain {
|
||||
let swapchain_fn = vk::KhrSwapchainFn::load(|name| unsafe {
|
||||
mem::transmute(instance.get_device_proc_addr(device.handle(), name.as_ptr()))
|
||||
});
|
||||
Swapchain {
|
||||
handle: device.handle(),
|
||||
swapchain_fn: swapchain_fn,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name() -> &'static CStr {
|
||||
vk::KhrSwapchainFn::name()
|
||||
}
|
||||
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkDestroySwapchainKHR.html>"]
|
||||
pub unsafe fn destroy_swapchain(
|
||||
&self,
|
||||
swapchain: vk::SwapchainKHR,
|
||||
allocation_callbacks: Option<&vk::AllocationCallbacks>,
|
||||
) {
|
||||
self.swapchain_fn.destroy_swapchain_khr(
|
||||
self.handle,
|
||||
swapchain,
|
||||
allocation_callbacks.as_raw_ptr(),
|
||||
);
|
||||
}
|
||||
|
||||
/// On success, returns the next image's index and whether the swapchain is suboptimal for the surface.
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkAcquireNextImageKHR.html>"]
|
||||
pub unsafe fn acquire_next_image(
|
||||
&self,
|
||||
swapchain: vk::SwapchainKHR,
|
||||
timeout: u64,
|
||||
semaphore: vk::Semaphore,
|
||||
fence: vk::Fence,
|
||||
) -> VkResult<(u32, bool)> {
|
||||
let mut index = mem::uninitialized();
|
||||
let err_code = self.swapchain_fn.acquire_next_image_khr(
|
||||
self.handle,
|
||||
swapchain,
|
||||
timeout,
|
||||
semaphore,
|
||||
fence,
|
||||
&mut index,
|
||||
);
|
||||
match err_code {
|
||||
vk::Result::SUCCESS => Ok((index, false)),
|
||||
vk::Result::SUBOPTIMAL_KHR => Ok((index, true)),
|
||||
_ => Err(err_code),
|
||||
}
|
||||
}
|
||||
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkCreateSwapchainKHR.html>"]
|
||||
pub unsafe fn create_swapchain(
|
||||
&self,
|
||||
create_info: &vk::SwapchainCreateInfoKHR,
|
||||
allocation_callbacks: Option<&vk::AllocationCallbacks>,
|
||||
) -> VkResult<vk::SwapchainKHR> {
|
||||
let mut swapchain = mem::uninitialized();
|
||||
let err_code = self.swapchain_fn.create_swapchain_khr(
|
||||
self.handle,
|
||||
create_info,
|
||||
allocation_callbacks.as_raw_ptr(),
|
||||
&mut swapchain,
|
||||
);
|
||||
match err_code {
|
||||
vk::Result::SUCCESS => Ok(swapchain),
|
||||
_ => Err(err_code),
|
||||
}
|
||||
}
|
||||
|
||||
/// On success, returns whether the swapchain is suboptimal for the surface.
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkQueuePresentKHR.html>"]
|
||||
pub unsafe fn queue_present(
|
||||
&self,
|
||||
queue: vk::Queue,
|
||||
create_info: &vk::PresentInfoKHR,
|
||||
) -> VkResult<bool> {
|
||||
let err_code = self.swapchain_fn.queue_present_khr(queue, create_info);
|
||||
match err_code {
|
||||
vk::Result::SUCCESS => Ok(false),
|
||||
vk::Result::SUBOPTIMAL_KHR => Ok(true),
|
||||
_ => Err(err_code),
|
||||
}
|
||||
}
|
||||
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkGetSwapchainImagesKHR.html>"]
|
||||
pub unsafe fn get_swapchain_images(
|
||||
&self,
|
||||
swapchain: vk::SwapchainKHR,
|
||||
) -> VkResult<Vec<vk::Image>> {
|
||||
let mut count = 0;
|
||||
self.swapchain_fn.get_swapchain_images_khr(
|
||||
self.handle,
|
||||
swapchain,
|
||||
&mut count,
|
||||
ptr::null_mut(),
|
||||
);
|
||||
|
||||
let mut v = Vec::with_capacity(count as usize);
|
||||
let err_code = self.swapchain_fn.get_swapchain_images_khr(
|
||||
self.handle,
|
||||
swapchain,
|
||||
&mut count,
|
||||
v.as_mut_ptr(),
|
||||
);
|
||||
v.set_len(count as usize);
|
||||
match err_code {
|
||||
vk::Result::SUCCESS => Ok(v),
|
||||
_ => Err(err_code),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
#![allow(dead_code)]
|
||||
use prelude::*;
|
||||
use std::ffi::CStr;
|
||||
use std::mem;
|
||||
use version::{EntryV1_0, InstanceV1_0};
|
||||
use vk;
|
||||
use RawPtr;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WaylandSurface {
|
||||
handle: vk::Instance,
|
||||
wayland_surface_fn: vk::KhrWaylandSurfaceFn,
|
||||
}
|
||||
|
||||
impl WaylandSurface {
|
||||
pub fn new<E: EntryV1_0, I: InstanceV1_0>(entry: &E, instance: &I) -> WaylandSurface {
|
||||
let surface_fn = vk::KhrWaylandSurfaceFn::load(|name| unsafe {
|
||||
mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr()))
|
||||
});
|
||||
WaylandSurface {
|
||||
handle: instance.handle(),
|
||||
wayland_surface_fn: surface_fn,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name() -> &'static CStr {
|
||||
vk::KhrWaylandSurfaceFn::name()
|
||||
}
|
||||
|
||||
#[doc = "<https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkCreateWaylandSurfaceKHR.html>"]
|
||||
pub unsafe fn create_wayland_surface(
|
||||
&self,
|
||||
create_info: &vk::WaylandSurfaceCreateInfoKHR,
|
||||
allocation_callbacks: Option<&vk::AllocationCallbacks>,
|
||||
) -> VkResult<vk::SurfaceKHR> {
|
||||
let mut surface = mem::uninitialized();
|
||||
let err_code = self.wayland_surface_fn.create_wayland_surface_khr(
|
||||
self.handle,
|
||||
create_info,
|
||||
allocation_callbacks.as_raw_ptr(),
|
||||
&mut surface,
|
||||
);
|
||||
match err_code {
|
||||
vk::Result::SUCCESS => Ok(surface),
|
||||
_ => Err(err_code),
|
||||
}
|
||||
}
|
||||
}
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче