зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
915014cad0
Коммит
ff86798488
|
@ -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"]
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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']
|
||||
|
||||
|
|
|
@ -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]]
|
||||
|
|
|
@ -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"
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -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]
|
||||
|
|
|
@ -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]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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 })
|
||||
}
|
||||
|
|
|
@ -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"}
|
|
@ -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"
|
||||
|
|
|
@ -64,8 +64,8 @@
|
|||
//! - RefCell\<T\>
|
||||
//! - Mutex\<T\>
|
||||
//! - RwLock\<T\>
|
||||
//! - Rc\<T\> *(if* features = ["rc"] *is enabled)*
|
||||
//! - Arc\<T\> *(if* features = ["rc"] *is enabled)*
|
||||
//! - Rc\<T\> *(if* features = \["rc"\] *is enabled)*
|
||||
//! - Arc\<T\> *(if* features = \["rc"\] *is enabled)*
|
||||
//! - **Collection types**:
|
||||
//! - BTreeMap\<K, V\>
|
||||
//! - BTreeSet\<T\>
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -61,8 +61,8 @@
|
|||
//! - RefCell\<T\>
|
||||
//! - Mutex\<T\>
|
||||
//! - RwLock\<T\>
|
||||
//! - Rc\<T\> *(if* features = ["rc"] *is enabled)*
|
||||
//! - Arc\<T\> *(if* features = ["rc"] *is enabled)*
|
||||
//! - Rc\<T\> *(if* features = \["rc"\] *is enabled)*
|
||||
//! - Arc\<T\> *(if* features = \["rc"\] *is enabled)*
|
||||
//! - **Collection types**:
|
||||
//! - BTreeMap\<K, V\>
|
||||
//! - BTreeSet\<T\>
|
||||
|
|
|
@ -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"}
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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"}
|
|
@ -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",
|
||||
]
|
||||
|
|
|
@ -18,7 +18,7 @@ First add to your `Cargo.toml`:
|
|||
|
||||
```toml
|
||||
[dependencies]
|
||||
spirv = "0.2.0+1.5.4"
|
||||
spirv = "0.3.0"
|
||||
```
|
||||
|
||||
Version
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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\" }" },
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -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}
|
|
@ -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"
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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() }
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -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",
|
||||
|
|
|
@ -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(|| {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)) };
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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}
|
|
@ -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"
|
||||
|
|
Загрузка…
Ссылка в новой задаче