Bug 1873164 - Update wgpu to revision 4b82121501a61c2c2e11cb472d70ba54af3aa12d. r=webgpu-reviewers,supply-chain-reviewers,ErichDonGubler

Changelog

 * #4927 BGL Weak Pointer Deduplication Pool
   By cwfitzgerald in https://github.com/gfx-rs/wgpu/pull/4927
 * #4958 Change examples page menu on smaller screens
   By Dinnerbone in https://github.com/gfx-rs/wgpu/pull/4958
 * #4950 Bump anyhow from 1.0.77 to 1.0.78
   By dependabot[bot] in https://github.com/gfx-rs/wgpu/pull/4950
 * #4957 Disable Linux Tests
   By cwfitzgerald in https://github.com/gfx-rs/wgpu/pull/4957
 * #4960 Fix incorrect ConfigureSurfaceError::TooLarge message
   By Dinnerbone in https://github.com/gfx-rs/wgpu/pull/4960
 * #4935 Add `cfg_aliases` to `wgpu`
   By daxpedda in https://github.com/gfx-rs/wgpu/pull/4935
 * #4939 hello_compute: check for missing command-line args
   By vilcans in https://github.com/gfx-rs/wgpu/pull/4939
 * #4948 Bump winit from 0.29.6 to 0.29.8
   By dependabot[bot] in https://github.com/gfx-rs/wgpu/pull/4948
 * #4944 Fix xtask wasm-bindgen install
   By rukai in https://github.com/gfx-rs/wgpu/pull/4944
 * #4858 [glsl-in] fix swizzle in global const context
   By teoxoy in https://github.com/gfx-rs/wgpu/pull/4858
 * #4968 [gl] fix RGBA8 format capabilities
   By teoxoy in https://github.com/gfx-rs/wgpu/pull/4968
 * #4947 Avoid allocating during queue submit
   By udoprog in https://github.com/gfx-rs/wgpu/pull/4947
 * #4965 Bump serde from 1.0.193 to 1.0.194
   By dependabot[bot] in https://github.com/gfx-rs/wgpu/pull/4965
 * #4975 Fix Hang in Multithreaded Compute Test
   By cwfitzgerald in https://github.com/gfx-rs/wgpu/pull/4975
 * #4966 Bump anyhow from 1.0.78 to 1.0.79
   By dependabot[bot] in https://github.com/gfx-rs/wgpu/pull/4966
 * #4978 Bump thiserror from 1.0.52 to 1.0.56
   By dependabot[bot] in https://github.com/gfx-rs/wgpu/pull/4978
 * #4979 Bump syn from 2.0.46 to 2.0.47
   By dependabot[bot] in https://github.com/gfx-rs/wgpu/pull/4979
 * #4977 Use Custom Mesa for Building
   By cwfitzgerald in https://github.com/gfx-rs/wgpu/pull/4977
 * #4981 Bump serde_json from 1.0.108 to 1.0.110
   By dependabot[bot] in https://github.com/gfx-rs/wgpu/pull/4981
 * #4959 wgpu-hal: Fix Mesa version check for version with suffix containing `.`
   By ids1024 in https://github.com/gfx-rs/wgpu/pull/4959
 * #4976 Shorten Lock Lifetimes
   By cwfitzgerald in https://github.com/gfx-rs/wgpu/pull/4976
 * #4980 Pin DXC and Vulkan SDK version
   By cwfitzgerald in https://github.com/gfx-rs/wgpu/pull/4980
 * #4974 gles: use already existing debug__fn private capabilty instead of checking extensions
   By valaphee in https://github.com/gfx-rs/wgpu/pull/4974
 * #4987 Remove Mac CI
   By cwfitzgerald in https://github.com/gfx-rs/wgpu/pull/4987
 * #4990 Fix Queue::write_texture, Fix DX12 write_texture_subset_2d and re-enable the test.
   By dtzxporter in https://github.com/gfx-rs/wgpu/pull/4990
 * #4994 Bump syn from 2.0.47 to 2.0.48
   By dependabot[bot] in https://github.com/gfx-rs/wgpu/pull/4994
 * #4993 Bump serde_json from 1.0.110 to 1.0.111
   By dependabot[bot] in https://github.com/gfx-rs/wgpu/pull/4993
 * #4992 Bump gpu-allocator from 0.24.0 to 0.25.0
   By dependabot[bot] in https://github.com/gfx-rs/wgpu/pull/4992
 * #4995 Add Verbosity Flags to wgpu-info
   By cwfitzgerald in https://github.com/gfx-rs/wgpu/pull/4995
 * #4996 Dependency Update Rollup
   By cwfitzgerald in https://github.com/gfx-rs/wgpu/pull/4996
 * #4954 Put raw texture access behind snatch guards
   By nical in https://github.com/gfx-rs/wgpu/pull/4954
 * #4954 Put raw texture access behind snatch guards
   By nical in https://github.com/gfx-rs/wgpu/pull/4954
 * #4969 Texture snatching
   By nical in https://github.com/gfx-rs/wgpu/pull/4969
 * #4969 Texture snatching
   By nical in https://github.com/gfx-rs/wgpu/pull/4969

Differential Revision: https://phabricator.services.mozilla.com/D197786
This commit is contained in:
Nicolas Silva 2024-01-05 21:57:42 +00:00
parent 915014cad0
commit ff86798488
60 changed files with 2777 additions and 2350 deletions

View File

@ -25,9 +25,9 @@ git = "https://github.com/franziskuskiefer/cose-rust"
rev = "43c22248d136c8b38fe42ea709d08da6355cf04b"
replace-with = "vendored-sources"
[source."git+https://github.com/gfx-rs/wgpu?rev=46757372cc02d6608124502104a0c225e1744fd7"]
[source."git+https://github.com/gfx-rs/wgpu?rev=4b82121501a61c2c2e11cb472d70ba54af3aa12d"]
git = "https://github.com/gfx-rs/wgpu"
rev = "46757372cc02d6608124502104a0c225e1744fd7"
rev = "4b82121501a61c2c2e11cb472d70ba54af3aa12d"
replace-with = "vendored-sources"
[source."git+https://github.com/hsivonen/chardetng?rev=3484d3e3ebdc8931493aa5df4d7ee9360a90e76b"]

27
Cargo.lock generated
View File

@ -1157,7 +1157,7 @@ dependencies = [
[[package]]
name = "d3d12"
version = "0.7.0"
source = "git+https://github.com/gfx-rs/wgpu?rev=46757372cc02d6608124502104a0c225e1744fd7#46757372cc02d6608124502104a0c225e1744fd7"
source = "git+https://github.com/gfx-rs/wgpu?rev=4b82121501a61c2c2e11cb472d70ba54af3aa12d#4b82121501a61c2c2e11cb472d70ba54af3aa12d"
dependencies = [
"bitflags 2.4.0",
"libloading",
@ -3796,7 +3796,7 @@ checksum = "a2983372caf4480544083767bf2d27defafe32af49ab4df3a0b7fc90793a3664"
[[package]]
name = "naga"
version = "0.14.2"
source = "git+https://github.com/gfx-rs/wgpu?rev=46757372cc02d6608124502104a0c225e1744fd7#46757372cc02d6608124502104a0c225e1744fd7"
source = "git+https://github.com/gfx-rs/wgpu?rev=4b82121501a61c2c2e11cb472d70ba54af3aa12d#4b82121501a61c2c2e11cb472d70ba54af3aa12d"
dependencies = [
"bit-set",
"bitflags 2.4.0",
@ -4937,9 +4937,9 @@ dependencies = [
[[package]]
name = "serde"
version = "1.0.193"
version = "1.0.194"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
checksum = "0b114498256798c94a0689e1a15fec6005dee8ac1f41de56404b67afc2a4b773"
dependencies = [
"serde_derive",
]
@ -4965,9 +4965,9 @@ dependencies = [
[[package]]
name = "serde_derive"
version = "1.0.193"
version = "1.0.194"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
checksum = "a3385e45322e8f9931410f01b3031ec534c3947d0e94c18049af4d9f9907d4e0"
dependencies = [
"proc-macro2",
"quote",
@ -5178,12 +5178,11 @@ dependencies = [
[[package]]
name = "spirv"
version = "0.2.0+1.5.4"
version = "0.3.0+sdk-1.3.268.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "246bfa38fe3db3f1dfc8ca5a2cdeb7348c78be2112740cc0ec8ef18b6d94f830"
checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844"
dependencies = [
"bitflags 1.999.999",
"num-traits",
"bitflags 2.4.0",
]
[[package]]
@ -6412,14 +6411,16 @@ dependencies = [
[[package]]
name = "wgpu-core"
version = "0.18.0"
source = "git+https://github.com/gfx-rs/wgpu?rev=46757372cc02d6608124502104a0c225e1744fd7#46757372cc02d6608124502104a0c225e1744fd7"
source = "git+https://github.com/gfx-rs/wgpu?rev=4b82121501a61c2c2e11cb472d70ba54af3aa12d#4b82121501a61c2c2e11cb472d70ba54af3aa12d"
dependencies = [
"arrayvec",
"bit-vec",
"bitflags 2.4.0",
"codespan-reporting",
"indexmap 2.999.999",
"log",
"naga",
"once_cell",
"parking_lot",
"profiling",
"ron",
@ -6435,7 +6436,7 @@ dependencies = [
[[package]]
name = "wgpu-hal"
version = "0.18.0"
source = "git+https://github.com/gfx-rs/wgpu?rev=46757372cc02d6608124502104a0c225e1744fd7#46757372cc02d6608124502104a0c225e1744fd7"
source = "git+https://github.com/gfx-rs/wgpu?rev=4b82121501a61c2c2e11cb472d70ba54af3aa12d#4b82121501a61c2c2e11cb472d70ba54af3aa12d"
dependencies = [
"android_system_properties",
"arrayvec",
@ -6472,7 +6473,7 @@ dependencies = [
[[package]]
name = "wgpu-types"
version = "0.18.0"
source = "git+https://github.com/gfx-rs/wgpu?rev=46757372cc02d6608124502104a0c225e1744fd7#46757372cc02d6608124502104a0c225e1744fd7"
source = "git+https://github.com/gfx-rs/wgpu?rev=4b82121501a61c2c2e11cb472d70ba54af3aa12d#4b82121501a61c2c2e11cb472d70ba54af3aa12d"
dependencies = [
"bitflags 2.4.0",
"js-sys",

View File

@ -17,7 +17,7 @@ default = []
[dependencies.wgc]
package = "wgpu-core"
git = "https://github.com/gfx-rs/wgpu"
rev = "46757372cc02d6608124502104a0c225e1744fd7"
rev = "4b82121501a61c2c2e11cb472d70ba54af3aa12d"
#Note: "replay" shouldn't ideally be needed,
# but it allows us to serialize everything across IPC.
features = ["replay", "trace", "serial-pass", "strict_asserts", "wgsl", "api_log_info"]
@ -27,36 +27,36 @@ features = ["replay", "trace", "serial-pass", "strict_asserts", "wgsl", "api_log
[target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies.wgc]
package = "wgpu-core"
git = "https://github.com/gfx-rs/wgpu"
rev = "46757372cc02d6608124502104a0c225e1744fd7"
rev = "4b82121501a61c2c2e11cb472d70ba54af3aa12d"
features = ["metal"]
# We want the wgpu-core Direct3D backends on Windows.
[target.'cfg(windows)'.dependencies.wgc]
package = "wgpu-core"
git = "https://github.com/gfx-rs/wgpu"
rev = "46757372cc02d6608124502104a0c225e1744fd7"
rev = "4b82121501a61c2c2e11cb472d70ba54af3aa12d"
features = ["dx12"]
# We want the wgpu-core Vulkan backend on Linux and Windows.
[target.'cfg(any(windows, all(unix, not(any(target_os = "macos", target_os = "ios")))))'.dependencies.wgc]
package = "wgpu-core"
git = "https://github.com/gfx-rs/wgpu"
rev = "46757372cc02d6608124502104a0c225e1744fd7"
rev = "4b82121501a61c2c2e11cb472d70ba54af3aa12d"
features = ["vulkan"]
[dependencies.wgt]
package = "wgpu-types"
git = "https://github.com/gfx-rs/wgpu"
rev = "46757372cc02d6608124502104a0c225e1744fd7"
rev = "4b82121501a61c2c2e11cb472d70ba54af3aa12d"
[dependencies.wgh]
package = "wgpu-hal"
git = "https://github.com/gfx-rs/wgpu"
rev = "46757372cc02d6608124502104a0c225e1744fd7"
rev = "4b82121501a61c2c2e11cb472d70ba54af3aa12d"
[target.'cfg(windows)'.dependencies.d3d12]
git = "https://github.com/gfx-rs/wgpu"
rev = "46757372cc02d6608124502104a0c225e1744fd7"
rev = "4b82121501a61c2c2e11cb472d70ba54af3aa12d"
[target.'cfg(windows)'.dependencies]
winapi = "0.3"

View File

@ -20,11 +20,11 @@ origin:
# Human-readable identifier for this version/release
# Generally "version NNN", "tag SSS", "bookmark SSS"
release: commit 46757372cc02d6608124502104a0c225e1744fd7
release: commit 4b82121501a61c2c2e11cb472d70ba54af3aa12d
# Revision to pull in
# Must be a long or short commit SHA (long preferred)
revision: 46757372cc02d6608124502104a0c225e1744fd7
revision: 4b82121501a61c2c2e11cb472d70ba54af3aa12d
license: ['MIT', 'Apache-2.0']

View File

@ -1269,7 +1269,7 @@ who = [
"Nicolas Silva <nical@fastmail.com>",
]
criteria = "safe-to-deploy"
delta = "0.7.0 -> 0.7.0@git:46757372cc02d6608124502104a0c225e1744fd7"
delta = "0.7.0 -> 0.7.0@git:4b82121501a61c2c2e11cb472d70ba54af3aa12d"
importable = false
[[audits.darling]]
@ -2541,7 +2541,7 @@ delta = "0.13.0 -> 0.14.0"
[[audits.naga]]
who = ["Jim Blandy <jimb@red-bean.com>", "Nicolas Silva <nical@fastmail.com>"]
criteria = "safe-to-deploy"
delta = "0.14.0 -> 0.14.2@git:46757372cc02d6608124502104a0c225e1744fd7"
delta = "0.14.0 -> 0.14.2@git:4b82121501a61c2c2e11cb472d70ba54af3aa12d"
importable = false
[[audits.net2]]
@ -3519,6 +3519,11 @@ who = "Mike Hommey <mh+mozilla@glandium.org>"
criteria = "safe-to-deploy"
delta = "0.4.4 -> 0.4.7"
[[audits.spirv]]
who = "Nicolas Silva <nical@fastmail.com>"
criteria = "safe-to-deploy"
delta = "0.2.0+1.5.4 -> 0.3.0+sdk-1.3.268.0"
[[audits.strck]]
who = "Makoto Kato <m_kato@ga2.so-net.ne.jp>"
criteria = "safe-to-deploy"
@ -4308,7 +4313,7 @@ delta = "0.17.0 -> 0.18.0"
[[audits.wgpu-core]]
who = ["Jim Blandy <jimb@red-bean.com>", "Nicolas Silva <nical@fastmail.com>"]
criteria = "safe-to-deploy"
delta = "0.18.0 -> 0.18.0@git:46757372cc02d6608124502104a0c225e1744fd7"
delta = "0.18.0 -> 0.18.0@git:4b82121501a61c2c2e11cb472d70ba54af3aa12d"
importable = false
[[audits.wgpu-hal]]
@ -4357,7 +4362,7 @@ delta = "0.17.0 -> 0.18.0"
[[audits.wgpu-hal]]
who = ["Jim Blandy <jimb@red-bean.com>", "Nicolas Silva <nical@fastmail.com>"]
criteria = "safe-to-deploy"
delta = "0.18.0 -> 0.18.0@git:46757372cc02d6608124502104a0c225e1744fd7"
delta = "0.18.0 -> 0.18.0@git:4b82121501a61c2c2e11cb472d70ba54af3aa12d"
importable = false
[[audits.wgpu-types]]
@ -4406,7 +4411,7 @@ delta = "0.17.0 -> 0.18.0"
[[audits.wgpu-types]]
who = ["Jim Blandy <jimb@red-bean.com>", "Nicolas Silva <nical@fastmail.com>"]
criteria = "safe-to-deploy"
delta = "0.18.0 -> 0.18.0@git:46757372cc02d6608124502104a0c225e1744fd7"
delta = "0.18.0 -> 0.18.0@git:4b82121501a61c2c2e11cb472d70ba54af3aa12d"
importable = false
[[audits.whatsys]]

View File

@ -545,6 +545,13 @@ user-id = 3618
user-login = "dtolnay"
user-name = "David Tolnay"
[[publisher.serde]]
version = "1.0.194"
when = "2024-01-02"
user-id = 3618
user-login = "dtolnay"
user-name = "David Tolnay"
[[publisher.serde_bytes]]
version = "0.11.9"
when = "2023-02-05"
@ -573,6 +580,13 @@ user-id = 3618
user-login = "dtolnay"
user-name = "David Tolnay"
[[publisher.serde_derive]]
version = "1.0.194"
when = "2024-01-02"
user-id = 3618
user-login = "dtolnay"
user-name = "David Tolnay"
[[publisher.serde_json]]
version = "1.0.93"
when = "2023-02-08"

File diff suppressed because one or more lines are too long

View File

@ -51,7 +51,7 @@ bitflags = "2.2"
log = "0.4"
num-traits = "0.2"
rustc-hash = "1.1.0"
thiserror = "1.0.52"
thiserror = "1.0.56"
[dependencies.arbitrary]
version = "1.3"
@ -78,12 +78,12 @@ version = "0.2.1"
optional = true
[dependencies.serde]
version = "1.0.193"
version = "1.0.194"
features = ["derive"]
optional = true
[dependencies.spirv]
version = "0.2"
version = "0.3"
optional = true
[dependencies.termcolor]
@ -113,7 +113,7 @@ version = "1.0"
features = ["derive"]
[dev-dependencies.spirv]
version = "0.2"
version = "0.3"
features = ["deserialize"]
[features]

View File

@ -1478,7 +1478,11 @@ impl Index<Handle<Expression>> for Context<'_> {
type Output = Expression;
fn index(&self, index: Handle<Expression>) -> &Self::Output {
&self.expressions[index]
if self.is_const {
&self.module.const_expressions[index]
} else {
&self.expressions[index]
}
}
}

View File

@ -1,5 +1,4 @@
use super::error::Error;
use num_traits::cast::FromPrimitive;
use std::convert::TryInto;
pub(super) const fn map_binary_operator(word: spirv::Op) -> Result<crate::BinaryOperator, Error> {

View File

@ -43,7 +43,6 @@ use crate::{
FastHashMap, FastHashSet, FastIndexMap,
};
use num_traits::cast::FromPrimitive;
use petgraph::graphmap::GraphMap;
use std::{convert::TryInto, mem, num::NonZeroU32, path::PathBuf};
@ -661,7 +660,7 @@ impl<I: Iterator<Item = u32>> Frontend<I> {
if wc == 0 {
return Err(Error::InvalidWordCount);
}
let op = spirv::Op::from_u16(opcode).ok_or(Error::UnknownInstruction(opcode))?;
let op = spirv::Op::from_u32(opcode as u32).ok_or(Error::UnknownInstruction(opcode))?;
Ok(Instruction { op, wc })
}

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"931117d542e190ad20b9c984a357c900c39fe8d59df2c229b6e3a711622a98c8","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"c3ece10a36d19b4e857a770eaf74a2164d220f55fa11947065a3898c1697ecef","build.rs":"f9ba30324b9ce085c903595fb55a5293f8c2348ff36bfe870521b935ae6d105c","crates-io.md":"56e988ac4944c45f5bf5051e3827892ed8fb817853d99d9df1fff6621108e270","src/de/format.rs":"c85071b016df643b161859682d21ce34fa0ebf2a3bdbeeea69859da48f5d934f","src/de/ignored_any.rs":"6480f2b2a83dc4764d01b2eec7309729eef2492eede2e5ee98d23a60b05198eb","src/de/impls.rs":"2857d734176a0b78a41c9358354b0b0b83c6b2d948590be072d98606a8cae9d6","src/de/mod.rs":"07cbf58cc8f45d8009558adfed7f7340ea68ad9296bb79d7c4a872ae1a635d09","src/de/seed.rs":"045d890712a04eb33ffc5a021e5d948a63c89402b8ffeea749df2171b7484f8f","src/de/size_hint.rs":"fff83dc39d30e75e8e611991f9c5399188a1aad23a6462dbca2c8b62655cfedb","src/de/value.rs":"5d8dcae3a98a2203f2c0934adb84dbf741f120f246dfc02aa6d0d10673dc39c7","src/integer128.rs":"29ef30b7d94507b34807090e68173767cdc7aff62edccd38affe69e75338dddc","src/lib.rs":"45e8ba8590fc9e78a7bd0bbfac14cdb1eeea5cb16f920997e0efc10e0b55e540","src/macros.rs":"e3486ef4a9a4ed1b27234aa1817ccb25ec0eb026ffc95e2c71c7b917f1f45629","src/private/de.rs":"6557a124fdaf61f9c7cd80163e40f4a453354e45b63a4eb55dafdfe0159f6881","src/private/doc.rs":"9ad740e9ea2eedf861b77116eda9a6fb74bc8553541cd17d1bc5791a3ef3271a","src/private/mod.rs":"b8f0c348621d91dd9da3db83d8877e70bc61ad0a2dc2d6fb57c6fc2c2cbafa26","src/private/ser.rs":"656613691bd8d40cb70a52d4ebe3ee96a993c8a1292d50822d9ca5bdad84426b","src/ser/fmt.rs":"77a5583e5c227ea1982b097ed6378af5c899d43761d71e33440262fd35944695","src/ser/impls.rs":"850619164b399c37cd373d24f5a2c83453f40b34bb978c5722d2c1ae226775b5","src/ser/impossible.rs":"e11b37689ec1395378d546fce74221ca9046d0761744301f12029102fd07e30e","src/ser/mod.rs":"e95dabf07216136440d6a2822cf37775f583d141c21d1b37ec9c55ae2a5024ab","src/std_error.rs":"25a07149e2e468747ffa5a58051c7f93d7b3c0fa0372f012a96c97ec8ab03b97"},"package":"25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"}
{"files":{"Cargo.toml":"1823c76d8cb6a803a6f29bb748445814da9249561e17c21827c5ca061460f5f2","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"c3ece10a36d19b4e857a770eaf74a2164d220f55fa11947065a3898c1697ecef","build.rs":"f9ba30324b9ce085c903595fb55a5293f8c2348ff36bfe870521b935ae6d105c","crates-io.md":"56e988ac4944c45f5bf5051e3827892ed8fb817853d99d9df1fff6621108e270","src/de/format.rs":"c85071b016df643b161859682d21ce34fa0ebf2a3bdbeeea69859da48f5d934f","src/de/ignored_any.rs":"6480f2b2a83dc4764d01b2eec7309729eef2492eede2e5ee98d23a60b05198eb","src/de/impls.rs":"2857d734176a0b78a41c9358354b0b0b83c6b2d948590be072d98606a8cae9d6","src/de/mod.rs":"7fb7427de1981bfa13af06c898d213a6bc34697148e96cef08d3c447c1999527","src/de/seed.rs":"045d890712a04eb33ffc5a021e5d948a63c89402b8ffeea749df2171b7484f8f","src/de/size_hint.rs":"fff83dc39d30e75e8e611991f9c5399188a1aad23a6462dbca2c8b62655cfedb","src/de/value.rs":"5d8dcae3a98a2203f2c0934adb84dbf741f120f246dfc02aa6d0d10673dc39c7","src/integer128.rs":"29ef30b7d94507b34807090e68173767cdc7aff62edccd38affe69e75338dddc","src/lib.rs":"84c4afda21e66fc28152099bcf182092fe8df409ba510296c66a54987bb4a107","src/macros.rs":"e3486ef4a9a4ed1b27234aa1817ccb25ec0eb026ffc95e2c71c7b917f1f45629","src/private/de.rs":"6557a124fdaf61f9c7cd80163e40f4a453354e45b63a4eb55dafdfe0159f6881","src/private/doc.rs":"9ad740e9ea2eedf861b77116eda9a6fb74bc8553541cd17d1bc5791a3ef3271a","src/private/mod.rs":"b8f0c348621d91dd9da3db83d8877e70bc61ad0a2dc2d6fb57c6fc2c2cbafa26","src/private/ser.rs":"656613691bd8d40cb70a52d4ebe3ee96a993c8a1292d50822d9ca5bdad84426b","src/ser/fmt.rs":"77a5583e5c227ea1982b097ed6378af5c899d43761d71e33440262fd35944695","src/ser/impls.rs":"850619164b399c37cd373d24f5a2c83453f40b34bb978c5722d2c1ae226775b5","src/ser/impossible.rs":"e11b37689ec1395378d546fce74221ca9046d0761744301f12029102fd07e30e","src/ser/mod.rs":"a7fd082203d63cbe4f0fe86d9be16bf4f3b2444653dac6bb61d82e0f4f6b4214","src/std_error.rs":"25a07149e2e468747ffa5a58051c7f93d7b3c0fa0372f012a96c97ec8ab03b97"},"package":"0b114498256798c94a0689e1a15fec6005dee8ac1f41de56404b67afc2a4b773"}

View File

@ -13,7 +13,7 @@
edition = "2018"
rust-version = "1.31"
name = "serde"
version = "1.0.193"
version = "1.0.194"
authors = [
"Erick Tryzelaar <erick.tryzelaar@gmail.com>",
"David Tolnay <dtolnay@gmail.com>",
@ -74,4 +74,4 @@ std = []
unstable = []
[target."cfg(any())".dependencies.serde_derive]
version = "=1.0.193"
version = "=1.0.194"

View File

@ -64,8 +64,8 @@
//! - RefCell\<T\>
//! - Mutex\<T\>
//! - RwLock\<T\>
//! - Rc\<T\>&emsp;*(if* features = ["rc"] *is enabled)*
//! - Arc\<T\>&emsp;*(if* features = ["rc"] *is enabled)*
//! - Rc\<T\>&emsp;*(if* features = \["rc"\] *is enabled)*
//! - Arc\<T\>&emsp;*(if* features = \["rc"\] *is enabled)*
//! - **Collection types**:
//! - BTreeMap\<K, V\>
//! - BTreeSet\<T\>

View File

@ -95,7 +95,7 @@
////////////////////////////////////////////////////////////////////////////////
// Serde types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/serde/1.0.193")]
#![doc(html_root_url = "https://docs.rs/serde/1.0.194")]
// Support using Serde without the standard library!
#![cfg_attr(not(feature = "std"), no_std)]
// Show which crate feature enables conditionally compiled APIs in documentation.
@ -122,7 +122,6 @@
// things are often more readable this way
clippy::cast_lossless,
clippy::module_name_repetitions,
clippy::option_if_let_else,
clippy::single_match_else,
clippy::type_complexity,
clippy::use_self,

View File

@ -61,8 +61,8 @@
//! - RefCell\<T\>
//! - Mutex\<T\>
//! - RwLock\<T\>
//! - Rc\<T\>&emsp;*(if* features = ["rc"] *is enabled)*
//! - Arc\<T\>&emsp;*(if* features = ["rc"] *is enabled)*
//! - Rc\<T\>&emsp;*(if* features = \["rc"\] *is enabled)*
//! - Arc\<T\>&emsp;*(if* features = \["rc"\] *is enabled)*
//! - **Collection types**:
//! - BTreeMap\<K, V\>
//! - BTreeSet\<T\>

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"e1855acc71acc2ca2c973f774d5942b647b954cfcc509832e828e22d7cb96cfa","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"c3ece10a36d19b4e857a770eaf74a2164d220f55fa11947065a3898c1697ecef","crates-io.md":"56e988ac4944c45f5bf5051e3827892ed8fb817853d99d9df1fff6621108e270","src/bound.rs":"1b4504ae82ec3dc287eeb4262a57380af484f483c1d6b6c8ebb121370fda135a","src/de.rs":"c221ab2b94a5d80dccff74a37f3448b3d695656552b452595dc289c73b12fb2b","src/dummy.rs":"9533dfee23f20d92ea75734c739022820c2787ded0d54f459feacdeb770ec912","src/fragment.rs":"6757cb4c3131d4300f093572efc273c4ab5a20e3e1efb54a311dcfa52d0bd6eb","src/internals/ast.rs":"7dc997e4090033bbd1d0bdd870e8bb87b096b7f66cfd02047f6b85ebdd569b12","src/internals/attr.rs":"7ec05ffad5b049ba2c91cfb9eedc5d472030682d9c8bcd81040f646525dcc7cd","src/internals/case.rs":"10c8dda2b32d8c6c6b63cf09cdc63d02375af7e95ecefe8fecb34f93b65191bb","src/internals/check.rs":"d842eb9912fd29311060b67f3bc62c438eb7b5d86093355acb4de7eee02a0ef8","src/internals/ctxt.rs":"83a4e6fbe0e439d578478883594407e03f2f340541be479bdf0b04a202633a37","src/internals/mod.rs":"ed021ca635c18132a0e5c3d90f21b7f65def0a61e946421a30200b5b9ab6ad43","src/internals/receiver.rs":"105d72145d1e6a45cdccee3694fcba599ece59194d2e070e8c5669c6f18c81da","src/internals/respan.rs":"899753859c58ce5f532a3ec4584796a52f13ed5a0533191e48c953ba5c1b52ff","src/internals/symbol.rs":"d619e88caa3c7a09b03014257f2b349ee922290062d9b97b4dd19d0e64532690","src/lib.rs":"9b755f1f68c5e18fb7be0ab32dd56dd4be2f919826fe1a9d3830c01a23662e52","src/pretend.rs":"2c79785bc42e975534d7d88c04b46377cefd3db948b63a32234707531c55b099","src/ser.rs":"e3341471cea9d7e2fb4043e5d1746862beb9a4e25196170879eeac529d460920","src/this.rs":"87818dc80cbb521b51938a653d09daf10aafc220bb10425948de82ad670fcb85"},"package":"43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"}
{"files":{"Cargo.toml":"6edb5218a4acfe9c7a8934931364e42e79afa74cb3c526bb88cbe954dfafe508","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"c3ece10a36d19b4e857a770eaf74a2164d220f55fa11947065a3898c1697ecef","crates-io.md":"56e988ac4944c45f5bf5051e3827892ed8fb817853d99d9df1fff6621108e270","src/bound.rs":"1b4504ae82ec3dc287eeb4262a57380af484f483c1d6b6c8ebb121370fda135a","src/de.rs":"c221ab2b94a5d80dccff74a37f3448b3d695656552b452595dc289c73b12fb2b","src/dummy.rs":"9533dfee23f20d92ea75734c739022820c2787ded0d54f459feacdeb770ec912","src/fragment.rs":"6757cb4c3131d4300f093572efc273c4ab5a20e3e1efb54a311dcfa52d0bd6eb","src/internals/ast.rs":"7dc997e4090033bbd1d0bdd870e8bb87b096b7f66cfd02047f6b85ebdd569b12","src/internals/attr.rs":"7ec05ffad5b049ba2c91cfb9eedc5d472030682d9c8bcd81040f646525dcc7cd","src/internals/case.rs":"10c8dda2b32d8c6c6b63cf09cdc63d02375af7e95ecefe8fecb34f93b65191bb","src/internals/check.rs":"d842eb9912fd29311060b67f3bc62c438eb7b5d86093355acb4de7eee02a0ef8","src/internals/ctxt.rs":"83a4e6fbe0e439d578478883594407e03f2f340541be479bdf0b04a202633a37","src/internals/mod.rs":"ed021ca635c18132a0e5c3d90f21b7f65def0a61e946421a30200b5b9ab6ad43","src/internals/receiver.rs":"105d72145d1e6a45cdccee3694fcba599ece59194d2e070e8c5669c6f18c81da","src/internals/respan.rs":"899753859c58ce5f532a3ec4584796a52f13ed5a0533191e48c953ba5c1b52ff","src/internals/symbol.rs":"d619e88caa3c7a09b03014257f2b349ee922290062d9b97b4dd19d0e64532690","src/lib.rs":"5007fb78556e468731d63f2e5973714a8c11bfa74ec593e6309913737f7e1861","src/pretend.rs":"2c79785bc42e975534d7d88c04b46377cefd3db948b63a32234707531c55b099","src/ser.rs":"e3341471cea9d7e2fb4043e5d1746862beb9a4e25196170879eeac529d460920","src/this.rs":"87818dc80cbb521b51938a653d09daf10aafc220bb10425948de82ad670fcb85"},"package":"a3385e45322e8f9931410f01b3031ec534c3947d0e94c18049af4d9f9907d4e0"}

View File

@ -12,7 +12,7 @@
[package]
rust-version = "1.56"
name = "serde_derive"
version = "1.0.193"
version = "1.0.194"
authors = [
"Erick Tryzelaar <erick.tryzelaar@gmail.com>",
"David Tolnay <dtolnay@gmail.com>",
@ -43,13 +43,13 @@ name = "serde_derive"
proc-macro = true
[dependencies.proc-macro2]
version = "1.0"
version = "1.0.74"
[dependencies.quote]
version = "1.0"
version = "1.0.35"
[dependencies.syn]
version = "2.0.28"
version = "2.0.46"
[dev-dependencies.serde]
version = "1"

View File

@ -13,7 +13,7 @@
//!
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.193")]
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.194")]
// Ignored clippy lints
#![allow(
// clippy false positive: https://github.com/rust-lang/rust-clippy/issues/7054
@ -50,7 +50,6 @@
clippy::match_wildcard_for_single_variants,
clippy::module_name_repetitions,
clippy::must_use_candidate,
clippy::option_if_let_else,
clippy::similar_names,
clippy::single_match_else,
clippy::struct_excessive_bools,

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"965504451cd792223d66d76e77778f823e5274acf1a06371815c6fcdc39cb602","README.md":"b2fb89fc821eb3ecb38a229ed3dfed36a2f30ba9338b3695ee6ce96eab438d60","autogen_spirv.rs":"6408f8408001fd1012e2731a737cb08f032114b390c3cf10d813ab89a7c84c03","lib.rs":"334f71db6c449cbea3c6f7485abf9c8b91be968e532758ead3a7a834f1284440","release.toml":"acbbc8f28fd56745b98909e9f0928d97cdadeab242652a8596e716fe6d405b5e"},"package":"246bfa38fe3db3f1dfc8ca5a2cdeb7348c78be2112740cc0ec8ef18b6d94f830"}
{"files":{"Cargo.toml":"29fbbbc568f51d6ab5154843bdd673427f083c459db8c6d366ec8f2078c39431","README.md":"d0a33acc70ea5212e5fc6b5d5c88db60b38753b2591f67ebf06644aa13d6e631","autogen_spirv.rs":"236bd685f9eb20b9a82a6c0fef1553a6365b24a7848ae2b681df3c1528edc080","lib.rs":"334f71db6c449cbea3c6f7485abf9c8b91be968e532758ead3a7a834f1284440","release.toml":"a9c4eb6eaa1b3b8eb7ff742ec4963be32ec1ec7664c8a52218cc74898bad3ec4"},"package":"eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844"}

View File

@ -3,33 +3,34 @@
# 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
# 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)
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2018"
name = "spirv"
version = "0.2.0+1.5.4"
version = "0.3.0+sdk-1.3.268.0"
authors = ["Lei Zhang <antiagainst@gmail.com>"]
description = "Rust definition of SPIR-V structs and enums"
documentation = "https://docs.rs/spirv"
readme = "README.md"
keywords = ["spirv", "definition", "struct", "enum"]
keywords = [
"spirv",
"definition",
"struct",
"enum",
]
license = "Apache-2.0"
repository = "https://github.com/gfx-rs/rspirv"
[lib]
path = "lib.rs"
[dependencies.bitflags]
version = "1"
[dependencies.num-traits]
version = "0.2"
default-features = false
[dependencies.bitflags]
version = "2.0"
[dependencies.serde]
version = "1"
@ -37,5 +38,11 @@ features = ["derive"]
optional = true
[features]
deserialize = ["serde"]
serialize = ["serde"]
deserialize = [
"serde",
"bitflags/serde",
]
serialize = [
"serde",
"bitflags/serde",
]

View File

@ -18,7 +18,7 @@ First add to your `Cargo.toml`:
```toml
[dependencies]
spirv = "0.2.0+1.5.4"
spirv = "0.3.0"
```
Version

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,11 @@
pre-release-commit-message = "Release {{crate_name}} {{version}}"
no-dev-version = true
tag-message = "Release {{crate_name}} {{version}}"
tag-name = "{{crate_name}}-{{version}}"
sign-commit = true
sign-tag = true
publish = false
pre-release-replacements = [
{file="README.md", search="spirv = .*", replace="{{crate_name}} = \"{{version}}\""},
{file="../rspirv/Cargo.toml", search="spirv = \\{ version = \".*\", path = \"../spirv\" \\}", replace="{{crate_name}} = { version = \"{{version}}\", path = \"../spirv\" }" },
]

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"f7d6539341f7ff8362c314e0c1b9bf95eea7dad87af191e28bc30e3c53de28fd","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","src/any_surface.rs":"c5e961783be28548681c3c38579ea0b5724c5336848216a423e83a0db2208ece","src/binding_model.rs":"ad6667fd22e3a56fb09d35f077a1d94203c0d1ef36832492971a8143ad109ca2","src/command/bind.rs":"fcfbefdbdde10a1add947308ef3e80ed2acd8b6459bc7e0c25b0bbb38b1144ff","src/command/bundle.rs":"db63658fb05d548d593599e3fa0fb9c42f56419e35d97b56011c913c906c7c13","src/command/clear.rs":"f7a1c3374949885652fde94658a14e09dac84fc41d58c352e585c764d9a14f3c","src/command/compute.rs":"c393569da1377e136180560dbc19b1314b6527ae0e0cb2834a9222052f9bffce","src/command/draw.rs":"79db78560c6046f309f103f224750260ff926550846336bebd186252b4732fbc","src/command/memory_init.rs":"9c982099046ee174e1574d3f841e712831a84dd0948ebe2ffcb51e01c5104fa7","src/command/mod.rs":"dd22c5eab57f6f03373c41bfda2a55666ee61dfb2482a1126f959a48d0ad81c8","src/command/query.rs":"8c21df7d24e49664f70b364bd9daf575bebe5c17a456f346f0a98d4e6c810636","src/command/render.rs":"795fd6e78e91ee6f4f54856cdddbb680745d0accda802533f88e205de135436a","src/command/transfer.rs":"6012000a420c2e177c00a6df91b15ac58e947f5422d67bb8db5843a2a3fff134","src/conv.rs":"7e3ffe33b47a6fd3617aabf9f11cc68f1ccbee2c7343b8dbbcd0e8f3447e1ad8","src/device/any_device.rs":"2cb2be0fd078d65039692d309d8688cf4a02fb768579cf22c93cfa514d20ad7f","src/device/global.rs":"ed1580f15bdec3927b736101b78dc34fec40d92ed4ead15a0e1b5f70e72d5675","src/device/life.rs":"9c9d2c21852bc1b9e133bfdea33b89abbbe9d849ad5c00d09863fe5594792e40","src/device/mod.rs":"45ad9b826f296cbef9470c3cfc705f832198587b45847ddd0ea4ddd5eb55f7eb","src/device/queue.rs":"7ec005a04371d0cb191bc067074ac83f95dc751e5f1145e1cb7935b76b2b3716","src/device/resource.rs":"396bfda6c181826288484426f4fa170376256e1d29df916e1f265d2397e5987d","src/device/trace.rs":"9a8ec674567a8866a6bd1ed2ad06e474bd2504ed91f228d3040cb6db18fe5f2b","src/error.rs":"32680e922acfb1f1d6842177179768d365c575a8baa402da9d5a43a2357b0dbf","src/global.rs":"c0a590e0136bf19a63ddc87dd3f0bbfbe24bcb810d0ccfc6c5f26631750d63ea","src/hal_api.rs":"3ee0f5e66b313fd1b8c79b3d73f0f1dbde88676b651d79518fa2dc5aff0ab856","src/hub.rs":"4cec8de74a661bb628040ff457d38faf8c92d0824c4d5a4955834d56ebd25926","src/id.rs":"2c73422b2b5f0ce4a5bc3fce79bb3d3a370cda7aa6680c2239829ffc5a85d869","src/identity.rs":"0701f6f41e754dde2bebc567a87c25b353dfab40b79a322990dbfa477739ab8c","src/init_tracker/buffer.rs":"61eb9cfaa312135b7a937ff6a3117f531b5b7323fae6553a41d6de9bc106d7e0","src/init_tracker/mod.rs":"0867f79f83555390d0982d1dc6dcf0d4340e10cb89aa633d3c3ecc45deb3c78c","src/init_tracker/texture.rs":"030fd594bf9948fad391390d85c5e1fec7eaf67b6e812c60f2dd59bc4fda8fd5","src/instance.rs":"e1d4af51bb445850d9e2d7d12b239413bb555f07f95d3a1851cc73443c5c18f0","src/lib.rs":"ab61469bc2d9bdcc47b73435a0d438ba413c5619ab653180a56e8e2aefe93c74","src/pipeline.rs":"bd6e242f0f5408da0a675066092129281aadd5ab0051c036821b34c17992c1da","src/present.rs":"7751da30b27eed7521be7af166c6a07468eda47bf96206082cc33df6f77ec0d8","src/registry.rs":"c259ca61dd5f2b632ff2ee871f82727921fa48dee15253872799af1dda77484b","src/resource.rs":"e3c22585dd85dc79a4c5b50a7302392421bfc16dbac6de14592440deeeb7ee8a","src/snatch.rs":"2de558dda543329d70be35ed72dffdeba816814f6f0059d720a568abd47e40a7","src/storage.rs":"02be927de5c85f5f59a1c847bbdc8e9e02fb976c39fb7e3078a8f9fbff929934","src/track/buffer.rs":"c5ae73d1d84bcfb5a17c31f43de661cd0bf931e15e9fd92ad18fd31a88b05330","src/track/metadata.rs":"f8994ad91db7f3bb1b7f8b8b0f6884753d733ce28238b36f31da2230706f848e","src/track/mod.rs":"25015210f4f960f1daf4891a13d5b6ac48aad87cbc158a0bcdb1f718219f6e20","src/track/range.rs":"2a15794e79b0470d5ba6b3267173a42f34312878e1cb288f198d2854a7888e53","src/track/stateless.rs":"43ec668f56c962f255b900a773a537dde1c21dd0b2e3804271786fb90e9cfffa","src/track/texture.rs":"d4e92ef3400cf48b2e76d8b7c1e4c6a1cef0d3d060c6abdb46b9a3b386bc9dc9","src/validation.rs":"6933c349d155f647778134696c53cbd641419a959505f2f0a3db31fcceefc8b4"},"package":null}
{"files":{"Cargo.toml":"f3ec42fd497e3fe2070ff1285713980e3a1b2c13e9dfb3eccb237baf68fa9954","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","src/any_surface.rs":"c5e961783be28548681c3c38579ea0b5724c5336848216a423e83a0db2208ece","src/binding_model.rs":"da0febe86a77cf3b6f958865af0cf07e1d0788a09e883030986a520360cc226a","src/command/bind.rs":"a37f042484b65d9fdea4cdab3667381623ee9a8943a6d32683d410b92736d306","src/command/bundle.rs":"db63658fb05d548d593599e3fa0fb9c42f56419e35d97b56011c913c906c7c13","src/command/clear.rs":"69b30b92c61ff4396243d3dc42fb46a187771d40af26f9ec1c631dc602f76daa","src/command/compute.rs":"c393569da1377e136180560dbc19b1314b6527ae0e0cb2834a9222052f9bffce","src/command/draw.rs":"79db78560c6046f309f103f224750260ff926550846336bebd186252b4732fbc","src/command/memory_init.rs":"9c982099046ee174e1574d3f841e712831a84dd0948ebe2ffcb51e01c5104fa7","src/command/mod.rs":"74d7dffe3fc3d504feb85dad0c73a06ea7bfbe4311f86e96f9390c2c974dcb03","src/command/query.rs":"8c21df7d24e49664f70b364bd9daf575bebe5c17a456f346f0a98d4e6c810636","src/command/render.rs":"5f271a6f2705e31b2ca90e88ec858ae81a714c5b4a51491890ebed45c1ce1287","src/command/transfer.rs":"0d2e2c397bc8830d8e84d84d0708413954ed7c4594e22c66d2b65255ccab68d7","src/conv.rs":"7e3ffe33b47a6fd3617aabf9f11cc68f1ccbee2c7343b8dbbcd0e8f3447e1ad8","src/device/any_device.rs":"2cb2be0fd078d65039692d309d8688cf4a02fb768579cf22c93cfa514d20ad7f","src/device/bgl.rs":"292a0f07121aec78e86e0125d08785072bd4b7e763c99975b581b342ac4fcaa3","src/device/global.rs":"4bbcabe510572e3c405475117ae005a7563a5d47d4ac0b2225b7a5443e8939a7","src/device/life.rs":"3829f0cdba9b5476acd2e108fc0373b8ac2d2a6feed01c5653df9e87cb16f39c","src/device/mod.rs":"4d15b1d1ab3b90ca8d953fad062263f129d0338d493abcc5ffe65caf2d038674","src/device/queue.rs":"18769043c85a07909741a67dc3a7e303db490a623cc1a0448563818668300e3c","src/device/resource.rs":"88a0c3f1036ccd69efe2d62b494286bacab8b56e9fe969b61a58a8c07693b358","src/device/trace.rs":"9a8ec674567a8866a6bd1ed2ad06e474bd2504ed91f228d3040cb6db18fe5f2b","src/error.rs":"32680e922acfb1f1d6842177179768d365c575a8baa402da9d5a43a2357b0dbf","src/global.rs":"c0a590e0136bf19a63ddc87dd3f0bbfbe24bcb810d0ccfc6c5f26631750d63ea","src/hal_api.rs":"3ee0f5e66b313fd1b8c79b3d73f0f1dbde88676b651d79518fa2dc5aff0ab856","src/hash_utils.rs":"e8d484027c7ce81978e4679a5e20af9416ab7d2fa595f1ca95992b29d625b0ca","src/hub.rs":"4cec8de74a661bb628040ff457d38faf8c92d0824c4d5a4955834d56ebd25926","src/id.rs":"2c73422b2b5f0ce4a5bc3fce79bb3d3a370cda7aa6680c2239829ffc5a85d869","src/identity.rs":"0701f6f41e754dde2bebc567a87c25b353dfab40b79a322990dbfa477739ab8c","src/init_tracker/buffer.rs":"61eb9cfaa312135b7a937ff6a3117f531b5b7323fae6553a41d6de9bc106d7e0","src/init_tracker/mod.rs":"0867f79f83555390d0982d1dc6dcf0d4340e10cb89aa633d3c3ecc45deb3c78c","src/init_tracker/texture.rs":"030fd594bf9948fad391390d85c5e1fec7eaf67b6e812c60f2dd59bc4fda8fd5","src/instance.rs":"e1d4af51bb445850d9e2d7d12b239413bb555f07f95d3a1851cc73443c5c18f0","src/lib.rs":"082cf63acb7099ca2597d6bdd756c11782e4e39064da74b06000c99d5d7fdb85","src/pipeline.rs":"e3a8d4bc0a60d2ad647b8062798be2af387099b3af42214f180e6cebae3d807c","src/pool.rs":"8c88d86763bc465bf628157c62db9641f6789ece684cc4a20a2fdf50d37e0e16","src/present.rs":"c419d81f2d8814c6af4460ed4d03b4485b57743c3d2a52a50ab7c3d3c6f21968","src/registry.rs":"ffa4029aaf8ed980bd2b61d056a7ec32099f5c2e1d85f3b9f1861baa34ac488c","src/resource.rs":"84e96b5944bd776af5019fd64afef739bc5facb99e089a71f070922fd61af60a","src/snatch.rs":"dd514e1954137eec4a0753a3670e8180796ac9c9ff770a1ca1813863debce823","src/storage.rs":"9ef4ee85e321fee73a50f21d0932f1a2ae08515b0e1d6be207f330e4ea59d1b6","src/track/buffer.rs":"c5ae73d1d84bcfb5a17c31f43de661cd0bf931e15e9fd92ad18fd31a88b05330","src/track/metadata.rs":"f8994ad91db7f3bb1b7f8b8b0f6884753d733ce28238b36f31da2230706f848e","src/track/mod.rs":"02bac3cf2e53af45f79646817e85da8e4072d576438036a44b41ce1744e02d64","src/track/range.rs":"2a15794e79b0470d5ba6b3267173a42f34312878e1cb288f198d2854a7888e53","src/track/stateless.rs":"43ec668f56c962f255b900a773a537dde1c21dd0b2e3804271786fb90e9cfffa","src/track/texture.rs":"769d87975b2fa0f6ca5794b7eaa203b2d6a00dea452783e6105ca7daf141490f","src/validation.rs":"613c58c3601f36d6aa5986cea01f30497c6bd4ceb990824904d101b2327941a9"},"package":null}

View File

@ -41,7 +41,9 @@ arrayvec = "0.7"
bit-vec = "0.6"
bitflags = "2"
codespan-reporting = "0.11"
indexmap = "2"
log = "0.4"
once_cell = "1"
parking_lot = ">=0.11,<0.13"
rustc-hash = "1.1"
smallvec = "1"

View File

@ -1,5 +1,7 @@
use crate::{
device::{Device, DeviceError, MissingDownlevelFlags, MissingFeatures, SHADER_STAGE_COUNT},
device::{
bgl, Device, DeviceError, MissingDownlevelFlags, MissingFeatures, SHADER_STAGE_COUNT,
},
error::{ErrorFormatter, PrettyError},
hal_api::HalApi,
id::{
@ -12,7 +14,7 @@ use crate::{
snatch::SnatchGuard,
track::{BindGroupStates, UsageConflict},
validation::{MissingBufferUsageError, MissingTextureUsageError},
FastHashMap, Label,
Label,
};
use arrayvec::ArrayVec;
@ -440,32 +442,32 @@ pub struct BindGroupLayoutDescriptor<'a> {
pub entries: Cow<'a, [wgt::BindGroupLayoutEntry]>,
}
pub(crate) type BindEntryMap = FastHashMap<u32, wgt::BindGroupLayoutEntry>;
pub type BindGroupLayouts<A> = crate::storage::Storage<BindGroupLayout<A>, BindGroupLayoutId>;
/// Bind group layout.
///
/// The lifetime of BGLs is a bit special. They are only referenced on CPU
/// without considering GPU operations. And on CPU they get manual
/// inc-refs and dec-refs. In particular, the following objects depend on them:
/// - produced bind groups
/// - produced pipeline layouts
/// - pipelines with implicit layouts
#[derive(Debug)]
pub struct BindGroupLayout<A: HalApi> {
pub(crate) raw: Option<A::BindGroupLayout>,
pub(crate) device: Arc<Device<A>>,
pub(crate) entries: BindEntryMap,
pub(crate) entries: bgl::EntryMap,
/// It is very important that we know if the bind group comes from the BGL pool.
///
/// If it does, then we need to remove it from the pool when we drop it.
///
/// We cannot unconditionally remove from the pool, as BGLs that don't come from the pool
/// (derived BGLs) must not be removed.
pub(crate) origin: bgl::Origin,
#[allow(unused)]
pub(crate) dynamic_count: usize,
pub(crate) count_validator: BindingTypeMaxCountValidator,
pub(crate) binding_count_validator: BindingTypeMaxCountValidator,
pub(crate) info: ResourceInfo<BindGroupLayoutId>,
pub(crate) label: String,
}
impl<A: HalApi> Drop for BindGroupLayout<A> {
fn drop(&mut self) {
if matches!(self.origin, bgl::Origin::Pool) {
self.device.bgl_pool.remove(&self.entries);
}
if let Some(raw) = self.raw.take() {
resource_log!("Destroy raw BindGroupLayout {:?}", self.info.label());
unsafe {
@ -618,6 +620,14 @@ impl<A: HalApi> PipelineLayout<A> {
pub(crate) fn raw(&self) -> &A::PipelineLayout {
self.raw.as_ref().unwrap()
}
pub(crate) fn get_binding_maps(&self) -> ArrayVec<&bgl::EntryMap, { hal::MAX_BIND_GROUPS }> {
self.bind_group_layouts
.iter()
.map(|bgl| &bgl.entries)
.collect()
}
/// Validate push constants match up with expected ranges.
pub(crate) fn validate_push_constant_ranges(
&self,
@ -837,11 +847,14 @@ impl<A: HalApi> Drop for BindGroup<A> {
impl<A: HalApi> BindGroup<A> {
pub(crate) fn raw(&self, guard: &SnatchGuard) -> Option<&A::BindGroup> {
// Clippy insist on writing it this way. The idea is to return None
// if any of the raw buffer is not valid anymore.
for buffer in &self.used_buffer_ranges {
// Clippy insist on writing it this way. The idea is to return None
// if any of the raw buffer is not valid anymore.
let _ = buffer.buffer.raw(guard)?;
}
for texture in &self.used_texture_ranges {
let _ = texture.texture.raw(guard)?;
}
self.raw.as_ref()
}
pub(crate) fn validate_dynamic_bindings(

View File

@ -16,7 +16,7 @@ type BindGroupMask = u8;
mod compat {
use arrayvec::ArrayVec;
use crate::{binding_model::BindGroupLayout, hal_api::HalApi, resource::Resource};
use crate::{binding_model::BindGroupLayout, device::bgl, hal_api::HalApi, resource::Resource};
use std::{ops::Range, sync::Arc};
#[derive(Debug, Clone)]
@ -60,17 +60,35 @@ mod compat {
let mut diff = Vec::new();
if let Some(expected_bgl) = self.expected.as_ref() {
let expected_bgl_type = match expected_bgl.origin {
bgl::Origin::Derived => "implicit",
bgl::Origin::Pool => "explicit",
};
let expected_label = expected_bgl.label();
diff.push(format!(
"Should be compatible with bind group layout with label = `{}`",
expected_bgl.label()
"Should be compatible an with an {expected_bgl_type} bind group layout {}",
if expected_label.is_empty() {
"without label".to_string()
} else {
format!("with label = `{}`", expected_label)
}
));
if let Some(assigned_bgl) = self.assigned.as_ref() {
let assigned_bgl_type = match assigned_bgl.origin {
bgl::Origin::Derived => "implicit",
bgl::Origin::Pool => "explicit",
};
let assigned_label = assigned_bgl.label();
diff.push(format!(
"Assigned bind group layout with label = `{}`",
assigned_bgl.label()
"Assigned {assigned_bgl_type} bind group layout {}",
if assigned_label.is_empty() {
"without label".to_string()
} else {
format!("with label = `{}`", assigned_label)
}
));
for (id, e_entry) in &expected_bgl.entries {
if let Some(a_entry) = assigned_bgl.entries.get(id) {
for (id, e_entry) in expected_bgl.entries.iter() {
if let Some(a_entry) = assigned_bgl.entries.get(*id) {
if a_entry.binding != e_entry.binding {
diff.push(format!(
"Entry {id} binding expected {}, got {}",
@ -96,32 +114,28 @@ mod compat {
));
}
} else {
diff.push(format!("Entry {id} not found in assigned bindgroup layout"))
diff.push(format!(
"Entry {id} not found in assigned bind group layout"
))
}
}
assigned_bgl.entries.iter().for_each(|(id, _e_entry)| {
if !expected_bgl.entries.contains_key(id) {
diff.push(format!("Entry {id} not found in expected bindgroup layout"))
if !expected_bgl.entries.contains_key(*id) {
diff.push(format!(
"Entry {id} not found in expected bind group layout"
))
}
});
} else {
diff.push(
"Assigned bindgroup layout is implicit, expected explicit".to_owned(),
);
}
} else if let Some(assigned_bgl) = self.assigned.as_ref() {
diff.push(format!(
"Assigned bind group layout = `{}`",
assigned_bgl.label()
));
diff.push(
"Assigned bindgroup layout is not implicit, expected implicit".to_owned(),
);
}
if diff.is_empty() {
diff.push("But no differences found? (internal error)".to_owned())
if expected_bgl.origin != assigned_bgl.origin {
diff.push(format!("Expected {expected_bgl_type} bind group layout, got {assigned_bgl_type}"))
}
} else {
diff.push("Assigned bind group layout not found (internal error)".to_owned());
}
} else {
diff.push("Expected bind group layout not found (internal error)".to_owned());
}
diff

View File

@ -252,11 +252,9 @@ pub(crate) fn clear_texture<A: HalApi>(
alignments: &hal::Alignments,
zero_buffer: &A::Buffer,
) -> Result<(), ClearError> {
let dst_inner = dst_texture.inner();
let dst_raw = dst_inner
.as_ref()
.unwrap()
.as_raw()
let snatch_guard = dst_texture.device.snatchable_lock.read();
let dst_raw = dst_texture
.raw(&snatch_guard)
.ok_or_else(|| ClearError::InvalidTexture(dst_texture.as_info().id()))?;
// Issue the right barrier.
@ -296,7 +294,7 @@ pub(crate) fn clear_texture<A: HalApi>(
let dst_barrier = texture_tracker
.set_single(dst_texture, selector, clear_usage)
.unwrap()
.map(|pending| pending.into_hal(dst_inner.as_ref().unwrap()));
.map(|pending| pending.into_hal(dst_raw));
unsafe {
encoder.transition_textures(dst_barrier.into_iter());
}

View File

@ -226,11 +226,11 @@ impl<A: HalApi> CommandBuffer<A> {
profiling::scope!("drain_barriers");
let buffer_barriers = base.buffers.drain_transitions(snatch_guard);
let (transitions, textures) = base.textures.drain_transitions();
let (transitions, textures) = base.textures.drain_transitions(snatch_guard);
let texture_barriers = transitions
.into_iter()
.enumerate()
.map(|(i, p)| p.into_hal(textures[i].as_ref().unwrap()));
.map(|(i, p)| p.into_hal(textures[i].unwrap().raw().unwrap()));
unsafe {
raw.transition_buffers(buffer_barriers);

View File

@ -2370,12 +2370,12 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
(trackers, pending_discard_init_fixups)
};
let query_set_guard = hub.query_sets.read();
let cmd_buf = hub.command_buffers.get(encoder_id).unwrap();
let mut cmd_buf_data = cmd_buf.data.lock();
let cmd_buf_data = cmd_buf_data.as_mut().unwrap();
let query_set_guard = hub.query_sets.read();
let encoder = &mut cmd_buf_data.encoder;
let status = &mut cmd_buf_data.status;
let tracker = &mut cmd_buf_data.trackers;

View File

@ -15,7 +15,6 @@ use crate::{
TextureInitTrackerAction,
},
resource::{Resource, Texture, TextureErrorDimension},
storage::Storage,
track::{TextureSelector, Tracker},
};
@ -24,7 +23,7 @@ use hal::CommandEncoder as _;
use thiserror::Error;
use wgt::{BufferAddress, BufferUsages, Extent3d, TextureUsages};
use std::iter;
use std::{iter, sync::Arc};
use super::{memory_init::CommandBufferTextureMemoryActions, CommandEncoder};
@ -447,9 +446,8 @@ fn handle_texture_init<A: HalApi>(
device: &Device<A>,
copy_texture: &ImageCopyTexture,
copy_size: &Extent3d,
texture_guard: &Storage<Texture<A>, TextureId>,
texture: &Arc<Texture<A>>,
) {
let texture = texture_guard.get(copy_texture.texture).unwrap();
let init_action = TextureInitTrackerAction {
texture: texture.clone(),
range: TextureInitRange {
@ -494,12 +492,8 @@ fn handle_src_texture_init<A: HalApi>(
device: &Device<A>,
source: &ImageCopyTexture,
copy_size: &Extent3d,
texture_guard: &Storage<Texture<A>, TextureId>,
texture: &Arc<Texture<A>>,
) -> Result<(), TransferError> {
let _ = texture_guard
.get(source.texture)
.map_err(|_| TransferError::InvalidTexture(source.texture))?;
handle_texture_init(
MemoryInitKind::NeedsInitializedMemory,
encoder,
@ -508,7 +502,7 @@ fn handle_src_texture_init<A: HalApi>(
device,
source,
copy_size,
texture_guard,
texture,
);
Ok(())
}
@ -524,12 +518,8 @@ fn handle_dst_texture_init<A: HalApi>(
device: &Device<A>,
destination: &ImageCopyTexture,
copy_size: &Extent3d,
texture_guard: &Storage<Texture<A>, TextureId>,
texture: &Arc<Texture<A>>,
) -> Result<(), TransferError> {
let texture = texture_guard
.get(destination.texture)
.map_err(|_| TransferError::InvalidTexture(destination.texture))?;
// Attention: If we don't write full texture subresources, we need to a full
// clear first since we don't track subrects. This means that in rare cases
// even a *destination* texture of a transfer may need an immediate texture
@ -552,7 +542,7 @@ fn handle_dst_texture_init<A: HalApi>(
device,
destination,
copy_size,
texture_guard,
texture,
);
Ok(())
}
@ -764,14 +754,13 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let buffer_memory_init_actions = &mut cmd_buf_data.buffer_memory_init_actions;
let texture_memory_actions = &mut cmd_buf_data.texture_memory_actions;
let texture_guard = hub.textures.read();
if copy_size.width == 0 || copy_size.height == 0 || copy_size.depth_or_array_layers == 0 {
log::trace!("Ignoring copy_buffer_to_texture of size 0");
return Ok(());
}
let dst_texture = texture_guard
let dst_texture = hub
.textures
.get(destination.texture)
.map_err(|_| TransferError::InvalidTexture(destination.texture))?;
@ -782,7 +771,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
copy_size,
)?;
let (dst_range, dst_base) = extract_texture_selector(destination, copy_size, dst_texture)?;
let (dst_range, dst_base) = extract_texture_selector(destination, copy_size, &dst_texture)?;
// Handle texture init *before* dealing with barrier transitions so we
// have an easier time inserting "immediate-inits" that may be required
@ -794,7 +783,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
device,
destination,
copy_size,
&texture_guard,
&dst_texture,
)?;
let snatch_guard = device.snatchable_lock.read();
@ -820,20 +809,17 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let dst_pending = tracker
.textures
.set_single(dst_texture, dst_range, hal::TextureUses::COPY_DST)
.set_single(&dst_texture, dst_range, hal::TextureUses::COPY_DST)
.ok_or(TransferError::InvalidTexture(destination.texture))?;
let dst_inner = dst_texture.inner();
let dst_raw = dst_inner
.as_ref()
.unwrap()
.as_raw()
let dst_raw = dst_texture
.raw(&snatch_guard)
.ok_or(TransferError::InvalidTexture(destination.texture))?;
if !dst_texture.desc.usage.contains(TextureUsages::COPY_DST) {
return Err(
TransferError::MissingCopyDstUsageFlag(None, Some(destination.texture)).into(),
);
}
let dst_barrier = dst_pending.map(|pending| pending.into_hal(dst_inner.as_ref().unwrap()));
let dst_barrier = dst_pending.map(|pending| pending.into_hal(dst_raw));
if !dst_base.aspect.is_one() {
return Err(TransferError::CopyAspectNotOne.into());
@ -928,21 +914,20 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let buffer_memory_init_actions = &mut cmd_buf_data.buffer_memory_init_actions;
let texture_memory_actions = &mut cmd_buf_data.texture_memory_actions;
let texture_guard = hub.textures.read();
if copy_size.width == 0 || copy_size.height == 0 || copy_size.depth_or_array_layers == 0 {
log::trace!("Ignoring copy_texture_to_buffer of size 0");
return Ok(());
}
let src_texture = texture_guard
let src_texture = hub
.textures
.get(source.texture)
.map_err(|_| TransferError::InvalidTexture(source.texture))?;
let (hal_copy_size, array_layer_count) =
validate_texture_copy_range(source, &src_texture.desc, CopySide::Source, copy_size)?;
let (src_range, src_base) = extract_texture_selector(source, copy_size, src_texture)?;
let (src_range, src_base) = extract_texture_selector(source, copy_size, &src_texture)?;
// Handle texture init *before* dealing with barrier transitions so we
// have an easier time inserting "immediate-inits" that may be required
@ -954,20 +939,17 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
device,
source,
copy_size,
&texture_guard,
&src_texture,
)?;
let snatch_guard = device.snatchable_lock.read();
let src_pending = tracker
.textures
.set_single(src_texture, src_range, hal::TextureUses::COPY_SRC)
.set_single(&src_texture, src_range, hal::TextureUses::COPY_SRC)
.ok_or(TransferError::InvalidTexture(source.texture))?;
let src_inner = src_texture.inner();
let src_raw = src_inner
.as_ref()
.unwrap()
.as_raw()
let src_raw = src_texture
.raw(&snatch_guard)
.ok_or(TransferError::InvalidTexture(source.texture))?;
if !src_texture.desc.usage.contains(TextureUsages::COPY_SRC) {
return Err(TransferError::MissingCopySrcUsageFlag.into());
@ -985,7 +967,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
}
.into());
}
let src_barrier = src_pending.map(|pending| pending.into_hal(src_inner.as_ref().unwrap()));
let src_barrier = src_pending.map(|pending| pending.into_hal(src_raw));
let (dst_buffer, dst_pending) = {
let buffer_guard = hub.buffers.read();
@ -1089,6 +1071,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
return Err(TransferError::InvalidDevice(cmd_buf.device.as_info().id()).into());
}
let snatch_guard = device.snatchable_lock.read();
let mut cmd_buf_data = cmd_buf.data.lock();
let cmd_buf_data = cmd_buf_data.as_mut().unwrap();
@ -1104,21 +1088,19 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let tracker = &mut cmd_buf_data.trackers;
let texture_memory_actions = &mut cmd_buf_data.texture_memory_actions;
let texture_guard = hub.textures.read();
if copy_size.width == 0 || copy_size.height == 0 || copy_size.depth_or_array_layers == 0 {
log::trace!("Ignoring copy_texture_to_texture of size 0");
return Ok(());
}
let src_texture = texture_guard
let src_texture = hub
.textures
.get(source.texture)
.map_err(|_| TransferError::InvalidTexture(source.texture))?;
let src_inner = src_texture.inner();
let dst_texture = texture_guard
let dst_texture = hub
.textures
.get(destination.texture)
.map_err(|_| TransferError::InvalidTexture(source.texture))?;
let dst_inner = dst_texture.inner();
// src and dst texture format must be copy-compatible
// https://gpuweb.github.io/gpuweb/#copy-compatible
@ -1141,9 +1123,9 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
copy_size,
)?;
let (src_range, src_tex_base) = extract_texture_selector(source, copy_size, src_texture)?;
let (src_range, src_tex_base) = extract_texture_selector(source, copy_size, &src_texture)?;
let (dst_range, dst_tex_base) =
extract_texture_selector(destination, copy_size, dst_texture)?;
extract_texture_selector(destination, copy_size, &dst_texture)?;
let src_texture_aspects = hal::FormatAspects::from(src_texture.desc.format);
let dst_texture_aspects = hal::FormatAspects::from(dst_texture.desc.format);
if src_tex_base.aspect != src_texture_aspects {
@ -1163,7 +1145,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
device,
source,
copy_size,
&texture_guard,
&src_texture,
)?;
handle_dst_texture_init(
encoder,
@ -1172,18 +1154,16 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
device,
destination,
copy_size,
&texture_guard,
&dst_texture,
)?;
let src_pending = cmd_buf_data
.trackers
.textures
.set_single(src_texture, src_range, hal::TextureUses::COPY_SRC)
.set_single(&src_texture, src_range, hal::TextureUses::COPY_SRC)
.ok_or(TransferError::InvalidTexture(source.texture))?;
let src_raw = src_inner
.as_ref()
.unwrap()
.as_raw()
let src_raw = src_texture
.raw(&snatch_guard)
.ok_or(TransferError::InvalidTexture(source.texture))?;
if !src_texture.desc.usage.contains(TextureUsages::COPY_SRC) {
return Err(TransferError::MissingCopySrcUsageFlag.into());
@ -1192,18 +1172,16 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
//TODO: try to avoid this the collection. It's needed because both
// `src_pending` and `dst_pending` try to hold `trackers.textures` mutably.
let mut barriers: ArrayVec<_, 2> = src_pending
.map(|pending| pending.into_hal(src_inner.as_ref().unwrap()))
.map(|pending| pending.into_hal(src_raw))
.collect();
let dst_pending = cmd_buf_data
.trackers
.textures
.set_single(dst_texture, dst_range, hal::TextureUses::COPY_DST)
.set_single(&dst_texture, dst_range, hal::TextureUses::COPY_DST)
.ok_or(TransferError::InvalidTexture(destination.texture))?;
let dst_raw = dst_inner
.as_ref()
.unwrap()
.as_raw()
let dst_raw = dst_texture
.raw(&snatch_guard)
.ok_or(TransferError::InvalidTexture(destination.texture))?;
if !dst_texture.desc.usage.contains(TextureUsages::COPY_DST) {
return Err(
@ -1211,7 +1189,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
);
}
barriers.extend(dst_pending.map(|pending| pending.into_hal(dst_inner.as_ref().unwrap())));
barriers.extend(dst_pending.map(|pending| pending.into_hal(dst_raw)));
let hal_copy_size = hal::CopyExtent {
width: src_copy_size.width.min(dst_copy_size.width),

View File

@ -0,0 +1,129 @@
use std::hash::{Hash, Hasher};
use crate::{
binding_model::{self},
FastIndexMap,
};
/// Where a given BGL came from.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Origin {
/// The bind group layout was created by the user and is present in the BGL resource pool.
Pool,
/// The bind group layout was derived and is not present in the BGL resource pool.
Derived,
}
/// A HashMap-like structure that stores a BindGroupLayouts [`wgt::BindGroupLayoutEntry`]s.
///
/// It is hashable, so bind group layouts can be deduplicated.
#[derive(Debug, Default, Clone, Eq)]
pub struct EntryMap {
/// We use a IndexMap here so that we can sort the entries by their binding index,
/// guarenteeing that the hash of equivilant layouts will be the same.
inner: FastIndexMap<u32, wgt::BindGroupLayoutEntry>,
/// We keep track of whether the map is sorted or not, so that we can assert that
/// it is sorted, so that PartialEq and Hash will be stable.
///
/// We only need sorted if it is used in a Hash or PartialEq, so we never need
/// to actively sort it.
sorted: bool,
}
impl PartialEq for EntryMap {
fn eq(&self, other: &Self) -> bool {
self.assert_sorted();
other.assert_sorted();
self.inner == other.inner
}
}
impl Hash for EntryMap {
fn hash<H: Hasher>(&self, state: &mut H) {
self.assert_sorted();
// We don't need to hash the keys, since they are just extracted from the values.
//
// We know this is stable and will match the behavior of PartialEq as we ensure
// that the array is sorted.
for entry in self.inner.values() {
entry.hash(state);
}
}
}
impl EntryMap {
fn assert_sorted(&self) {
assert!(self.sorted);
}
/// Create a new [`BindGroupLayoutEntryMap`] from a slice of [`wgt::BindGroupLayoutEntry`]s.
///
/// Errors if there are duplicate bindings or if any binding index is greater than
/// the device's limits.
pub fn from_entries(
device_limits: &wgt::Limits,
entries: &[wgt::BindGroupLayoutEntry],
) -> Result<Self, binding_model::CreateBindGroupLayoutError> {
let mut inner = FastIndexMap::with_capacity_and_hasher(entries.len(), Default::default());
for entry in entries {
if entry.binding > device_limits.max_bindings_per_bind_group {
return Err(
binding_model::CreateBindGroupLayoutError::InvalidBindingIndex {
binding: entry.binding,
maximum: device_limits.max_bindings_per_bind_group,
},
);
}
if inner.insert(entry.binding, *entry).is_some() {
return Err(binding_model::CreateBindGroupLayoutError::ConflictBinding(
entry.binding,
));
}
}
inner.sort_unstable_keys();
Ok(Self {
inner,
sorted: true,
})
}
/// Get the count of [`wgt::BindGroupLayoutEntry`]s in this map.
pub fn len(&self) -> usize {
self.inner.len()
}
/// Get the [`wgt::BindGroupLayoutEntry`] for the given binding index.
pub fn get(&self, binding: u32) -> Option<&wgt::BindGroupLayoutEntry> {
self.inner.get(&binding)
}
/// Iterator over all the binding indices in this map.
pub fn indices(&self) -> impl ExactSizeIterator<Item = u32> + '_ {
self.inner.keys().copied()
}
/// Iterator over all the [`wgt::BindGroupLayoutEntry`]s in this map.
pub fn values(&self) -> impl ExactSizeIterator<Item = &wgt::BindGroupLayoutEntry> + '_ {
self.inner.values()
}
pub fn iter(&self) -> impl ExactSizeIterator<Item = (&u32, &wgt::BindGroupLayoutEntry)> + '_ {
self.inner.iter()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn contains_key(&self, key: u32) -> bool {
self.inner.contains_key(&key)
}
pub fn entry(&mut self, key: u32) -> indexmap::map::Entry<'_, u32, wgt::BindGroupLayoutEntry> {
self.sorted = false;
self.inner.entry(key)
}
}

View File

@ -3,8 +3,8 @@ use crate::device::trace;
use crate::{
api_log, binding_model, command, conv,
device::{
life::WaitIdleError, map_buffer, queue, DeviceError, DeviceLostClosure, DeviceLostReason,
HostMap, IMPLICIT_BIND_GROUP_LAYOUT_ERROR_LABEL,
bgl, life::WaitIdleError, map_buffer, queue, DeviceError, DeviceLostClosure,
DeviceLostReason, HostMap, IMPLICIT_BIND_GROUP_LAYOUT_ERROR_LABEL,
},
global::Global,
hal_api::HalApi,
@ -16,7 +16,7 @@ use crate::{
resource::{self, BufferAccessResult},
resource::{BufferAccessError, BufferMapOperation, CreateBufferError, Resource},
validation::check_buffer_usage,
FastHashMap, Label, LabelHelpers as _,
Label, LabelHelpers as _,
};
use arrayvec::ArrayVec;
@ -487,12 +487,11 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let hub = A::hub(self);
let buffer = {
let mut buffer_guard = hub.buffers.write();
buffer_guard
.get_and_mark_destroyed(buffer_id)
.map_err(|_| resource::DestroyError::Invalid)?
};
let buffer = hub
.buffers
.write()
.get_and_mark_destroyed(buffer_id)
.map_err(|_| resource::DestroyError::Invalid)?;
let _ = buffer.unmap();
@ -683,8 +682,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let fid = hub.buffers.prepare::<G>(id_in);
let error = loop {
let device_guard = hub.devices.read();
let device = match device_guard.get(device_id) {
let device = match hub.devices.get(device_id) {
Ok(device) => device,
Err(_) => break DeviceError::Invalid.into(),
};
@ -732,39 +730,13 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let hub = A::hub(self);
let mut texture_guard = hub.textures.write();
let texture = texture_guard
let texture = hub
.textures
.write()
.get_and_mark_destroyed(texture_id)
.map_err(|_| resource::DestroyError::Invalid)?;
let device = &texture.device;
#[cfg(feature = "trace")]
if let Some(ref mut trace) = *device.trace.lock() {
trace.add(trace::Action::FreeTexture(texture_id));
}
let last_submit_index = texture.info.submission_index();
if let resource::TextureInner::Native { ref raw } = *texture.inner().as_ref().unwrap() {
if !raw.is_none() {
let temp = queue::TempResource::Texture(texture.clone());
let mut guard = device.pending_writes.lock();
let pending_writes = guard.as_mut().unwrap();
if pending_writes.dst_textures.contains_key(&texture_id) {
pending_writes.temp_resources.push(temp);
} else {
drop(guard);
device
.lock_life()
.schedule_resource_destruction(temp, last_submit_index);
}
} else {
return Err(resource::DestroyError::AlreadyDestroyed);
}
}
Ok(())
texture.destroy()
}
pub fn texture_drop<A: HalApi>(&self, texture_id: id::TextureId, wait: bool) {
@ -962,7 +934,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let hub = A::hub(self);
let fid = hub.bind_group_layouts.prepare::<G>(id_in);
let error = 'outer: loop {
let error = loop {
let device = match hub.devices.get(device_id) {
Ok(device) => device,
Err(_) => break DeviceError::Invalid.into(),
@ -976,38 +948,50 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
trace.add(trace::Action::CreateBindGroupLayout(fid.id(), desc.clone()));
}
let mut entry_map = FastHashMap::default();
for entry in desc.entries.iter() {
if entry.binding > device.limits.max_bindings_per_bind_group {
break 'outer binding_model::CreateBindGroupLayoutError::InvalidBindingIndex {
binding: entry.binding,
maximum: device.limits.max_bindings_per_bind_group,
};
}
if entry_map.insert(entry.binding, *entry).is_some() {
break 'outer binding_model::CreateBindGroupLayoutError::ConflictBinding(
entry.binding,
);
}
}
let entry_map = match bgl::EntryMap::from_entries(&device.limits, &desc.entries) {
Ok(map) => map,
Err(e) => break e,
};
if let Some((id, layout)) = {
let bgl_guard = hub.bind_group_layouts.read();
device.deduplicate_bind_group_layout(&entry_map, &*bgl_guard)
} {
api_log!("Reusing BindGroupLayout {layout:?} -> {:?}", id);
let id = fid.assign_existing(&layout);
return (id, None);
}
// Currently we make a distinction between fid.assign and fid.assign_existing. This distinction is incorrect,
// but see https://github.com/gfx-rs/wgpu/issues/4912.
//
// `assign` also registers the ID with the resource info, so it can be automatically reclaimed. This needs to
// happen with a mutable reference, which means it can only happen on creation.
//
// Because we need to call `assign` inside the closure (to get mut access), we need to "move" the future id into the closure.
// Rust cannot figure out at compile time that we only ever consume the ID once, so we need to move the check
// to runtime using an Option.
let mut fid = Some(fid);
let layout = match device.create_bind_group_layout(&desc.label, entry_map) {
// The closure might get called, and it might give us an ID. Side channel it out of the closure.
let mut id = None;
let bgl_result = device.bgl_pool.get_or_init(entry_map, |entry_map| {
let bgl =
device.create_bind_group_layout(&desc.label, entry_map, bgl::Origin::Pool)?;
let (id_inner, arc) = fid.take().unwrap().assign(bgl);
id = Some(id_inner);
Ok(arc)
});
let layout = match bgl_result {
Ok(layout) => layout,
Err(e) => break e,
};
let (id, _layout) = fid.assign(layout);
// If the ID was not assigned, and we survived the above check,
// it means that the bind group layout already existed and we need to call `assign_existing`.
//
// Calling this function _will_ leak the ID. See https://github.com/gfx-rs/wgpu/issues/4912.
if id.is_none() {
id = Some(fid.take().unwrap().assign_existing(&layout))
}
api_log!("Device::create_bind_group_layout -> {id:?}");
return (id, None);
return (id.unwrap(), None);
};
let fid = hub.bind_group_layouts.prepare::<G>(id_in);
@ -1063,12 +1047,9 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
trace.add(trace::Action::CreatePipelineLayout(fid.id(), desc.clone()));
}
let layout = {
let bgl_guard = hub.bind_group_layouts.read();
match device.create_pipeline_layout(desc, &*bgl_guard) {
Ok(layout) => layout,
Err(e) => break e,
}
let layout = match device.create_pipeline_layout(desc, &hub.bind_group_layouts) {
Ok(layout) => layout,
Err(e) => break e,
};
let (id, _) = fid.assign(layout);
@ -1124,8 +1105,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
trace.add(trace::Action::CreateBindGroup(fid.id(), desc.clone()));
}
let bind_group_layout_guard = hub.bind_group_layouts.read();
let bind_group_layout = match bind_group_layout_guard.get(desc.layout) {
let bind_group_layout = match hub.bind_group_layouts.get(desc.layout) {
Ok(layout) => layout,
Err(..) => break binding_model::CreateBindGroupError::InvalidLayout,
};
@ -1134,7 +1114,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
break DeviceError::WrongDevice.into();
}
let bind_group = match device.create_bind_group(bind_group_layout, desc, hub) {
let bind_group = match device.create_bind_group(&bind_group_layout, desc, hub) {
Ok(bind_group) => bind_group,
Err(e) => break e,
};
@ -1767,9 +1747,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let hub = A::hub(self);
let error = loop {
let pipeline_guard = hub.compute_pipelines.read();
let pipeline = match pipeline_guard.get(pipeline_id) {
let pipeline = match hub.compute_pipelines.get(pipeline_id) {
Ok(pipeline) => pipeline,
Err(_) => break binding_model::GetBindGroupLayoutError::InvalidPipeline,
};

View File

@ -15,8 +15,8 @@ use crate::{
},
pipeline::{ComputePipeline, RenderPipeline},
resource::{
self, Buffer, DestroyedBuffer, QuerySet, Resource, Sampler, StagingBuffer, Texture,
TextureView,
self, Buffer, DestroyedBuffer, DestroyedTexture, QuerySet, Resource, Sampler,
StagingBuffer, Texture, TextureView,
},
track::{ResourceTracker, Tracker},
FastHashMap, SubmissionIndex,
@ -43,6 +43,7 @@ pub(crate) struct ResourceMaps<A: HalApi> {
pub render_bundles: FastHashMap<RenderBundleId, Arc<RenderBundle<A>>>,
pub query_sets: FastHashMap<QuerySetId, Arc<QuerySet<A>>>,
pub destroyed_buffers: FastHashMap<BufferId, Arc<DestroyedBuffer<A>>>,
pub destroyed_textures: FastHashMap<TextureId, Arc<DestroyedTexture<A>>>,
}
impl<A: HalApi> ResourceMaps<A> {
@ -61,6 +62,7 @@ impl<A: HalApi> ResourceMaps<A> {
render_bundles: FastHashMap::default(),
query_sets: FastHashMap::default(),
destroyed_buffers: FastHashMap::default(),
destroyed_textures: FastHashMap::default(),
}
}
@ -79,6 +81,7 @@ impl<A: HalApi> ResourceMaps<A> {
render_bundles,
query_sets,
destroyed_buffers,
destroyed_textures,
} = self;
buffers.clear();
staging_buffers.clear();
@ -93,6 +96,7 @@ impl<A: HalApi> ResourceMaps<A> {
render_bundles.clear();
query_sets.clear();
destroyed_buffers.clear();
destroyed_textures.clear();
}
pub(crate) fn extend(&mut self, mut other: Self) {
@ -110,6 +114,7 @@ impl<A: HalApi> ResourceMaps<A> {
render_bundles,
query_sets,
destroyed_buffers,
destroyed_textures,
} = self;
buffers.extend(other.buffers.drain());
staging_buffers.extend(other.staging_buffers.drain());
@ -124,6 +129,7 @@ impl<A: HalApi> ResourceMaps<A> {
render_bundles.extend(other.render_bundles.drain());
query_sets.extend(other.query_sets.drain());
destroyed_buffers.extend(other.destroyed_buffers.drain());
destroyed_textures.extend(other.destroyed_textures.drain());
}
}
@ -298,6 +304,11 @@ impl<A: HalApi> LifetimeTracker<A> {
TempResource::Texture(raw) => {
last_resources.textures.insert(raw.as_info().id(), raw);
}
TempResource::DestroyedTexture(destroyed) => {
last_resources
.destroyed_textures
.insert(destroyed.id, destroyed);
}
}
}
@ -404,6 +415,9 @@ impl<A: HalApi> LifetimeTracker<A> {
TempResource::Texture(raw) => {
resources.textures.insert(raw.as_info().id(), raw);
}
TempResource::DestroyedTexture(destroyed) => {
resources.destroyed_textures.insert(destroyed.id, destroyed);
}
}
}
@ -680,6 +694,27 @@ impl<A: HalApi> LifetimeTracker<A> {
}
}
fn triage_suspected_destroyed_textures(
&mut self,
#[cfg(feature = "trace")] trace: &mut Option<&mut trace::Trace>,
) {
for (id, texture) in self.suspected_resources.destroyed_textures.drain() {
let submit_index = texture.submission_index;
if let Some(resources) = self.active.iter_mut().find(|a| a.index == submit_index) {
resources
.last_resources
.destroyed_textures
.insert(id, texture);
} else {
self.free_resources.destroyed_textures.insert(id, texture);
}
#[cfg(feature = "trace")]
if let Some(ref mut t) = *trace {
t.add(trace::Action::DestroyTexture(id));
}
}
}
fn triage_suspected_compute_pipelines(
&mut self,
trackers: &Mutex<Tracker<A>>,
@ -913,6 +948,10 @@ impl<A: HalApi> LifetimeTracker<A> {
#[cfg(feature = "trace")]
&mut trace,
);
self.triage_suspected_destroyed_textures(
#[cfg(feature = "trace")]
&mut trace,
);
}
/// Determine which buffers are ready to map, and which must wait for the

View File

@ -19,6 +19,7 @@ use wgt::{BufferAddress, DeviceLostReason, TextureFormat};
use std::{iter, num::NonZeroU32, ptr};
pub mod any_device;
pub(crate) mod bgl;
pub mod global;
mod life;
pub mod queue;

View File

@ -16,8 +16,8 @@ use crate::{
identity::{GlobalIdentityHandlerFactory, Input},
init_tracker::{has_copy_partial_init_tracker_coverage, TextureInitRange},
resource::{
Buffer, BufferAccessError, BufferMapState, DestroyedBuffer, Resource, ResourceInfo,
ResourceType, StagingBuffer, Texture, TextureInner,
Buffer, BufferAccessError, BufferMapState, DestroyedBuffer, DestroyedTexture, Resource,
ResourceInfo, ResourceType, StagingBuffer, Texture, TextureInner,
},
resource_log, track, FastHashMap, SubmissionIndex,
};
@ -164,6 +164,7 @@ pub enum TempResource<A: HalApi> {
Buffer(Arc<Buffer<A>>),
StagingBuffer(Arc<StagingBuffer<A>>),
DestroyedBuffer(Arc<DestroyedBuffer<A>>),
DestroyedTexture(Arc<DestroyedTexture<A>>),
Texture(Arc<Texture<A>>),
}
@ -740,7 +741,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
// doesn't really matter because we need this only if we copy
// more than one layer, and then we validate for this being not
// None
size.height,
height_blocks,
);
let block_size = dst
@ -802,6 +803,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
}
}
let snatch_guard = device.snatchable_lock.read();
// Re-get `dst` immutably here, so that the mutable borrow of the
// `texture_guard.get` above ends in time for the `clear_texture`
// call above. Since we've held `texture_guard` the whole time, we know
@ -810,11 +813,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
dst.info
.use_at(device.active_submission_index.load(Ordering::Relaxed) + 1);
let dst_inner = dst.inner();
let dst_raw = dst_inner
.as_ref()
.unwrap()
.as_raw()
let dst_raw = dst
.raw(&snatch_guard)
.ok_or(TransferError::InvalidTexture(destination.texture))?;
let bytes_per_row = data_layout
@ -897,9 +897,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
.set_single(&dst, selector, hal::TextureUses::COPY_DST)
.ok_or(TransferError::InvalidTexture(destination.texture))?;
unsafe {
encoder.transition_textures(
transition.map(|pending| pending.into_hal(dst_inner.as_ref().unwrap())),
);
encoder.transition_textures(transition.map(|pending| pending.into_hal(dst_raw)));
encoder.transition_buffers(iter::once(barrier));
encoder.copy_buffer_to_texture(inner_buffer.as_ref().unwrap(), dst_raw, regions);
}
@ -1076,11 +1074,9 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
dst.info
.use_at(device.active_submission_index.load(Ordering::Relaxed) + 1);
let dst_inner = dst.inner();
let dst_raw = dst_inner
.as_ref()
.unwrap()
.as_raw()
let snatch_guard = device.snatchable_lock.read();
let dst_raw = dst
.raw(&snatch_guard)
.ok_or(TransferError::InvalidTexture(destination.texture))?;
let regions = hal::TextureCopy {
@ -1100,9 +1096,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
.textures
.set_single(&dst, selector, hal::TextureUses::COPY_DST)
.ok_or(TransferError::InvalidTexture(destination.texture))?;
encoder.transition_textures(
transitions.map(|pending| pending.into_hal(dst_inner.as_ref().unwrap())),
);
encoder.transition_textures(transitions.map(|pending| pending.into_hal(dst_raw)));
encoder.copy_external_image_to_texture(
source,
dst_raw,
@ -1238,12 +1232,12 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
}
for texture in cmd_buf_trackers.textures.used_resources() {
let id = texture.info.id();
let should_extend = match *texture.inner().as_ref().unwrap() {
TextureInner::Native { raw: None } => {
let should_extend = match texture.inner.get(&snatch_guard) {
None => {
return Err(QueueSubmitError::DestroyedTexture(id));
}
TextureInner::Native { raw: Some(_) } => false,
TextureInner::Surface { ref has_work, .. } => {
Some(TextureInner::Native { .. }) => false,
Some(TextureInner::Surface { ref has_work, .. }) => {
has_work.store(true, Ordering::Relaxed);
true
}
@ -1399,11 +1393,12 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
trackers
.textures
.set_from_usage_scope(&used_surface_textures);
let (transitions, textures) = trackers.textures.drain_transitions();
let (transitions, textures) =
trackers.textures.drain_transitions(&snatch_guard);
let texture_barriers = transitions
.into_iter()
.enumerate()
.map(|(i, p)| p.into_hal(textures[i].as_ref().unwrap()));
.map(|(i, p)| p.into_hal(textures[i].unwrap().raw().unwrap()));
let present = unsafe {
baked.encoder.transition_textures(texture_barriers);
baked.encoder.end_encoding().unwrap()
@ -1427,16 +1422,14 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let pending_writes = pending_writes.as_mut().unwrap();
{
let texture_guard = hub.textures.read();
used_surface_textures.set_size(texture_guard.len());
used_surface_textures.set_size(hub.textures.read().len());
for (&id, texture) in pending_writes.dst_textures.iter() {
match *texture.inner().as_ref().unwrap() {
TextureInner::Native { raw: None } => {
match texture.inner.get(&snatch_guard) {
None => {
return Err(QueueSubmitError::DestroyedTexture(id));
}
TextureInner::Native { raw: Some(_) } => {}
TextureInner::Surface { ref has_work, .. } => {
Some(TextureInner::Native { .. }) => {}
Some(TextureInner::Surface { ref has_work, .. }) => {
has_work.store(true, Ordering::Relaxed);
unsafe {
used_surface_textures
@ -1453,11 +1446,12 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
trackers
.textures
.set_from_usage_scope(&used_surface_textures);
let (transitions, textures) = trackers.textures.drain_transitions();
let (transitions, textures) =
trackers.textures.drain_transitions(&snatch_guard);
let texture_barriers = transitions
.into_iter()
.enumerate()
.map(|(i, p)| p.into_hal(textures[i].as_ref().unwrap()));
.map(|(i, p)| p.into_hal(textures[i].unwrap().raw().unwrap()));
unsafe {
pending_writes
.command_encoder

View File

@ -6,7 +6,7 @@ use crate::{
device::life::{LifetimeTracker, WaitIdleError},
device::queue::PendingWrites,
device::{
AttachmentData, CommandAllocator, DeviceLostInvocation, MissingDownlevelFlags,
bgl, AttachmentData, CommandAllocator, DeviceLostInvocation, MissingDownlevelFlags,
MissingFeatures, RenderPassContext, CLEANUP_WAIT_MS,
},
hal_api::HalApi,
@ -19,6 +19,7 @@ use crate::{
},
instance::Adapter,
pipeline,
pool::ResourcePool,
registry::Registry,
resource::ResourceInfo,
resource::{
@ -120,6 +121,8 @@ pub struct Device<A: HalApi> {
/// Temporary storage for resource management functions. Cleared at the end
/// of every call (unless an error occurs).
pub(crate) temp_suspected: Mutex<Option<ResourceMaps<A>>>,
/// Pool of bind group layouts, allowing deduplication.
pub(crate) bgl_pool: ResourcePool<bgl::EntryMap, BindGroupLayout<A>>,
pub(crate) alignments: hal::Alignments,
pub(crate) limits: wgt::Limits,
pub(crate) features: wgt::Features,
@ -261,6 +264,7 @@ impl<A: HalApi> Device<A> {
trackers: Mutex::new(Tracker::new()),
life_tracker: Mutex::new(life::LifetimeTracker::new()),
temp_suspected: Mutex::new(Some(life::ResourceMaps::new())),
bgl_pool: ResourcePool::new(),
#[cfg(feature = "trace")]
trace: Mutex::new(trace_path.and_then(|path| match trace::Trace::new(path) {
Ok(mut trace) => {
@ -583,9 +587,7 @@ impl<A: HalApi> Device<A> {
debug_assert_eq!(self.as_info().id().backend(), A::VARIANT);
Texture {
inner: RwLock::new(Some(resource::TextureInner::Native {
raw: Some(hal_texture),
})),
inner: Snatchable::new(resource::TextureInner::Native { raw: hal_texture }),
device: self.clone(),
desc: desc.map_label(|_| ()),
hal_usage,
@ -903,15 +905,14 @@ impl<A: HalApi> Device<A> {
texture: &Arc<Texture<A>>,
desc: &resource::TextureViewDescriptor,
) -> Result<TextureView<A>, resource::CreateTextureViewError> {
let inner = texture.inner();
let texture_raw = inner
.as_ref()
.unwrap()
.as_raw()
let snatch_guard = texture.device.snatchable_lock.read();
let texture_raw = texture
.raw(&snatch_guard)
.ok_or(resource::CreateTextureViewError::InvalidTexture)?;
// resolve TextureViewDescriptor defaults
// https://gpuweb.github.io/gpuweb/#abstract-opdef-resolving-gputextureviewdescriptor-defaults
let resolved_format = desc.format.unwrap_or_else(|| {
texture
.desc
@ -1513,29 +1514,6 @@ impl<A: HalApi> Device<A> {
})
}
pub(crate) fn deduplicate_bind_group_layout<'a>(
self: &Arc<Self>,
entry_map: &'a binding_model::BindEntryMap,
guard: &'a Storage<BindGroupLayout<A>, id::BindGroupLayoutId>,
) -> Option<(id::BindGroupLayoutId, Arc<BindGroupLayout<A>>)> {
guard
.iter(self.as_info().id().backend())
.find(|&(_, bgl)| {
bgl.device.info.id() == self.as_info().id() && bgl.entries == *entry_map
})
.map(|(id, resource)| (id, resource.clone()))
}
pub(crate) fn get_introspection_bind_group_layouts<'a>(
pipeline_layout: &'a binding_model::PipelineLayout<A>,
) -> ArrayVec<&'a binding_model::BindEntryMap, { hal::MAX_BIND_GROUPS }> {
pipeline_layout
.bind_group_layouts
.iter()
.map(|layout| &layout.entries)
.collect()
}
/// Generate information about late-validated buffer bindings for pipelines.
//TODO: should this be combined with `get_introspection_bind_group_layouts` in some way?
pub(crate) fn make_late_sized_buffer_groups(
@ -1576,7 +1554,8 @@ impl<A: HalApi> Device<A> {
pub(crate) fn create_bind_group_layout(
self: &Arc<Self>,
label: &crate::Label,
entry_map: binding_model::BindEntryMap,
entry_map: bgl::EntryMap,
origin: bgl::Origin,
) -> Result<BindGroupLayout<A>, binding_model::CreateBindGroupLayoutError> {
#[derive(PartialEq)]
enum WritableStorage {
@ -1739,9 +1718,8 @@ impl<A: HalApi> Device<A> {
let bgl_flags = conv::bind_group_layout_flags(self.features);
let mut hal_bindings = entry_map.values().cloned().collect::<Vec<_>>();
let hal_bindings = entry_map.values().copied().collect::<Vec<_>>();
let label = label.to_hal(self.instance_flags);
hal_bindings.sort_by_key(|b| b.binding);
let hal_desc = hal::BindGroupLayoutDescriptor {
label,
flags: bgl_flags,
@ -1768,13 +1746,10 @@ impl<A: HalApi> Device<A> {
Ok(BindGroupLayout {
raw: Some(raw),
device: self.clone(),
info: ResourceInfo::new(label.unwrap_or("<BindGroupLayout>")),
dynamic_count: entry_map
.values()
.filter(|b| b.ty.has_dynamic_offset())
.count(),
count_validator,
entries: entry_map,
origin,
binding_count_validator: count_validator,
info: ResourceInfo::new(label.unwrap_or("<BindGroupLayout>")),
label: label.unwrap_or_default().to_string(),
})
}
@ -1996,7 +1971,7 @@ impl<A: HalApi> Device<A> {
// Find the corresponding declaration in the layout
let decl = layout
.entries
.get(&binding)
.get(binding)
.ok_or(Error::MissingBindingDeclaration(binding))?;
let (res_index, count) = match entry.resource {
Br::Buffer(ref bb) => {
@ -2206,8 +2181,8 @@ impl<A: HalApi> Device<A> {
// collect in the order of BGL iteration
late_buffer_binding_sizes: layout
.entries
.keys()
.flat_map(|binding| late_buffer_binding_sizes.get(binding).cloned())
.indices()
.flat_map(|binding| late_buffer_binding_sizes.get(&binding).cloned())
.collect(),
})
}
@ -2379,7 +2354,7 @@ impl<A: HalApi> Device<A> {
pub(crate) fn create_pipeline_layout(
self: &Arc<Self>,
desc: &binding_model::PipelineLayoutDescriptor,
bgl_guard: &Storage<BindGroupLayout<A>, id::BindGroupLayoutId>,
bgl_registry: &Registry<id::BindGroupLayoutId, BindGroupLayout<A>>,
) -> Result<binding_model::PipelineLayout<A>, binding_model::CreatePipelineLayoutError> {
use crate::binding_model::CreatePipelineLayoutError as Error;
@ -2432,31 +2407,38 @@ impl<A: HalApi> Device<A> {
let mut count_validator = binding_model::BindingTypeMaxCountValidator::default();
// validate total resource counts
// Collect references to the BGLs
let mut bind_group_layouts = ArrayVec::new();
for &id in desc.bind_group_layouts.iter() {
let Ok(bind_group_layout) = bgl_guard.get(id) else {
let Ok(bgl) = bgl_registry.get(id) else {
return Err(Error::InvalidBindGroupLayout(id));
};
if bind_group_layout.device.as_info().id() != self.as_info().id() {
bind_group_layouts.push(bgl);
}
// Validate total resource counts and check for a matching device
for bgl in &bind_group_layouts {
if bgl.device.as_info().id() != self.as_info().id() {
return Err(DeviceError::WrongDevice.into());
}
count_validator.merge(&bind_group_layout.count_validator);
count_validator.merge(&bgl.binding_count_validator);
}
count_validator
.validate(&self.limits)
.map_err(Error::TooManyBindings)?;
let bgl_vec = desc
.bind_group_layouts
let raw_bind_group_layouts = bind_group_layouts
.iter()
.map(|&id| bgl_guard.get(id).unwrap().raw())
.collect::<Vec<_>>();
.map(|bgl| bgl.raw())
.collect::<ArrayVec<_, { hal::MAX_BIND_GROUPS }>>();
let hal_desc = hal::PipelineLayoutDescriptor {
label: desc.label.to_hal(self.instance_flags),
flags: hal::PipelineLayoutFlags::FIRST_VERTEX_INSTANCE,
bind_group_layouts: &bgl_vec,
bind_group_layouts: &raw_bind_group_layouts,
push_constant_ranges: desc.push_constant_ranges.as_ref(),
};
@ -2468,15 +2450,13 @@ impl<A: HalApi> Device<A> {
.map_err(DeviceError::from)?
};
drop(raw_bind_group_layouts);
Ok(binding_model::PipelineLayout {
raw: Some(raw),
device: self.clone(),
info: ResourceInfo::new(desc.label.borrow_or_default()),
bind_group_layouts: desc
.bind_group_layouts
.iter()
.map(|&id| bgl_guard.get(id).unwrap().clone())
.collect(),
bind_group_layouts,
push_constant_ranges: desc.push_constant_ranges.iter().cloned().collect(),
})
}
@ -2486,10 +2466,10 @@ impl<A: HalApi> Device<A> {
pub(crate) fn derive_pipeline_layout(
self: &Arc<Self>,
implicit_context: Option<ImplicitPipelineContext>,
mut derived_group_layouts: ArrayVec<binding_model::BindEntryMap, { hal::MAX_BIND_GROUPS }>,
mut derived_group_layouts: ArrayVec<bgl::EntryMap, { hal::MAX_BIND_GROUPS }>,
bgl_registry: &Registry<id::BindGroupLayoutId, BindGroupLayout<A>>,
pipeline_layout_registry: &Registry<id::PipelineLayoutId, binding_model::PipelineLayout<A>>,
) -> Result<id::PipelineLayoutId, pipeline::ImplicitLayoutError> {
) -> Result<Arc<binding_model::PipelineLayout<A>>, pipeline::ImplicitLayoutError> {
while derived_group_layouts
.last()
.map_or(false, |map| map.is_empty())
@ -2508,16 +2488,8 @@ impl<A: HalApi> Device<A> {
}
for (bgl_id, map) in ids.group_ids.iter_mut().zip(derived_group_layouts) {
let bgl = match self.deduplicate_bind_group_layout(&map, &bgl_registry.read()) {
Some((dedup_id, _)) => {
*bgl_id = dedup_id;
None
}
None => Some(self.create_bind_group_layout(&None, map)?),
};
if let Some(bgl) = bgl {
bgl_registry.force_replace(*bgl_id, bgl);
}
let bgl = self.create_bind_group_layout(&None, map, bgl::Origin::Derived)?;
bgl_registry.force_replace(*bgl_id, bgl);
}
let layout_desc = binding_model::PipelineLayoutDescriptor {
@ -2525,9 +2497,9 @@ impl<A: HalApi> Device<A> {
bind_group_layouts: Cow::Borrowed(&ids.group_ids[..group_count]),
push_constant_ranges: Cow::Borrowed(&[]), //TODO?
};
let layout = self.create_pipeline_layout(&layout_desc, &bgl_registry.read())?;
let layout = self.create_pipeline_layout(&layout_desc, bgl_registry)?;
pipeline_layout_registry.force_replace(ids.root_id, layout);
Ok(ids.root_id)
Ok(pipeline_layout_registry.get(ids.root_id).unwrap())
}
pub(crate) fn create_compute_pipeline(
@ -2549,12 +2521,6 @@ impl<A: HalApi> Device<A> {
self.require_downlevel_flags(wgt::DownlevelFlags::COMPUTE_SHADERS)?;
let mut derived_group_layouts =
ArrayVec::<binding_model::BindEntryMap, { hal::MAX_BIND_GROUPS }>::new();
let mut shader_binding_sizes = FastHashMap::default();
let io = validation::StageIo::default();
let shader_module = hub
.shader_modules
.get(desc.stage.module)
@ -2564,59 +2530,66 @@ impl<A: HalApi> Device<A> {
return Err(DeviceError::WrongDevice.into());
}
{
let flag = wgt::ShaderStages::COMPUTE;
let pipeline_layout_guard = hub.pipeline_layouts.read();
let provided_layouts = match desc.layout {
Some(pipeline_layout_id) => Some(Device::get_introspection_bind_group_layouts(
pipeline_layout_guard
.get(pipeline_layout_id)
.map_err(|_| pipeline::CreateComputePipelineError::InvalidLayout)?,
)),
None => {
for _ in 0..self.limits.max_bind_groups {
derived_group_layouts.push(binding_model::BindEntryMap::default());
}
None
// Get the pipeline layout from the desc if it is provided.
let pipeline_layout = match desc.layout {
Some(pipeline_layout_id) => {
let pipeline_layout = hub
.pipeline_layouts
.get(pipeline_layout_id)
.map_err(|_| pipeline::CreateComputePipelineError::InvalidLayout)?;
if pipeline_layout.device.as_info().id() != self.as_info().id() {
return Err(DeviceError::WrongDevice.into());
}
};
Some(pipeline_layout)
}
None => None,
};
let mut binding_layout_source = match pipeline_layout {
Some(ref pipeline_layout) => {
validation::BindingLayoutSource::Provided(pipeline_layout.get_binding_maps())
}
None => validation::BindingLayoutSource::new_derived(&self.limits),
};
let mut shader_binding_sizes = FastHashMap::default();
let io = validation::StageIo::default();
{
let stage = wgt::ShaderStages::COMPUTE;
if let Some(ref interface) = shader_module.interface {
let _ = interface.check_stage(
provided_layouts.as_ref().map(|p| p.as_slice()),
&mut derived_group_layouts,
&mut binding_layout_source,
&mut shader_binding_sizes,
&desc.stage.entry_point,
flag,
stage,
io,
None,
)?;
}
}
let pipeline_layout_id = match desc.layout {
Some(id) => id,
None => self.derive_pipeline_layout(
let pipeline_layout = match binding_layout_source {
validation::BindingLayoutSource::Provided(_) => {
drop(binding_layout_source);
pipeline_layout.unwrap()
}
validation::BindingLayoutSource::Derived(entries) => self.derive_pipeline_layout(
implicit_context,
derived_group_layouts,
entries,
&hub.bind_group_layouts,
&hub.pipeline_layouts,
)?,
};
let pipeline_layout_guard = hub.pipeline_layouts.read();
let layout = pipeline_layout_guard
.get(pipeline_layout_id)
.map_err(|_| pipeline::CreateComputePipelineError::InvalidLayout)?;
if layout.device.as_info().id() != self.as_info().id() {
return Err(DeviceError::WrongDevice.into());
}
let late_sized_buffer_groups =
Device::make_late_sized_buffer_groups(&shader_binding_sizes, layout);
Device::make_late_sized_buffer_groups(&shader_binding_sizes, &pipeline_layout);
let pipeline_desc = hal::ComputePipelineDescriptor {
label: desc.label.to_hal(self.instance_flags),
layout: layout.raw(),
layout: pipeline_layout.raw(),
stage: hal::ProgrammableStage {
entry_point: desc.stage.entry_point.as_ref(),
module: shader_module.raw(),
@ -2643,7 +2616,7 @@ impl<A: HalApi> Device<A> {
let pipeline = pipeline::ComputePipeline {
raw: Some(raw),
layout: layout.clone(),
layout: pipeline_layout,
device: self.clone(),
_shader_module: shader_module,
late_sized_buffer_groups,
@ -2661,8 +2634,6 @@ impl<A: HalApi> Device<A> {
) -> Result<pipeline::RenderPipeline<A>, pipeline::CreateRenderPipelineError> {
use wgt::TextureFormatFeatureFlags as Tfff;
let mut shader_modules = Vec::new();
// This has to be done first, or otherwise the IDs may be pointing to entries
// that are not even in the storage.
if let Some(ref ids) = implicit_context {
@ -2675,8 +2646,6 @@ impl<A: HalApi> Device<A> {
}
}
let mut derived_group_layouts =
ArrayVec::<binding_model::BindEntryMap, { hal::MAX_BIND_GROUPS }>::new();
let mut shader_binding_sizes = FastHashMap::default();
let num_attachments = desc.fragment.as_ref().map(|f| f.targets.len()).unwrap_or(0);
@ -2944,11 +2913,29 @@ impl<A: HalApi> Device<A> {
}
}
if desc.layout.is_none() {
for _ in 0..self.limits.max_bind_groups {
derived_group_layouts.push(binding_model::BindEntryMap::default());
// Get the pipeline layout from the desc if it is provided.
let pipeline_layout = match desc.layout {
Some(pipeline_layout_id) => {
let pipeline_layout = hub
.pipeline_layouts
.get(pipeline_layout_id)
.map_err(|_| pipeline::CreateRenderPipelineError::InvalidLayout)?;
if pipeline_layout.device.as_info().id() != self.as_info().id() {
return Err(DeviceError::WrongDevice.into());
}
Some(pipeline_layout)
}
}
None => None,
};
let mut binding_layout_source = match pipeline_layout {
Some(ref pipeline_layout) => {
validation::BindingLayoutSource::Provided(pipeline_layout.get_binding_maps())
}
None => validation::BindingLayoutSource::new_derived(&self.limits),
};
let samples = {
let sc = desc.multisample.count;
@ -2958,122 +2945,86 @@ impl<A: HalApi> Device<A> {
sc
};
let shader_module_guard = hub.shader_modules.read();
let vertex_shader_module;
let vertex_stage = {
let stage = &desc.vertex.stage;
let flag = wgt::ShaderStages::VERTEX;
let stage_desc = &desc.vertex.stage;
let stage = wgt::ShaderStages::VERTEX;
let shader_module = shader_module_guard.get(stage.module).map_err(|_| {
vertex_shader_module = hub.shader_modules.get(stage_desc.module).map_err(|_| {
pipeline::CreateRenderPipelineError::Stage {
stage: flag,
stage,
error: validation::StageError::InvalidModule,
}
})?;
if shader_module.device.as_info().id() != self.as_info().id() {
if vertex_shader_module.device.as_info().id() != self.as_info().id() {
return Err(DeviceError::WrongDevice.into());
}
shader_modules.push(shader_module.clone());
let pipeline_layout_guard = hub.pipeline_layouts.read();
let provided_layouts = match desc.layout {
Some(pipeline_layout_id) => {
let pipeline_layout = pipeline_layout_guard
.get(pipeline_layout_id)
.map_err(|_| pipeline::CreateRenderPipelineError::InvalidLayout)?;
if pipeline_layout.device.as_info().id() != self.as_info().id() {
return Err(DeviceError::WrongDevice.into());
}
Some(Device::get_introspection_bind_group_layouts(
pipeline_layout,
))
}
None => None,
};
if let Some(ref interface) = shader_module.interface {
if let Some(ref interface) = vertex_shader_module.interface {
io = interface
.check_stage(
provided_layouts.as_ref().map(|p| p.as_slice()),
&mut derived_group_layouts,
&mut binding_layout_source,
&mut shader_binding_sizes,
&stage.entry_point,
flag,
&stage_desc.entry_point,
stage,
io,
desc.depth_stencil.as_ref().map(|d| d.depth_compare),
)
.map_err(|error| pipeline::CreateRenderPipelineError::Stage {
stage: flag,
error,
})?;
validated_stages |= flag;
.map_err(|error| pipeline::CreateRenderPipelineError::Stage { stage, error })?;
validated_stages |= stage;
}
hal::ProgrammableStage {
module: shader_module.raw(),
entry_point: stage.entry_point.as_ref(),
module: vertex_shader_module.raw(),
entry_point: stage_desc.entry_point.as_ref(),
}
};
let mut fragment_shader_module = None;
let fragment_stage = match desc.fragment {
Some(ref fragment) => {
let flag = wgt::ShaderStages::FRAGMENT;
Some(ref fragment_state) => {
let stage = wgt::ShaderStages::FRAGMENT;
let shader_module =
shader_module_guard
.get(fragment.stage.module)
let shader_module = fragment_shader_module.insert(
hub.shader_modules
.get(fragment_state.stage.module)
.map_err(|_| pipeline::CreateRenderPipelineError::Stage {
stage: flag,
stage,
error: validation::StageError::InvalidModule,
})?;
shader_modules.push(shader_module.clone());
let pipeline_layout_guard = hub.pipeline_layouts.read();
let provided_layouts = match desc.layout {
Some(pipeline_layout_id) => Some(Device::get_introspection_bind_group_layouts(
pipeline_layout_guard
.get(pipeline_layout_id)
.as_ref()
.map_err(|_| pipeline::CreateRenderPipelineError::InvalidLayout)?,
)),
None => None,
};
})?,
);
if validated_stages == wgt::ShaderStages::VERTEX {
if let Some(ref interface) = shader_module.interface {
io = interface
.check_stage(
provided_layouts.as_ref().map(|p| p.as_slice()),
&mut derived_group_layouts,
&mut binding_layout_source,
&mut shader_binding_sizes,
&fragment.stage.entry_point,
flag,
&fragment_state.stage.entry_point,
stage,
io,
desc.depth_stencil.as_ref().map(|d| d.depth_compare),
)
.map_err(|error| pipeline::CreateRenderPipelineError::Stage {
stage: flag,
stage,
error,
})?;
validated_stages |= flag;
validated_stages |= stage;
}
}
if let Some(ref interface) = shader_module.interface {
shader_expects_dual_source_blending = interface
.fragment_uses_dual_source_blending(&fragment.stage.entry_point)
.fragment_uses_dual_source_blending(&fragment_state.stage.entry_point)
.map_err(|error| pipeline::CreateRenderPipelineError::Stage {
stage: flag,
stage,
error,
})?;
}
Some(hal::ProgrammableStage {
module: shader_module.raw(),
entry_point: fragment.stage.entry_point.as_ref(),
entry_point: fragment_state.stage.entry_point.as_ref(),
})
}
None => None,
@ -3126,22 +3077,18 @@ impl<A: HalApi> Device<A> {
return Err(pipeline::ImplicitLayoutError::ReflectionError(last_stage).into());
}
let pipeline_layout_id = match desc.layout {
Some(id) => id,
None => self.derive_pipeline_layout(
let pipeline_layout = match binding_layout_source {
validation::BindingLayoutSource::Provided(_) => {
drop(binding_layout_source);
pipeline_layout.unwrap()
}
validation::BindingLayoutSource::Derived(entries) => self.derive_pipeline_layout(
implicit_context,
derived_group_layouts,
entries,
&hub.bind_group_layouts,
&hub.pipeline_layouts,
)?,
};
let layout = {
let pipeline_layout_guard = hub.pipeline_layouts.read();
pipeline_layout_guard
.get(pipeline_layout_id)
.map_err(|_| pipeline::CreateRenderPipelineError::InvalidLayout)?
.clone()
};
// Multiview is only supported if the feature is enabled
if desc.multiview.is_some() {
@ -3165,11 +3112,11 @@ impl<A: HalApi> Device<A> {
}
let late_sized_buffer_groups =
Device::make_late_sized_buffer_groups(&shader_binding_sizes, &layout);
Device::make_late_sized_buffer_groups(&shader_binding_sizes, &pipeline_layout);
let pipeline_desc = hal::RenderPipelineDescriptor {
label: desc.label.to_hal(self.instance_flags),
layout: layout.raw(),
layout: pipeline_layout.raw(),
vertex_buffers: &vertex_buffers,
vertex_stage,
primitive: desc.primitive,
@ -3233,9 +3180,16 @@ impl<A: HalApi> Device<A> {
}
}
let shader_modules = {
let mut shader_modules = ArrayVec::new();
shader_modules.push(vertex_shader_module);
shader_modules.extend(fragment_shader_module);
shader_modules
};
let pipeline = pipeline::RenderPipeline {
raw: Some(raw),
layout: layout.clone(),
layout: pipeline_layout,
device: self.clone(),
pass_context,
_shader_modules: shader_modules,
@ -3278,7 +3232,10 @@ impl<A: HalApi> Device<A> {
.contains(wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES);
// If we're running downlevel, we need to manually ask the backend what
// we can use as we can't trust WebGPU.
let downlevel = !self.downlevel.is_webgpu_compliant();
let downlevel = !self
.downlevel
.flags
.contains(wgt::DownlevelFlags::WEBGPU_TEXTURE_FORMAT_SUPPORT);
if using_device_features || downlevel {
Ok(self.get_texture_format_features(adapter, format))

View File

@ -0,0 +1,86 @@
//! Module for hashing utilities.
//!
//! Named hash_utils to prevent clashing with the std::hash module.
/// HashMap using a fast, non-cryptographic hash algorithm.
pub type FastHashMap<K, V> =
std::collections::HashMap<K, V, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>;
/// HashSet using a fast, non-cryptographic hash algorithm.
pub type FastHashSet<K> =
std::collections::HashSet<K, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>;
/// IndexMap using a fast, non-cryptographic hash algorithm.
pub type FastIndexMap<K, V> =
indexmap::IndexMap<K, V, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>;
/// HashMap that uses pre-hashed keys and an identity hasher.
///
/// This is useful when you only need the key to lookup the value, and don't need to store the key,
/// particularly when the key is large.
pub type PreHashedMap<K, V> =
std::collections::HashMap<PreHashedKey<K>, V, std::hash::BuildHasherDefault<IdentityHasher>>;
/// A pre-hashed key using FxHash which allows the hashing operation to be disconnected
/// from the storage in the map.
pub struct PreHashedKey<K>(u64, std::marker::PhantomData<fn() -> K>);
impl<K> std::fmt::Debug for PreHashedKey<K> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("PreHashedKey").field(&self.0).finish()
}
}
impl<K> Copy for PreHashedKey<K> {}
impl<K> Clone for PreHashedKey<K> {
fn clone(&self) -> Self {
*self
}
}
impl<K> PartialEq for PreHashedKey<K> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<K> Eq for PreHashedKey<K> {}
impl<K> std::hash::Hash for PreHashedKey<K> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
impl<K: std::hash::Hash> PreHashedKey<K> {
pub fn from_key(key: &K) -> Self {
use std::hash::Hasher;
let mut hasher = rustc_hash::FxHasher::default();
key.hash(&mut hasher);
Self(hasher.finish(), std::marker::PhantomData)
}
}
/// A hasher which does nothing. Useful for when you want to use a map with pre-hashed keys.
///
/// When hashing with this hasher, you must provide exactly 8 bytes. Multiple calls to `write`
/// will overwrite the previous value.
#[derive(Default)]
pub struct IdentityHasher {
hash: u64,
}
impl std::hash::Hasher for IdentityHasher {
fn write(&mut self, bytes: &[u8]) {
self.hash = u64::from_ne_bytes(
bytes
.try_into()
.expect("identity hasher must be given exactly 8 bytes"),
);
}
fn finish(&self) -> u64 {
self.hash
}
}

View File

@ -84,12 +84,14 @@ pub mod device;
pub mod error;
pub mod global;
pub mod hal_api;
mod hash_utils;
pub mod hub;
pub mod id;
pub mod identity;
mod init_tracker;
pub mod instance;
pub mod pipeline;
mod pool;
pub mod present;
pub mod registry;
pub mod resource;
@ -106,6 +108,8 @@ pub use hal::{api, MAX_BIND_GROUPS, MAX_COLOR_ATTACHMENTS, MAX_VERTEX_BUFFERS};
use std::{borrow::Cow, os::raw::c_char};
pub(crate) use hash_utils::*;
/// The index of a queue submission.
///
/// These are the values stored in `Device::fence`.
@ -335,13 +339,6 @@ macro_rules! resource_log {
}
pub(crate) use resource_log;
/// Fast hash map used internally.
type FastHashMap<K, V> =
std::collections::HashMap<K, V, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>;
/// Fast hash set used internally.
type FastHashSet<K> =
std::collections::HashSet<K, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>;
#[inline]
pub(crate) fn get_lowest_common_denom(a: u32, b: u32) -> u32 {
let gcd = if a >= b {

View File

@ -479,7 +479,8 @@ pub struct RenderPipeline<A: HalApi> {
pub(crate) raw: Option<A::RenderPipeline>,
pub(crate) device: Arc<Device<A>>,
pub(crate) layout: Arc<PipelineLayout<A>>,
pub(crate) _shader_modules: Vec<Arc<ShaderModule<A>>>,
pub(crate) _shader_modules:
ArrayVec<Arc<ShaderModule<A>>, { hal::MAX_CONCURRENT_SHADER_STAGES }>,
pub(crate) pass_context: RenderPassContext,
pub(crate) flags: PipelineFlags,
pub(crate) strip_index_format: Option<wgt::IndexFormat>,

312
third_party/rust/wgpu-core/src/pool.rs vendored Normal file
View File

@ -0,0 +1,312 @@
use std::{
collections::{hash_map::Entry, HashMap},
hash::Hash,
sync::{Arc, Weak},
};
use once_cell::sync::OnceCell;
use parking_lot::Mutex;
use crate::{PreHashedKey, PreHashedMap};
type SlotInner<V> = Weak<V>;
type ResourcePoolSlot<V> = Arc<OnceCell<SlotInner<V>>>;
pub struct ResourcePool<K, V> {
// We use a pre-hashed map as we never actually need to read the keys.
//
// This additionally allows us to not need to hash more than once on get_or_init.
inner: Mutex<PreHashedMap<K, ResourcePoolSlot<V>>>,
}
impl<K: Clone + Eq + Hash, V> ResourcePool<K, V> {
pub fn new() -> Self {
Self {
inner: Mutex::new(HashMap::default()),
}
}
/// Get a resource from the pool with the given entry map, or create a new one if it doesn't exist using the given constructor.
///
/// Behaves such that only one resource will be created for each unique entry map at any one time.
pub fn get_or_init<F, E>(&self, key: K, constructor: F) -> Result<Arc<V>, E>
where
F: FnOnce(K) -> Result<Arc<V>, E>,
{
// Hash the key outside of the lock.
let hashed_key = PreHashedKey::from_key(&key);
// We can't prove at compile time that these will only ever be consumed once,
// so we need to do the check at runtime.
let mut key = Some(key);
let mut constructor = Some(constructor);
'race: loop {
let mut map_guard = self.inner.lock();
let entry = match map_guard.entry(hashed_key) {
// An entry exists for this resource.
//
// We know that either:
// - The resource is still alive, and Weak::upgrade will succeed.
// - The resource is in the process of being dropped, and Weak::upgrade will fail.
//
// The entry will never be empty while the BGL is still alive.
Entry::Occupied(entry) => Arc::clone(entry.get()),
// No entry exists for this resource.
//
// We know that the resource is not alive, so we can create a new entry.
Entry::Vacant(entry) => Arc::clone(entry.insert(Arc::new(OnceCell::new()))),
};
drop(map_guard);
// Some other thread may beat us to initializing the entry, but OnceCell guarentees that only one thread
// will actually initialize the entry.
//
// We pass the strong reference outside of the closure to keep it alive while we're the only one keeping a reference to it.
let mut strong = None;
let weak = entry.get_or_try_init(|| {
let strong_inner = constructor.take().unwrap()(key.take().unwrap())?;
let weak = Arc::downgrade(&strong_inner);
strong = Some(strong_inner);
Ok(weak)
})?;
// If strong is Some, that means we just initialized the entry, so we can just return it.
if let Some(strong) = strong {
return Ok(strong);
}
// The entry was already initialized by someone else, so we need to try to upgrade it.
if let Some(strong) = weak.upgrade() {
// We succeed, the resource is still alive, just return that.
return Ok(strong);
}
// The resource is in the process of being dropped, because upgrade failed. The entry still exists in the map, but it points to nothing.
//
// We're in a race with the drop implementation of the resource, so lets just go around again. When we go around again:
// - If the entry exists, we might need to go around a few more times.
// - If the entry doesn't exist, we'll create a new one.
continue 'race;
}
}
/// Remove the given entry map from the pool.
///
/// Must *only* be called in the Drop impl of [`BindGroupLayout`].
pub fn remove(&self, key: &K) {
let hashed_key = PreHashedKey::from_key(key);
let mut map_guard = self.inner.lock();
// Weak::upgrade will be failing long before this code is called. All threads trying to access the resource will be spinning,
// waiting for the entry to be removed. It is safe to remove the entry from the map.
map_guard.remove(&hashed_key);
}
}
#[cfg(test)]
mod tests {
use std::sync::{
atomic::{AtomicU32, Ordering},
Barrier,
};
use super::*;
#[test]
fn deduplication() {
let pool = ResourcePool::<u32, u32>::new();
let mut counter = 0_u32;
let arc1 = pool
.get_or_init::<_, ()>(0, |key| {
counter += 1;
Ok(Arc::new(key))
})
.unwrap();
assert_eq!(*arc1, 0);
assert_eq!(counter, 1);
let arc2 = pool
.get_or_init::<_, ()>(0, |key| {
counter += 1;
Ok(Arc::new(key))
})
.unwrap();
assert!(Arc::ptr_eq(&arc1, &arc2));
assert_eq!(*arc2, 0);
assert_eq!(counter, 1);
drop(arc1);
drop(arc2);
pool.remove(&0);
let arc3 = pool
.get_or_init::<_, ()>(0, |key| {
counter += 1;
Ok(Arc::new(key))
})
.unwrap();
assert_eq!(*arc3, 0);
assert_eq!(counter, 2);
}
// Test name has "2_threads" in the name so nextest reserves two threads for it.
#[test]
fn concurrent_creation_2_threads() {
struct Resources {
pool: ResourcePool<u32, u32>,
counter: AtomicU32,
barrier: Barrier,
}
let resources = Arc::new(Resources {
pool: ResourcePool::<u32, u32>::new(),
counter: AtomicU32::new(0),
barrier: Barrier::new(2),
});
// Like all races, this is not inherently guaranteed to work, but in practice it should work fine.
//
// To validate the expected order of events, we've put print statements in the code, indicating when each thread is at a certain point.
// The output will look something like this if the test is working as expected:
//
// ```
// 0: prewait
// 1: prewait
// 1: postwait
// 0: postwait
// 1: init
// 1: postget
// 0: postget
// ```
fn thread_inner(idx: u8, resources: &Resources) -> Arc<u32> {
eprintln!("{idx}: prewait");
// Once this returns, both threads should hit get_or_init at about the same time,
// allowing us to actually test concurrent creation.
//
// Like all races, this is not inherently guaranteed to work, but in practice it should work fine.
resources.barrier.wait();
eprintln!("{idx}: postwait");
let ret = resources
.pool
.get_or_init::<_, ()>(0, |key| {
eprintln!("{idx}: init");
// Simulate long running constructor, ensuring that both threads will be in get_or_init.
std::thread::sleep(std::time::Duration::from_millis(250));
resources.counter.fetch_add(1, Ordering::SeqCst);
Ok(Arc::new(key))
})
.unwrap();
eprintln!("{idx}: postget");
ret
}
let thread1 = std::thread::spawn({
let resource_clone = Arc::clone(&resources);
move || thread_inner(1, &resource_clone)
});
let arc0 = thread_inner(0, &resources);
assert_eq!(resources.counter.load(Ordering::Acquire), 1);
let arc1 = thread1.join().unwrap();
assert!(Arc::ptr_eq(&arc0, &arc1));
}
// Test name has "2_threads" in the name so nextest reserves two threads for it.
#[test]
fn create_while_drop_2_threads() {
struct Resources {
pool: ResourcePool<u32, u32>,
barrier: Barrier,
}
let resources = Arc::new(Resources {
pool: ResourcePool::<u32, u32>::new(),
barrier: Barrier::new(2),
});
// Like all races, this is not inherently guaranteed to work, but in practice it should work fine.
//
// To validate the expected order of events, we've put print statements in the code, indicating when each thread is at a certain point.
// The output will look something like this if the test is working as expected:
//
// ```
// 0: prewait
// 1: prewait
// 1: postwait
// 0: postwait
// 1: postsleep
// 1: removal
// 0: postget
// ```
//
// The last two _may_ be flipped.
let existing_entry = resources
.pool
.get_or_init::<_, ()>(0, |key| Ok(Arc::new(key)))
.unwrap();
// Drop the entry, but do _not_ remove it from the pool.
// This simulates the situation where the resource arc has been dropped, but the Drop implementation
// has not yet run, which calls remove.
drop(existing_entry);
fn thread0_inner(resources: &Resources) {
eprintln!("0: prewait");
resources.barrier.wait();
eprintln!("0: postwait");
// We try to create a new entry, but the entry already exists.
//
// As Arc::upgrade is failing, we will just keep spinning until remove is called.
resources
.pool
.get_or_init::<_, ()>(0, |key| Ok(Arc::new(key)))
.unwrap();
eprintln!("0: postget");
}
fn thread1_inner(resources: &Resources) {
eprintln!("1: prewait");
resources.barrier.wait();
eprintln!("1: postwait");
// We wait a little bit, making sure that thread0_inner has started spinning.
std::thread::sleep(std::time::Duration::from_millis(250));
eprintln!("1: postsleep");
// We remove the entry from the pool, allowing thread0_inner to re-create.
resources.pool.remove(&0);
eprintln!("1: removal");
}
let thread1 = std::thread::spawn({
let resource_clone = Arc::clone(&resources);
move || thread1_inner(&resource_clone)
});
thread0_inner(&resources);
thread1.join().unwrap();
}
}

View File

@ -27,6 +27,7 @@ use crate::{
identity::{GlobalIdentityHandlerFactory, Input},
init_tracker::TextureInitTracker,
resource::{self, ResourceInfo},
snatch::Snatchable,
track,
};
@ -77,7 +78,7 @@ pub enum ConfigureSurfaceError {
PreviousOutputExists,
#[error("Both `Surface` width and height must be non-zero. Wait to recreate the `Surface` until the window has non-zero area.")]
ZeroArea,
#[error("`Surface` width and height must be within the maximum supported texture size. Requested was ({width}, height), maximum extent is {max_texture_dimension_2d}.")]
#[error("`Surface` width and height must be within the maximum supported texture size. Requested was ({width}, {height}), maximum extent is {max_texture_dimension_2d}.")]
TooLarge {
width: u32,
height: u32,
@ -215,11 +216,11 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let mut presentation = surface.presentation.lock();
let present = presentation.as_mut().unwrap();
let texture = resource::Texture {
inner: RwLock::new(Some(resource::TextureInner::Surface {
inner: Snatchable::new(resource::TextureInner::Surface {
raw: Some(ast.texture),
parent_id: surface_id,
has_work: AtomicBool::new(false),
})),
}),
device: device.clone(),
desc: texture_desc,
hal_usage,
@ -325,8 +326,9 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let texture = hub.textures.unregister(texture_id);
if let Some(texture) = texture {
let mut exclusive_snatch_guard = device.snatchable_lock.write();
let suf = A::get_surface(&surface);
let mut inner = texture.inner_mut();
let mut inner = texture.inner_mut(&mut exclusive_snatch_guard);
let inner = inner.as_mut().unwrap();
match *inner {
@ -420,13 +422,14 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let texture = hub.textures.unregister(texture_id);
if let Some(texture) = texture {
let suf = A::get_surface(&surface);
match *texture.inner_mut().as_mut().take().as_mut().unwrap() {
&mut resource::TextureInner::Surface {
ref mut raw,
ref parent_id,
let exclusive_snatch_guard = device.snatchable_lock.write();
match texture.inner.snatch(exclusive_snatch_guard).unwrap() {
resource::TextureInner::Surface {
mut raw,
parent_id,
has_work: _,
} => {
if surface_id == *parent_id {
if surface_id == parent_id {
unsafe { suf.unwrap().raw.discard_texture(raw.take().unwrap()) };
} else {
log::warn!("Surface texture is outdated");

View File

@ -80,12 +80,21 @@ impl<I: id::TypedId + Copy, T: Resource<I>> FutureId<'_, I, T> {
Arc::new(value)
}
/// Assign a new resource to this ID.
///
/// Registers it with the registry, and fills out the resource info.
pub fn assign(self, value: T) -> (I, Arc<T>) {
let mut data = self.data.write();
data.insert(self.id, self.init(value));
(self.id, data.get(self.id).unwrap().clone())
}
/// Assign an existing resource to a new ID.
///
/// Registers it with the registry.
///
/// This _will_ leak the ID, and it will not be recycled again.
/// See https://github.com/gfx-rs/wgpu/issues/4912.
pub fn assign_existing(self, value: &Arc<T>) -> I {
let mut data = self.data.write();
debug_assert!(!data.contains(self.id));
@ -125,7 +134,7 @@ impl<I: id::TypedId, T: Resource<I>> Registry<I, T> {
self.read().try_get(id).map(|o| o.cloned())
}
pub(crate) fn get(&self, id: I) -> Result<Arc<T>, InvalidId> {
self.read().get(id).map(|v| v.clone())
self.read().get_owned(id)
}
pub(crate) fn read<'a>(&'a self) -> RwLockReadGuard<'a, Storage<T, I>> {
self.storage.read()

View File

@ -14,14 +14,14 @@ use crate::{
identity::{GlobalIdentityHandlerFactory, IdentityManager},
init_tracker::{BufferInitTracker, TextureInitTracker},
resource, resource_log,
snatch::{SnatchGuard, Snatchable},
snatch::{ExclusiveSnatchGuard, SnatchGuard, Snatchable},
track::TextureSelector,
validation::MissingBufferUsageError,
Label, SubmissionIndex,
};
use hal::CommandEncoder;
use parking_lot::{Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard};
use parking_lot::{Mutex, RwLock};
use smallvec::SmallVec;
use thiserror::Error;
use wgt::WasmNotSendSync;
@ -709,7 +709,7 @@ pub type TextureDescriptor<'a> = wgt::TextureDescriptor<Label<'a>, Vec<wgt::Text
#[derive(Debug)]
pub(crate) enum TextureInner<A: HalApi> {
Native {
raw: Option<A::Texture>,
raw: A::Texture,
},
Surface {
raw: Option<A::SurfaceTexture>,
@ -719,12 +719,10 @@ pub(crate) enum TextureInner<A: HalApi> {
}
impl<A: HalApi> TextureInner<A> {
pub fn as_raw(&self) -> Option<&A::Texture> {
match *self {
Self::Native { raw: Some(ref tex) } => Some(tex),
Self::Surface {
raw: Some(ref tex), ..
} => Some(tex.borrow()),
pub fn raw(&self) -> Option<&A::Texture> {
match self {
Self::Native { raw } => Some(raw),
Self::Surface { raw: Some(tex), .. } => Some(tex.borrow()),
_ => None,
}
}
@ -748,7 +746,7 @@ pub enum TextureClearMode<A: HalApi> {
#[derive(Debug)]
pub struct Texture<A: HalApi> {
pub(crate) inner: RwLock<Option<TextureInner<A>>>,
pub(crate) inner: Snatchable<TextureInner<A>>,
pub(crate) device: Arc<Device<A>>,
pub(crate) desc: wgt::TextureDescriptor<(), Vec<wgt::TextureFormat>>,
pub(crate) hal_usage: hal::TextureUses,
@ -789,11 +787,8 @@ impl<A: HalApi> Drop for Texture<A> {
}
_ => {}
};
if self.inner.read().is_none() {
return;
}
let inner = self.inner.write().take().unwrap();
if let TextureInner::Native { raw: Some(raw) } = inner {
if let Some(TextureInner::Native { raw }) = self.inner.take() {
unsafe {
self.device.raw().destroy_texture(raw);
}
@ -802,11 +797,15 @@ impl<A: HalApi> Drop for Texture<A> {
}
impl<A: HalApi> Texture<A> {
pub(crate) fn inner<'a>(&'a self) -> RwLockReadGuard<'a, Option<TextureInner<A>>> {
self.inner.read()
pub(crate) fn raw<'a>(&'a self, snatch_guard: &'a SnatchGuard) -> Option<&'a A::Texture> {
self.inner.get(snatch_guard)?.raw()
}
pub(crate) fn inner_mut<'a>(&'a self) -> RwLockWriteGuard<'a, Option<TextureInner<A>>> {
self.inner.write()
pub(crate) fn inner_mut<'a>(
&'a self,
guard: &mut ExclusiveSnatchGuard,
) -> Option<&'a mut TextureInner<A>> {
self.inner.get_mut(guard)
}
pub(crate) fn get_clear_view<'a>(
clear_mode: &'a TextureClearMode<A>,
@ -836,6 +835,50 @@ impl<A: HalApi> Texture<A> {
}
}
}
pub(crate) fn destroy(self: &Arc<Self>) -> Result<(), DestroyError> {
let device = &self.device;
let texture_id = self.info.id();
#[cfg(feature = "trace")]
if let Some(ref mut trace) = *device.trace.lock() {
trace.add(trace::Action::FreeTexture(texture_id));
}
let temp = {
let snatch_guard = device.snatchable_lock.write();
let raw = match self.inner.snatch(snatch_guard) {
Some(TextureInner::Native { raw }) => raw,
Some(TextureInner::Surface { .. }) => {
return Ok(());
}
None => {
return Err(resource::DestroyError::AlreadyDestroyed);
}
};
queue::TempResource::DestroyedTexture(Arc::new(DestroyedTexture {
raw: Some(raw),
device: Arc::clone(&self.device),
submission_index: self.info.submission_index(),
id: self.info.id.unwrap(),
label: self.info.label.clone(),
}))
};
let mut pending_writes = device.pending_writes.lock();
let pending_writes = pending_writes.as_mut().unwrap();
if pending_writes.dst_textures.contains_key(&texture_id) {
pending_writes.temp_resources.push(temp);
} else {
let last_submit_index = self.info.submission_index();
device
.lock_life()
.schedule_resource_destruction(temp, last_submit_index);
}
Ok(())
}
}
impl<G: GlobalIdentityHandlerFactory> Global<G> {
@ -850,9 +893,10 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
profiling::scope!("Texture::as_hal");
let hub = A::hub(self);
let texture = { hub.textures.try_get(id).ok().flatten() };
let inner = texture.as_ref().unwrap().inner();
let hal_texture = inner.as_ref().unwrap().as_raw();
let texture_opt = { hub.textures.try_get(id).ok().flatten() };
let texture = texture_opt.as_ref().unwrap();
let snatch_guard = texture.device.snatchable_lock.read();
let hal_texture = texture.raw(&snatch_guard);
hal_texture_callback(hal_texture);
}
@ -927,6 +971,38 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
}
}
/// A texture that has been marked as destroyed and is staged for actual deletion soon.
#[derive(Debug)]
pub struct DestroyedTexture<A: HalApi> {
raw: Option<A::Texture>,
device: Arc<Device<A>>,
label: String,
pub(crate) id: TextureId,
pub(crate) submission_index: u64,
}
impl<A: HalApi> DestroyedTexture<A> {
pub fn label(&self) -> &dyn Debug {
if !self.label.is_empty() {
return &self.label;
}
&self.id
}
}
impl<A: HalApi> Drop for DestroyedTexture<A> {
fn drop(&mut self) {
if let Some(raw) = self.raw.take() {
resource_log!("Deallocate raw Texture (destroyed) {:?}", self.label());
unsafe {
use hal::Device;
self.device.raw().destroy_texture(raw);
}
}
}
}
#[derive(Clone, Copy, Debug)]
pub enum TextureErrorDimension {
X,

View File

@ -30,6 +30,11 @@ impl<T> Snatchable<T> {
unsafe { (*self.value.get()).as_ref() }
}
/// Get write access to the value. Requires a the snatchable lock's write guard.
pub fn get_mut(&self, _guard: &mut ExclusiveSnatchGuard) -> Option<&mut T> {
unsafe { (*self.value.get()).as_mut() }
}
/// Take the value. Requires a the snatchable lock's write guard.
pub fn snatch(&self, _guard: ExclusiveSnatchGuard) -> Option<T> {
unsafe { (*self.value.get()).take() }

View File

@ -131,6 +131,12 @@ where
result
}
/// Get an owned reference to an item behind a potentially invalid ID.
/// Panics if there is an epoch mismatch, or the entry is empty.
pub(crate) fn get_owned(&self, id: I) -> Result<Arc<T>, InvalidId> {
Ok(Arc::clone(self.get(id)?))
}
pub(crate) fn label_for_invalid_id(&self, id: I) -> &str {
let (index, _, _) = id.unzip();
match self.map.get(index as usize) {

View File

@ -151,12 +151,7 @@ impl PendingTransition<hal::BufferUses> {
impl PendingTransition<hal::TextureUses> {
/// Produce the hal barrier corresponding to the transition.
pub fn into_hal<'a, A: HalApi>(
self,
tex: &'a resource::TextureInner<A>,
) -> hal::TextureBarrier<'a, A> {
let texture = tex.as_raw().expect("Texture is destroyed");
pub fn into_hal<'a, A: HalApi>(self, texture: &'a A::Texture) -> hal::TextureBarrier<'a, A> {
// These showing up in a barrier is always a bug
strict_assert_ne!(self.usage.start, hal::TextureUses::UNKNOWN);
strict_assert_ne!(self.usage.end, hal::TextureUses::UNKNOWN);

View File

@ -24,6 +24,7 @@ use crate::{
hal_api::HalApi,
id::{TextureId, TypedId},
resource::{Resource, Texture, TextureInner},
snatch::SnatchGuard,
track::{
invalid_resource_state, skip_barrier, ResourceMetadata, ResourceMetadataProvider,
ResourceUses, UsageConflict,
@ -34,7 +35,7 @@ use hal::TextureUses;
use arrayvec::ArrayVec;
use naga::FastHashMap;
use parking_lot::{Mutex, RwLockReadGuard};
use parking_lot::Mutex;
use wgt::{strict_assert, strict_assert_eq};
use std::{borrow::Cow, iter, marker::PhantomData, ops::Range, sync::Arc, vec::Drain};
@ -497,17 +498,15 @@ impl<A: HalApi> TextureTracker<A> {
/// Drain all currently pending transitions.
pub fn drain_transitions<'a>(
&'a mut self,
) -> (
PendingTransitionList,
Vec<RwLockReadGuard<'a, Option<TextureInner<A>>>>,
) {
snatch_guard: &'a SnatchGuard<'a>,
) -> (PendingTransitionList, Vec<Option<&'a TextureInner<A>>>) {
let mut textures = Vec::new();
let transitions = self
.temp
.drain(..)
.map(|pending| {
let tex = unsafe { self.metadata.get_resource_unchecked(pending.id as _) };
textures.push(tex.inner());
textures.push(tex.inner.get(snatch_guard));
pending
})
.collect();

View File

@ -1,4 +1,5 @@
use crate::{binding_model::BindEntryMap, FastHashMap, FastHashSet};
use crate::{device::bgl, FastHashMap, FastHashSet};
use arrayvec::ArrayVec;
use std::{collections::hash_map::Entry, fmt};
use thiserror::Error;
use wgt::{BindGroupLayoutEntry, BindingType};
@ -774,6 +775,27 @@ pub fn check_texture_format(
}
}
pub enum BindingLayoutSource<'a> {
/// The binding layout is derived from the pipeline layout.
///
/// This will be filled in by the shader binding validation, as it iterates the shader's interfaces.
Derived(ArrayVec<bgl::EntryMap, { hal::MAX_BIND_GROUPS }>),
/// The binding layout is provided by the user in BGLs.
///
/// This will be validated against the shader's interfaces.
Provided(ArrayVec<&'a bgl::EntryMap, { hal::MAX_BIND_GROUPS }>),
}
impl<'a> BindingLayoutSource<'a> {
pub fn new_derived(limits: &wgt::Limits) -> Self {
let mut array = ArrayVec::new();
for _ in 0..limits.max_bind_groups {
array.push(Default::default());
}
BindingLayoutSource::Derived(array)
}
}
pub type StageIo = FastHashMap<wgt::ShaderLocation, InterfaceVar>;
impl Interface {
@ -933,8 +955,7 @@ impl Interface {
pub fn check_stage(
&self,
given_layouts: Option<&[&BindEntryMap]>,
derived_layouts: &mut [BindEntryMap],
layouts: &mut BindingLayoutSource<'_>,
shader_binding_sizes: &mut FastHashMap<naga::ResourceBinding, wgt::BufferSize>,
entry_point_name: &str,
stage_bit: wgt::ShaderStages,
@ -958,45 +979,53 @@ impl Interface {
// check resources visibility
for &handle in entry_point.resources.iter() {
let res = &self.resources[handle];
let result = match given_layouts {
Some(layouts) => {
// update the required binding size for this buffer
if let ResourceType::Buffer { size } = res.ty {
match shader_binding_sizes.entry(res.bind.clone()) {
Entry::Occupied(e) => {
*e.into_mut() = size.max(*e.get());
}
Entry::Vacant(e) => {
e.insert(size);
let result = 'err: {
match layouts {
BindingLayoutSource::Provided(layouts) => {
// update the required binding size for this buffer
if let ResourceType::Buffer { size } = res.ty {
match shader_binding_sizes.entry(res.bind.clone()) {
Entry::Occupied(e) => {
*e.into_mut() = size.max(*e.get());
}
Entry::Vacant(e) => {
e.insert(size);
}
}
}
let Some(map) = layouts.get(res.bind.group as usize) else {
break 'err Err(BindingError::Missing);
};
let Some(entry) = map.get(res.bind.binding) else {
break 'err Err(BindingError::Missing);
};
if !entry.visibility.contains(stage_bit) {
break 'err Err(BindingError::Invisible);
}
res.check_binding_use(entry)
}
layouts
.get(res.bind.group as usize)
.and_then(|map| map.get(&res.bind.binding))
.ok_or(BindingError::Missing)
.and_then(|entry| {
if entry.visibility.contains(stage_bit) {
Ok(entry)
} else {
Err(BindingError::Invisible)
BindingLayoutSource::Derived(layouts) => {
let Some(map) = layouts.get_mut(res.bind.group as usize) else {
break 'err Err(BindingError::Missing);
};
let ty = match res.derive_binding_type() {
Ok(ty) => ty,
Err(error) => break 'err Err(error),
};
match map.entry(res.bind.binding) {
indexmap::map::Entry::Occupied(e) if e.get().ty != ty => {
break 'err Err(BindingError::InconsistentlyDerivedType)
}
})
.and_then(|entry| res.check_binding_use(entry))
}
None => derived_layouts
.get_mut(res.bind.group as usize)
.ok_or(BindingError::Missing)
.and_then(|set| {
let ty = res.derive_binding_type()?;
match set.entry(res.bind.binding) {
Entry::Occupied(e) if e.get().ty != ty => {
return Err(BindingError::InconsistentlyDerivedType)
}
Entry::Occupied(e) => {
indexmap::map::Entry::Occupied(e) => {
e.into_mut().visibility |= stage_bit;
}
Entry::Vacant(e) => {
indexmap::map::Entry::Vacant(e) => {
e.insert(BindGroupLayoutEntry {
binding: res.bind.binding,
ty,
@ -1006,20 +1035,28 @@ impl Interface {
}
}
Ok(())
}),
}
}
};
if let Err(error) = result {
return Err(StageError::Binding(res.bind.clone(), error));
}
}
// check the compatibility between textures and samplers
if let Some(layouts) = given_layouts {
// Check the compatibility between textures and samplers
//
// We only need to do this if the binding layout is provided by the user, as derived
// layouts will inherently be correctly tagged.
if let BindingLayoutSource::Provided(layouts) = layouts {
for &(texture_handle, sampler_handle) in entry_point.sampling_pairs.iter() {
let texture_bind = &self.resources[texture_handle].bind;
let sampler_bind = &self.resources[sampler_handle].bind;
let texture_layout = &layouts[texture_bind.group as usize][&texture_bind.binding];
let sampler_layout = &layouts[sampler_bind.group as usize][&sampler_bind.binding];
let texture_layout = layouts[texture_bind.group as usize]
.get(texture_bind.binding)
.unwrap();
let sampler_layout = layouts[sampler_bind.group as usize]
.get(sampler_bind.binding)
.unwrap();
assert!(texture_layout.visibility.contains(stage_bit));
assert!(sampler_layout.visibility.contains(stage_bit));

File diff suppressed because one or more lines are too long

View File

@ -89,7 +89,7 @@ path = "../naga"
features = ["wgsl-in"]
[dev-dependencies.winit]
version = "0.29.6"
version = "0.29.8"
features = ["android-native-activity"]
[features]
@ -222,7 +222,7 @@ version = "0.5"
optional = true
[target."cfg(windows)".dependencies.gpu-allocator]
version = "0.24"
version = "0.25"
features = [
"d3d12",
"public-winapi",

View File

@ -20,7 +20,7 @@ impl crate::BufferTextureCopy {
&self,
format: wgt::TextureFormat,
) -> d3d12_ty::D3D12_PLACED_SUBRESOURCE_FOOTPRINT {
let (block_width, block_height) = format.block_dimensions();
let (block_width, _) = format.block_dimensions();
d3d12_ty::D3D12_PLACED_SUBRESOURCE_FOOTPRINT {
Offset: self.buffer_layout.offset,
Footprint: d3d12_ty::D3D12_SUBRESOURCE_FOOTPRINT {
@ -30,10 +30,7 @@ impl crate::BufferTextureCopy {
)
.unwrap(),
Width: self.size.width,
Height: self
.buffer_layout
.rows_per_image
.map_or(self.size.height, |count| count * block_height),
Height: self.size.height,
Depth: self.size.depth,
RowPitch: {
let actual = self.buffer_layout.bytes_per_row.unwrap_or_else(|| {

View File

@ -99,7 +99,7 @@ mod dxc {
let dxil = match hassle_rs::Dxil::new(dxil_path) {
Ok(dxil) => dxil,
Err(e) => {
log::warn!("Failed to load dxil.dll. Defaulting to DXC instead: {}", e);
log::warn!("Failed to load dxil.dll. Defaulting to FXC instead: {}", e);
return Ok(None);
}
};

View File

@ -220,7 +220,6 @@ impl super::Adapter {
let full_ver = Self::parse_full_version(&version).ok();
let es_ver = full_ver.map_or_else(|| Self::parse_version(&version).ok(), |_| None);
let web_gl = cfg!(target_arch = "wasm32");
if let Some(full_ver) = full_ver {
let core_profile = (full_ver >= (3, 2)).then_some(unsafe {
@ -608,10 +607,7 @@ impl super::Adapter {
super::PrivateCapabilities::TEXTURE_STORAGE,
supported((3, 0), (4, 2)),
);
private_caps.set(
super::PrivateCapabilities::DEBUG_FNS,
supported((3, 2), (4, 3)) && !web_gl,
);
private_caps.set(super::PrivateCapabilities::DEBUG_FNS, gl.supports_debug());
private_caps.set(
super::PrivateCapabilities::INVALIDATE_FRAMEBUFFER,
supported((3, 0), (4, 3)),
@ -1046,9 +1042,10 @@ impl crate::Adapter<super::Api> for super::Adapter {
Tf::Rg16Unorm => empty,
Tf::Rg16Snorm => empty,
Tf::Rg16Float => filterable | half_float_renderable,
Tf::Rgba8Unorm | Tf::Rgba8UnormSrgb => filterable_renderable | storage,
Tf::Rgba8Unorm => filterable_renderable | storage,
Tf::Rgba8UnormSrgb => filterable_renderable,
Tf::Bgra8Unorm | Tf::Bgra8UnormSrgb => filterable_renderable,
Tf::Rgba8Snorm => filterable,
Tf::Rgba8Snorm => filterable | storage,
Tf::Rgba8Uint => renderable | storage,
Tf::Rgba8Sint => renderable | storage,
Tf::Rgb10a2Uint => renderable,
@ -1071,7 +1068,7 @@ impl crate::Adapter<super::Api> for super::Adapter {
| Tf::Depth32FloatStencil8
| Tf::Depth24Plus
| Tf::Depth24PlusStencil8 => depth,
Tf::NV12 => unreachable!(),
Tf::NV12 => empty,
Tf::Rgb9e5Ufloat => filterable,
Tf::Bc1RgbaUnorm
| Tf::Bc1RgbaUnormSrgb

View File

@ -344,7 +344,7 @@ impl super::Device {
let program = unsafe { gl.create_program() }.unwrap();
#[cfg(not(target_arch = "wasm32"))]
if let Some(label) = label {
if gl.supports_debug() {
if private_caps.contains(PrivateCapabilities::DEBUG_FNS) {
let name = unsafe { mem::transmute(program) };
unsafe { gl.object_label(glow::PROGRAM, name, Some(label)) };
}
@ -593,7 +593,11 @@ impl crate::Device<super::Api> for super::Device {
#[cfg(not(target_arch = "wasm32"))]
if let Some(label) = desc.label {
if gl.supports_debug() {
if self
.shared
.private_caps
.contains(PrivateCapabilities::DEBUG_FNS)
{
let name = unsafe { mem::transmute(raw) };
unsafe { gl.object_label(glow::BUFFER, name, Some(label)) };
}
@ -732,7 +736,11 @@ impl crate::Device<super::Api> for super::Device {
#[cfg(not(target_arch = "wasm32"))]
if let Some(label) = desc.label {
if gl.supports_debug() {
if self
.shared
.private_caps
.contains(PrivateCapabilities::DEBUG_FNS)
{
let name = unsafe { mem::transmute(raw) };
unsafe { gl.object_label(glow::RENDERBUFFER, name, Some(label)) };
}
@ -896,7 +904,11 @@ impl crate::Device<super::Api> for super::Device {
#[cfg(not(target_arch = "wasm32"))]
if let Some(label) = desc.label {
if gl.supports_debug() {
if self
.shared
.private_caps
.contains(PrivateCapabilities::DEBUG_FNS)
{
let name = unsafe { mem::transmute(raw) };
unsafe { gl.object_label(glow::TEXTURE, name, Some(label)) };
}
@ -1035,7 +1047,11 @@ impl crate::Device<super::Api> for super::Device {
#[cfg(not(target_arch = "wasm32"))]
if let Some(label) = desc.label {
if gl.supports_debug() {
if self
.shared
.private_caps
.contains(PrivateCapabilities::DEBUG_FNS)
{
let name = unsafe { mem::transmute(raw) };
unsafe { gl.object_label(glow::SAMPLER, name, Some(label)) };
}

View File

@ -1711,7 +1711,17 @@ impl crate::Adapter<super::Api> for super::Adapter {
.framebuffer_stencil_sample_counts
.min(limits.sampled_image_stencil_sample_counts)
} else {
match format.sample_type(None, None).unwrap() {
let first_aspect = format_aspect
.iter()
.next()
.expect("All texture should at least one aspect")
.map();
// We should never get depth or stencil out of this, due to the above.
assert_ne!(first_aspect, wgt::TextureAspect::DepthOnly);
assert_ne!(first_aspect, wgt::TextureAspect::StencilOnly);
match format.sample_type(Some(first_aspect), None).unwrap() {
wgt::TextureSampleType::Float { .. } => limits
.framebuffer_color_sample_counts
.min(limits.sampled_image_color_sample_counts),

View File

@ -1,6 +1,7 @@
use std::{
ffi::{c_void, CStr, CString},
slice,
str::FromStr,
sync::Arc,
thread,
};
@ -855,11 +856,16 @@ impl crate::Instance<super::Api> for super::Instance {
{
// Check if mesa driver and version less than 21.2
if let Some(version) = exposed.info.driver_info.split_once("Mesa ").map(|s| {
s.1.rsplit_once('.')
.map(|v| v.0.parse::<f32>().unwrap_or_default())
.unwrap_or_default()
let mut components = s.1.split('.');
let major = components.next().and_then(|s| u8::from_str(s).ok());
let minor = components.next().and_then(|s| u8::from_str(s).ok());
if let (Some(major), Some(minor)) = (major, minor) {
(major, minor)
} else {
(0, 0)
}
}) {
if version < 21.2 {
if version < (21, 2) {
// See https://gitlab.freedesktop.org/mesa/mesa/-/issues/4688
log::warn!(
"Disabling presentation on '{}' (id {:?}) due to NV Optimus and Intel Mesa < v21.2",

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"18549fb7d7de2ea2481f30292dca63889856a33bd1b3698e16cee6631ab65df4","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","src/assertions.rs":"3fe98027aa73970c8ab7874a3e13dbfd6faa87df2081beb5c83aeec4c60f372f","src/lib.rs":"30e85d18f040cedb37861ef734a41df9fab730d868b25db3158921aa6bfc44a3","src/math.rs":"4d03039736dd6926feb139bc68734cb59df34ede310427bbf059e5c925e0af3b"},"package":null}
{"files":{"Cargo.toml":"be3f23b1527145b0f4c5f29dfdfa5865f7bb23a517c6d42f665dcb750129ff56","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","src/assertions.rs":"3fe98027aa73970c8ab7874a3e13dbfd6faa87df2081beb5c83aeec4c60f372f","src/lib.rs":"30e85d18f040cedb37861ef734a41df9fab730d868b25db3158921aa6bfc44a3","src/math.rs":"4d03039736dd6926feb139bc68734cb59df34ede310427bbf059e5c925e0af3b"},"package":null}

View File

@ -45,7 +45,7 @@ features = ["serde_derive"]
optional = true
[dev-dependencies]
serde_json = "1.0.108"
serde_json = "1.0.111"
[dev-dependencies.serde]
version = "1"