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:
Dzmitry Malyshau 2019-11-14 04:59:56 +00:00
Родитель bd713fe4ee
Коммит 1c5b01ed15
697 изменённых файлов: 247784 добавлений и 2631 удалений

Просмотреть файл

@ -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

463
Cargo.lock сгенерированный
Просмотреть файл

@ -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();

32
dom/webgpu/ffi/moz.build Normal file
Просмотреть файл

@ -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'

31
dom/webgpu/ffi/wgpu.h Normal file
Просмотреть файл

@ -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"}

17
third_party/rust/arrayvec/Cargo.toml поставляемый
Просмотреть файл

@ -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 = []

40
third_party/rust/arrayvec/README.rst поставляемый
Просмотреть файл

@ -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

49
third_party/rust/arrayvec/benches/extend.rs поставляемый
Просмотреть файл

@ -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);

90
third_party/rust/arrayvec/build.rs поставляемый
Просмотреть файл

@ -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()
}

57
third_party/rust/arrayvec/src/array.rs поставляемый
Просмотреть файл

@ -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 doesnt
/// need implementing.
pub unsafe trait Array {
/// The arrays element type
type Item;
/// The smallest type that can index and tell the length of the array.
#[doc(hidden)]
/// The smallest index type that indexes the array.
type Index: Index;
#[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, );

177
third_party/rust/arrayvec/src/array_string.rs поставляемый
Просмотреть файл

@ -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 strings buffer
unsafe fn raw_mut_bytes(&mut self) -> &mut [u8] {
slice::from_raw_parts_mut(self.xs.as_mut_ptr(), self.capacity())
}
}
impl<A: Array<Item=u8>> Deref for ArrayString<A> {
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))
}

74
third_party/rust/arrayvec/src/char.rs поставляемый
Просмотреть файл

@ -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(_)));
}
}
}

252
third_party/rust/arrayvec/src/lib.rs поставляемый
Просмотреть файл

@ -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));
}
}

32
third_party/rust/arrayvec/src/maybe_uninit.rs поставляемый
Просмотреть файл

@ -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
}
}

42
third_party/rust/arrayvec/src/range.rs поставляемый
Просмотреть файл

@ -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) }
}

2
third_party/rust/arrayvec/tests/serde.rs поставляемый
Просмотреть файл

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

180
third_party/rust/arrayvec/tests/tests.rs поставляемый
Просмотреть файл

@ -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);
}

1
third_party/rust/ash/.cargo-checksum.json поставляемый Normal file
Просмотреть файл

@ -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"}

29
third_party/rust/ash/Cargo.toml поставляемый Normal file
Просмотреть файл

@ -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
third_party/rust/ash/output поставляемый Normal file
Просмотреть файл

120
third_party/rust/ash/src/allocator.rs поставляемый Normal file
Просмотреть файл

@ -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
}
}

1997
third_party/rust/ash/src/device.rs поставляемый Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

281
third_party/rust/ash/src/entry.rs поставляемый Normal file
Просмотреть файл

@ -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)
}
}
}
}

701
third_party/rust/ash/src/extensions/experimental/amd.rs поставляемый Normal file
Просмотреть файл

@ -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,
}

1
third_party/rust/ash/src/extensions/experimental/mod.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1 @@
pub mod amd;

67
third_party/rust/ash/src/extensions/ext/debug_marker.rs поставляемый Normal file
Просмотреть файл

@ -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);
}
}

61
third_party/rust/ash/src/extensions/ext/debug_report.rs поставляемый Normal file
Просмотреть файл

@ -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),
}
}
}

157
third_party/rust/ash/src/extensions/ext/debug_utils.rs поставляемый Normal file
Просмотреть файл

@ -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,
);
}
}

7
third_party/rust/ash/src/extensions/ext/mod.rs поставляемый Normal file
Просмотреть файл

@ -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;

48
third_party/rust/ash/src/extensions/khr/android_surface.rs поставляемый Normal file
Просмотреть файл

@ -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),
}
}
}

50
third_party/rust/ash/src/extensions/khr/display_swapchain.rs поставляемый Normal file
Просмотреть файл

@ -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),
}
}
}

17
third_party/rust/ash/src/extensions/khr/mod.rs поставляемый Normal file
Просмотреть файл

@ -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;

137
third_party/rust/ash/src/extensions/khr/surface.rs поставляемый Normal file
Просмотреть файл

@ -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(),
);
}
}

129
third_party/rust/ash/src/extensions/khr/swapchain.rs поставляемый Normal file
Просмотреть файл

@ -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),
}
}
}

48
third_party/rust/ash/src/extensions/khr/wayland_surface.rs поставляемый Normal file
Просмотреть файл

@ -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),
}
}
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше