Bug 1878375 - Synchronize vendored Rust libraries with mozilla-central. r=leftmostcat
mozilla-central: 0d84aa48c2d6687c0f0c4e54bd87db960c71d0fc comm-central: 6fb59d66a6352e1d7a28f59e23a73a6bc1dac34a Differential Revision: https://phabricator.services.mozilla.com/D209761 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
18c8fab9c9
Коммит
d93354e048
|
@ -21,14 +21,9 @@ git = "https://github.com/franziskuskiefer/cose-rust"
|
|||
rev = "43c22248d136c8b38fe42ea709d08da6355cf04b"
|
||||
replace-with = "vendored-sources"
|
||||
|
||||
[source."git+https://github.com/gfx-rs/metal-rs?rev=ff8fd3d6dc7792852f8a015458d7e6d42d7fb352"]
|
||||
git = "https://github.com/gfx-rs/metal-rs"
|
||||
rev = "ff8fd3d6dc7792852f8a015458d7e6d42d7fb352"
|
||||
replace-with = "vendored-sources"
|
||||
|
||||
[source."git+https://github.com/gfx-rs/wgpu?rev=d00a69615b74ef75aeb428a7c00fa1a91eb13e97"]
|
||||
[source."git+https://github.com/gfx-rs/wgpu?rev=d5d683d3c491ec8cd2f5cdb43ac61e526cb7c231"]
|
||||
git = "https://github.com/gfx-rs/wgpu"
|
||||
rev = "d00a69615b74ef75aeb428a7c00fa1a91eb13e97"
|
||||
rev = "d5d683d3c491ec8cd2f5cdb43ac61e526cb7c231"
|
||||
replace-with = "vendored-sources"
|
||||
|
||||
[source."git+https://github.com/glandium/mio?rev=9a2ef335c366044ffe73b1c4acabe50a1daefe05"]
|
||||
|
|
|
@ -1034,8 +1034,8 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "d3d12"
|
||||
version = "0.19.0"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=d00a69615b74ef75aeb428a7c00fa1a91eb13e97#d00a69615b74ef75aeb428a7c00fa1a91eb13e97"
|
||||
version = "0.20.0"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=d5d683d3c491ec8cd2f5cdb43ac61e526cb7c231#d5d683d3c491ec8cd2f5cdb43ac61e526cb7c231"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"libloading 0.8.3",
|
||||
|
@ -3010,8 +3010,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "metal"
|
||||
version = "0.27.0"
|
||||
source = "git+https://github.com/gfx-rs/metal-rs?rev=ff8fd3d6dc7792852f8a015458d7e6d42d7fb352#ff8fd3d6dc7792852f8a015458d7e6d42d7fb352"
|
||||
version = "0.28.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5637e166ea14be6063a3f8ba5ccb9a4159df7d8f6d61c02fc3d480b1f90dcfcb"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"block",
|
||||
|
@ -3257,8 +3258,8 @@ checksum = "a2983372caf4480544083767bf2d27defafe32af49ab4df3a0b7fc90793a3664"
|
|||
|
||||
[[package]]
|
||||
name = "naga"
|
||||
version = "0.19.2"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=d00a69615b74ef75aeb428a7c00fa1a91eb13e97#d00a69615b74ef75aeb428a7c00fa1a91eb13e97"
|
||||
version = "0.20.0"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=d5d683d3c491ec8cd2f5cdb43ac61e526cb7c231#d5d683d3c491ec8cd2f5cdb43ac61e526cb7c231"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bit-set",
|
||||
|
@ -5529,14 +5530,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wgpu-core"
|
||||
version = "0.19.3"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=d00a69615b74ef75aeb428a7c00fa1a91eb13e97#d00a69615b74ef75aeb428a7c00fa1a91eb13e97"
|
||||
version = "0.20.0"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=d5d683d3c491ec8cd2f5cdb43ac61e526cb7c231#d5d683d3c491ec8cd2f5cdb43ac61e526cb7c231"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bit-vec",
|
||||
"bitflags 2.5.0",
|
||||
"cfg_aliases",
|
||||
"codespan-reporting",
|
||||
"document-features",
|
||||
"indexmap 2.2.6",
|
||||
"log",
|
||||
|
@ -5556,8 +5556,8 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wgpu-hal"
|
||||
version = "0.19.3"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=d00a69615b74ef75aeb428a7c00fa1a91eb13e97#d00a69615b74ef75aeb428a7c00fa1a91eb13e97"
|
||||
version = "0.20.0"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=d5d683d3c491ec8cd2f5cdb43ac61e526cb7c231#d5d683d3c491ec8cd2f5cdb43ac61e526cb7c231"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"arrayvec",
|
||||
|
@ -5595,8 +5595,8 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wgpu-types"
|
||||
version = "0.19.2"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=d00a69615b74ef75aeb428a7c00fa1a91eb13e97#d00a69615b74ef75aeb428a7c00fa1a91eb13e97"
|
||||
version = "0.20.0"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=d5d683d3c491ec8cd2f5cdb43ac61e526cb7c231#d5d683d3c491ec8cd2f5cdb43ac61e526cb7c231"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"js-sys",
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"mc_workspace_toml": "69d10cf0366d47dfbdc0d2aa5887148a7868a2fcfc67ed441f8d172c7704d25788640eddacb862804bc7ac9dffae3631931bb16131a4d068434089fff8b45202", "mc_gkrust_toml": "7b85230288493ac65c5496e68dd5b14661b51bc7667784c7afd8608bccb814195ca20d8e6a29f207190024607037f6621fa527c370be69bb9e28fc1cb51a8700", "mc_cargo_lock": "1395de27388bdfba890a884d7adc1965c69edcd22c8a320106ca14a93baec8c24990342de3dca1e63f0ad3bed20acfecec14b2135ab1b5644f734f20c4db3d6d"}
|
||||
{"mc_workspace_toml": "69d10cf0366d47dfbdc0d2aa5887148a7868a2fcfc67ed441f8d172c7704d25788640eddacb862804bc7ac9dffae3631931bb16131a4d068434089fff8b45202", "mc_gkrust_toml": "7b85230288493ac65c5496e68dd5b14661b51bc7667784c7afd8608bccb814195ca20d8e6a29f207190024607037f6621fa527c370be69bb9e28fc1cb51a8700", "mc_cargo_lock": "04934e849b60fe346c1d04d816c06c65eb87d611ae1f855f45ef33aec1d6466d4559b8d3881e85a0d2628e8cb12b6e61e8a267e9bb045de65940ed9a0db96197"}
|
|
@ -1 +1 @@
|
|||
{"files":{"CHANGELOG.md":"45fa76b0e5bc51721887147000e9e78a5934cb04d1ad628e501ef2082763d353","Cargo.toml":"a3135c67216ba021525ebc8d18dc3de5d779f1a1ddde5f25f4439acabd45824a","README.md":"76cee3209f773a62535de6c9724b53f158406359f35b4d48b17ac3747b6c102e","src/com.rs":"cfd6556a7abf38cba57559038f9f2cf86274418448fb2745436c251a99575e05","src/command_allocator.rs":"ef01059a661749470f3772d188fe0fab0f002e1d154facdab4b9b2932f4b2d93","src/command_list.rs":"8723f3b755b721e0dbb234bd604956c1b7922a2368231197495daa3fa6548e63","src/debug.rs":"aa33b98f7c3e71cba75fc42c6ca9af72d96b45122422c16e48525e24590c57bf","src/descriptor.rs":"fea0b820de1566b54d17d8d0c67e6f5a2126eda19526397eb710ff7d6db9db9e","src/device.rs":"c1dd479aabd22bced0d407523d60629ad1da439fb47ad89fe7b48bae1c4b23e5","src/dxgi.rs":"1516186845b91bf3df813a29b4a0e00a85ca5649fb7a2755da43fba984c41a42","src/heap.rs":"dae2380684896c97e97ed022929f79ce2cc4f5418a3ec34883086f7c88f423d0","src/lib.rs":"612e2f471b84502d219da3fb86ee13f3cbd6faf17d77407bab6c84e51ec424d0","src/pso.rs":"ff819c321536695e34a3be9a6051cf3e57765049a4a2035db6ab27add5a7978a","src/query.rs":"ff61a2b76a108afc1f082724bb9b07ac8b52afbe97356e0fcf6df0ff7e53e07d","src/queue.rs":"bd32813d0b8a3bedf3223b69ade9f9c799a138a9e27d970f86435d9ce32d1557","src/resource.rs":"8989cdb7c3ee0687c826047f39f85148459d9219754f20a970bf8aaa09b96e27","src/sync.rs":"5c287fb7498242a397eb1f08887be9cff9b48dc7cb13af5792cce5f7182b55f8"},"package":null}
|
||||
{"files":{"CHANGELOG.md":"45fa76b0e5bc51721887147000e9e78a5934cb04d1ad628e501ef2082763d353","Cargo.toml":"9938addd7ce2c7785a9ca11eb0049271317f9b05fdf0d7330d4a80f0e07ab500","README.md":"76cee3209f773a62535de6c9724b53f158406359f35b4d48b17ac3747b6c102e","src/com.rs":"cfd6556a7abf38cba57559038f9f2cf86274418448fb2745436c251a99575e05","src/command_allocator.rs":"ef01059a661749470f3772d188fe0fab0f002e1d154facdab4b9b2932f4b2d93","src/command_list.rs":"8723f3b755b721e0dbb234bd604956c1b7922a2368231197495daa3fa6548e63","src/debug.rs":"aa33b98f7c3e71cba75fc42c6ca9af72d96b45122422c16e48525e24590c57bf","src/descriptor.rs":"fea0b820de1566b54d17d8d0c67e6f5a2126eda19526397eb710ff7d6db9db9e","src/device.rs":"c1dd479aabd22bced0d407523d60629ad1da439fb47ad89fe7b48bae1c4b23e5","src/dxgi.rs":"1516186845b91bf3df813a29b4a0e00a85ca5649fb7a2755da43fba984c41a42","src/heap.rs":"dae2380684896c97e97ed022929f79ce2cc4f5418a3ec34883086f7c88f423d0","src/lib.rs":"612e2f471b84502d219da3fb86ee13f3cbd6faf17d77407bab6c84e51ec424d0","src/pso.rs":"ff819c321536695e34a3be9a6051cf3e57765049a4a2035db6ab27add5a7978a","src/query.rs":"ff61a2b76a108afc1f082724bb9b07ac8b52afbe97356e0fcf6df0ff7e53e07d","src/queue.rs":"bd32813d0b8a3bedf3223b69ade9f9c799a138a9e27d970f86435d9ce32d1557","src/resource.rs":"8989cdb7c3ee0687c826047f39f85148459d9219754f20a970bf8aaa09b96e27","src/sync.rs":"5c287fb7498242a397eb1f08887be9cff9b48dc7cb13af5792cce5f7182b55f8"},"package":null}
|
|
@ -12,7 +12,7 @@
|
|||
[package]
|
||||
edition = "2018"
|
||||
name = "d3d12"
|
||||
version = "0.19.0"
|
||||
version = "0.20.0"
|
||||
authors = ["gfx-rs developers"]
|
||||
description = "Low level D3D12 API wrapper"
|
||||
documentation = "https://docs.rs/d3d12"
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1,51 +0,0 @@
|
|||
name: ci
|
||||
|
||||
on: [pull_request, push]
|
||||
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
CARGO_INCREMENTAL: 0
|
||||
RUSTFLAGS: "-Cdebuginfo=0 --deny=warnings"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macos-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
channel: [stable, nightly]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
toolchain: ${{ matrix.channel }}
|
||||
|
||||
- name: Rust Version Info
|
||||
run: rustc --version && cargo --version
|
||||
|
||||
- name: Cache cargo registry
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cargo/registry
|
||||
key: ${{ runner.os }}-${{ matrix.channel }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
|
||||
|
||||
- name: Cache cargo index
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cargo/git
|
||||
key: ${{ runner.os }}-${{ matrix.channel }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}
|
||||
|
||||
- name: Cache cargo build
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: target
|
||||
key: ${{ runner.os }}-${{ matrix.channel }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
|
||||
|
||||
- name: cargo check
|
||||
run: cargo check --all-features
|
||||
|
||||
- name: Run all tests
|
||||
run: cargo test --all-features
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -12,7 +12,7 @@
|
|||
[package]
|
||||
edition = "2021"
|
||||
name = "metal"
|
||||
version = "0.27.0"
|
||||
version = "0.28.0"
|
||||
authors = ["gfx-rs developers"]
|
||||
exclude = [
|
||||
"guide/**/*",
|
||||
|
@ -90,35 +90,54 @@ required-features = ["dispatch"]
|
|||
[[example]]
|
||||
name = "fence"
|
||||
|
||||
[dependencies]
|
||||
bitflags = "2"
|
||||
block = "0.1.6"
|
||||
core-graphics-types = "0.1.3"
|
||||
foreign-types = "0.5"
|
||||
log = "0.4"
|
||||
paste = "1"
|
||||
[dependencies.bitflags]
|
||||
version = "2"
|
||||
|
||||
[dependencies.block]
|
||||
version = "0.1.6"
|
||||
|
||||
[dependencies.core-graphics-types]
|
||||
version = "0.1.3"
|
||||
|
||||
[dependencies.dispatch]
|
||||
version = "0.2"
|
||||
optional = true
|
||||
|
||||
[dependencies.foreign-types]
|
||||
version = "0.5"
|
||||
|
||||
[dependencies.log]
|
||||
version = "0.4"
|
||||
|
||||
[dependencies.objc]
|
||||
version = "0.2.4"
|
||||
|
||||
[dev-dependencies]
|
||||
cocoa = "0.24.0"
|
||||
cty = "0.2.1"
|
||||
glam = "0.22"
|
||||
png = "0.17"
|
||||
rand = "0.8"
|
||||
sema = "0.1.4"
|
||||
winit = "0.27"
|
||||
[dependencies.paste]
|
||||
version = "1"
|
||||
|
||||
[dev-dependencies.cocoa]
|
||||
version = "0.24.0"
|
||||
|
||||
[dev-dependencies.cty]
|
||||
version = "0.2.1"
|
||||
|
||||
[dev-dependencies.glam]
|
||||
version = "0.22"
|
||||
|
||||
[dev-dependencies.png]
|
||||
version = "0.17"
|
||||
|
||||
[dev-dependencies.rand]
|
||||
version = "0.8"
|
||||
|
||||
[dev-dependencies.sema]
|
||||
version = "0.1.4"
|
||||
|
||||
[dev-dependencies.winit]
|
||||
version = "0.27"
|
||||
|
||||
[features]
|
||||
default = ["link"]
|
||||
link = ["core-graphics-types/link"]
|
||||
mps = []
|
||||
private = []
|
||||
|
||||
[workspace]
|
||||
members = ["examples/texture"]
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
out.png
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -13,7 +13,7 @@
|
|||
edition = "2021"
|
||||
rust-version = "1.74"
|
||||
name = "naga"
|
||||
version = "0.19.2"
|
||||
version = "0.20.0"
|
||||
authors = ["gfx-rs developers"]
|
||||
exclude = [
|
||||
"bin/**/*",
|
||||
|
|
|
@ -129,8 +129,10 @@ pub fn process_overrides<'a>(
|
|||
Expression::Constant(c_h)
|
||||
}
|
||||
Expression::Constant(c_h) => {
|
||||
adjusted_constant_initializers.insert(c_h);
|
||||
module.constants[c_h].init = adjusted_global_expressions[c_h.index()];
|
||||
if adjusted_constant_initializers.insert(c_h) {
|
||||
let init = &mut module.constants[c_h].init;
|
||||
*init = adjusted_global_expressions[init.index()];
|
||||
}
|
||||
expr
|
||||
}
|
||||
expr => expr,
|
||||
|
|
|
@ -248,7 +248,7 @@ impl LocalImageType {
|
|||
/// this, by converting everything possible to a `LocalType` before inspecting
|
||||
/// it.
|
||||
///
|
||||
/// ## `Localtype` equality and SPIR-V `OpType` uniqueness
|
||||
/// ## `LocalType` equality and SPIR-V `OpType` uniqueness
|
||||
///
|
||||
/// The definition of `Eq` on `LocalType` is carefully chosen to help us follow
|
||||
/// certain SPIR-V rules. SPIR-V §2.8 requires some classes of `OpType...`
|
||||
|
|
|
@ -970,6 +970,11 @@ impl Writer {
|
|||
handle: Handle<crate::Type>,
|
||||
) -> Result<Word, Error> {
|
||||
let ty = &arena[handle];
|
||||
// If it's a type that needs SPIR-V capabilities, request them now.
|
||||
// This needs to happen regardless of the LocalType lookup succeeding,
|
||||
// because some types which map to the same LocalType have different
|
||||
// capability requirements. See https://github.com/gfx-rs/wgpu/issues/5569
|
||||
self.request_type_capabilities(&ty.inner)?;
|
||||
let id = if let Some(local) = make_local(&ty.inner) {
|
||||
// This type can be represented as a `LocalType`, so check if we've
|
||||
// already written an instruction for it. If not, do so now, with
|
||||
|
@ -985,10 +990,6 @@ impl Writer {
|
|||
|
||||
self.write_type_declaration_local(id, local);
|
||||
|
||||
// If it's a type that needs SPIR-V capabilities, request them now,
|
||||
// so write_type_declaration_local can stay infallible.
|
||||
self.request_type_capabilities(&ty.inner)?;
|
||||
|
||||
id
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
use std::{error::Error, fmt};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ShaderError<E> {
|
||||
/// The source code of the shader.
|
||||
pub source: String,
|
||||
pub label: Option<String>,
|
||||
pub inner: Box<E>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "wgsl-in")]
|
||||
impl fmt::Display for ShaderError<crate::front::wgsl::ParseError> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let label = self.label.as_deref().unwrap_or_default();
|
||||
let string = self.inner.emit_to_string(&self.source);
|
||||
write!(f, "\nShader '{label}' parsing {string}")
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "glsl-in")]
|
||||
impl fmt::Display for ShaderError<crate::front::glsl::ParseErrors> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let label = self.label.as_deref().unwrap_or_default();
|
||||
let string = self.inner.emit_to_string(&self.source);
|
||||
write!(f, "\nShader '{label}' parsing {string}")
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "spv-in")]
|
||||
impl fmt::Display for ShaderError<crate::front::spv::Error> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let label = self.label.as_deref().unwrap_or_default();
|
||||
let string = self.inner.emit_to_string(&self.source);
|
||||
write!(f, "\nShader '{label}' parsing {string}")
|
||||
}
|
||||
}
|
||||
impl fmt::Display for ShaderError<crate::WithSpan<crate::valid::ValidationError>> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use codespan_reporting::{
|
||||
diagnostic::{Diagnostic, Label},
|
||||
files::SimpleFile,
|
||||
term,
|
||||
};
|
||||
|
||||
let label = self.label.as_deref().unwrap_or_default();
|
||||
let files = SimpleFile::new(label, &self.source);
|
||||
let config = term::Config::default();
|
||||
let mut writer = term::termcolor::NoColor::new(Vec::new());
|
||||
|
||||
let diagnostic = Diagnostic::error().with_labels(
|
||||
self.inner
|
||||
.spans()
|
||||
.map(|&(span, ref desc)| {
|
||||
Label::primary((), span.to_range().unwrap()).with_message(desc.to_owned())
|
||||
})
|
||||
.collect(),
|
||||
);
|
||||
|
||||
term::emit(&mut writer, &config, &files, &diagnostic).expect("cannot write error");
|
||||
|
||||
write!(
|
||||
f,
|
||||
"\nShader validation {}",
|
||||
String::from_utf8_lossy(&writer.into_inner())
|
||||
)
|
||||
}
|
||||
}
|
||||
impl<E> Error for ShaderError<E>
|
||||
where
|
||||
ShaderError<E>: fmt::Display,
|
||||
E: Error + 'static,
|
||||
{
|
||||
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
Some(&self.inner)
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
use super::token::TokenValue;
|
||||
use crate::SourceLocation;
|
||||
use crate::{proc::ConstantEvaluatorError, Span};
|
||||
use codespan_reporting::diagnostic::{Diagnostic, Label};
|
||||
use codespan_reporting::files::SimpleFile;
|
||||
|
@ -137,14 +138,21 @@ pub struct Error {
|
|||
pub meta: Span,
|
||||
}
|
||||
|
||||
impl Error {
|
||||
/// Returns a [`SourceLocation`] for the error message.
|
||||
pub fn location(&self, source: &str) -> Option<SourceLocation> {
|
||||
Some(self.meta.location(source))
|
||||
}
|
||||
}
|
||||
|
||||
/// A collection of errors returned during shader parsing.
|
||||
#[derive(Clone, Debug)]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
pub struct ParseError {
|
||||
pub struct ParseErrors {
|
||||
pub errors: Vec<Error>,
|
||||
}
|
||||
|
||||
impl ParseError {
|
||||
impl ParseErrors {
|
||||
pub fn emit_to_writer(&self, writer: &mut impl WriteColor, source: &str) {
|
||||
self.emit_to_writer_with_path(writer, source, "glsl");
|
||||
}
|
||||
|
@ -172,19 +180,19 @@ impl ParseError {
|
|||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ParseError {
|
||||
impl std::fmt::Display for ParseErrors {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
self.errors.iter().try_for_each(|e| write!(f, "{e:?}"))
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for ParseError {
|
||||
impl std::error::Error for ParseErrors {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<Error>> for ParseError {
|
||||
impl From<Vec<Error>> for ParseErrors {
|
||||
fn from(errors: Vec<Error>) -> Self {
|
||||
Self { errors }
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ To begin, take a look at the documentation for the [`Frontend`].
|
|||
*/
|
||||
|
||||
pub use ast::{Precision, Profile};
|
||||
pub use error::{Error, ErrorKind, ExpectedToken, ParseError};
|
||||
pub use error::{Error, ErrorKind, ExpectedToken, ParseErrors};
|
||||
pub use token::TokenValue;
|
||||
|
||||
use crate::{proc::Layouter, FastHashMap, FastHashSet, Handle, Module, ShaderStage, Span, Type};
|
||||
|
@ -196,7 +196,7 @@ impl Frontend {
|
|||
&mut self,
|
||||
options: &Options,
|
||||
source: &str,
|
||||
) -> std::result::Result<Module, ParseError> {
|
||||
) -> std::result::Result<Module, ParseErrors> {
|
||||
self.reset(options.stage);
|
||||
|
||||
let lexer = lex::Lexer::new(source, &options.defines);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::{
|
||||
ast::Profile,
|
||||
error::ExpectedToken,
|
||||
error::{Error, ErrorKind, ParseError},
|
||||
error::{Error, ErrorKind, ParseErrors},
|
||||
token::TokenValue,
|
||||
Frontend, Options, Span,
|
||||
};
|
||||
|
@ -21,7 +21,7 @@ fn version() {
|
|||
)
|
||||
.err()
|
||||
.unwrap(),
|
||||
ParseError {
|
||||
ParseErrors {
|
||||
errors: vec![Error {
|
||||
kind: ErrorKind::InvalidVersion(99000),
|
||||
meta: Span::new(9, 14)
|
||||
|
@ -37,7 +37,7 @@ fn version() {
|
|||
)
|
||||
.err()
|
||||
.unwrap(),
|
||||
ParseError {
|
||||
ParseErrors {
|
||||
errors: vec![Error {
|
||||
kind: ErrorKind::InvalidVersion(449),
|
||||
meta: Span::new(9, 12)
|
||||
|
@ -53,7 +53,7 @@ fn version() {
|
|||
)
|
||||
.err()
|
||||
.unwrap(),
|
||||
ParseError {
|
||||
ParseErrors {
|
||||
errors: vec![Error {
|
||||
kind: ErrorKind::InvalidProfile("smart".into()),
|
||||
meta: Span::new(13, 18),
|
||||
|
@ -69,7 +69,7 @@ fn version() {
|
|||
)
|
||||
.err()
|
||||
.unwrap(),
|
||||
ParseError {
|
||||
ParseErrors {
|
||||
errors: vec![
|
||||
Error {
|
||||
kind: ErrorKind::PreprocessorError(PreprocessorError::UnexpectedHash,),
|
||||
|
@ -455,7 +455,7 @@ fn functions() {
|
|||
)
|
||||
.err()
|
||||
.unwrap(),
|
||||
ParseError {
|
||||
ParseErrors {
|
||||
errors: vec![Error {
|
||||
kind: ErrorKind::SemanticError("Function already defined".into()),
|
||||
meta: Span::new(134, 152),
|
||||
|
@ -634,7 +634,7 @@ fn implicit_conversions() {
|
|||
)
|
||||
.err()
|
||||
.unwrap(),
|
||||
ParseError {
|
||||
ParseErrors {
|
||||
errors: vec![Error {
|
||||
kind: ErrorKind::SemanticError("Unknown function \'test\'".into()),
|
||||
meta: Span::new(156, 165),
|
||||
|
@ -658,7 +658,7 @@ fn implicit_conversions() {
|
|||
)
|
||||
.err()
|
||||
.unwrap(),
|
||||
ParseError {
|
||||
ParseErrors {
|
||||
errors: vec![Error {
|
||||
kind: ErrorKind::SemanticError("Ambiguous best function for \'test\'".into()),
|
||||
meta: Span::new(158, 165),
|
||||
|
|
|
@ -5,7 +5,7 @@ use codespan_reporting::files::SimpleFile;
|
|||
use codespan_reporting::term;
|
||||
use termcolor::{NoColor, WriteColor};
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[derive(Clone, Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
#[error("invalid header")]
|
||||
InvalidHeader,
|
||||
|
|
|
@ -13,6 +13,7 @@ use thiserror::Error;
|
|||
#[derive(Clone, Debug)]
|
||||
pub struct ParseError {
|
||||
message: String,
|
||||
// The first span should be the primary span, and the other ones should be complementary.
|
||||
labels: Vec<(Span, Cow<'static, str>)>,
|
||||
notes: Vec<String>,
|
||||
}
|
||||
|
|
|
@ -274,6 +274,7 @@ pub mod back;
|
|||
mod block;
|
||||
#[cfg(feature = "compact")]
|
||||
pub mod compact;
|
||||
pub mod error;
|
||||
pub mod front;
|
||||
pub mod keywords;
|
||||
pub mod proc;
|
||||
|
|
|
@ -950,10 +950,10 @@ impl<'a> ConstantEvaluator<'a> {
|
|||
pattern: [crate::SwizzleComponent; 4],
|
||||
) -> Result<Handle<Expression>, ConstantEvaluatorError> {
|
||||
let mut get_dst_ty = |ty| match self.types[ty].inner {
|
||||
crate::TypeInner::Vector { size: _, scalar } => Ok(self.types.insert(
|
||||
TypeInner::Vector { size: _, scalar } => Ok(self.types.insert(
|
||||
Type {
|
||||
name: None,
|
||||
inner: crate::TypeInner::Vector { size, scalar },
|
||||
inner: TypeInner::Vector { size, scalar },
|
||||
},
|
||||
span,
|
||||
)),
|
||||
|
@ -1244,13 +1244,11 @@ impl<'a> ConstantEvaluator<'a> {
|
|||
Expression::ZeroValue(ty) | Expression::Compose { ty, .. } => {
|
||||
match self.types[ty].inner {
|
||||
TypeInner::Array { size, .. } => match size {
|
||||
crate::ArraySize::Constant(len) => {
|
||||
ArraySize::Constant(len) => {
|
||||
let expr = Expression::Literal(Literal::U32(len.get()));
|
||||
self.register_evaluated_expr(expr, span)
|
||||
}
|
||||
crate::ArraySize::Dynamic => {
|
||||
Err(ConstantEvaluatorError::ArrayLengthDynamic)
|
||||
}
|
||||
ArraySize::Dynamic => Err(ConstantEvaluatorError::ArrayLengthDynamic),
|
||||
},
|
||||
_ => Err(ConstantEvaluatorError::InvalidArrayLengthArg),
|
||||
}
|
||||
|
@ -1313,7 +1311,7 @@ impl<'a> ConstantEvaluator<'a> {
|
|||
Expression::ZeroValue(ty)
|
||||
if matches!(
|
||||
self.types[ty].inner,
|
||||
crate::TypeInner::Scalar(crate::Scalar {
|
||||
TypeInner::Scalar(crate::Scalar {
|
||||
kind: ScalarKind::Uint,
|
||||
..
|
||||
})
|
||||
|
@ -1628,7 +1626,7 @@ impl<'a> ConstantEvaluator<'a> {
|
|||
return self.cast(expr, target, span);
|
||||
};
|
||||
|
||||
let crate::TypeInner::Array {
|
||||
let TypeInner::Array {
|
||||
base: _,
|
||||
size,
|
||||
stride: _,
|
||||
|
|
|
@ -239,7 +239,7 @@ pub enum GuardedIndex {
|
|||
pub fn find_checked_indexes(
|
||||
module: &crate::Module,
|
||||
function: &crate::Function,
|
||||
info: &crate::valid::FunctionInfo,
|
||||
info: &valid::FunctionInfo,
|
||||
policies: BoundsCheckPolicies,
|
||||
) -> BitSet {
|
||||
use crate::Expression as Ex;
|
||||
|
@ -321,7 +321,7 @@ pub fn access_needs_check(
|
|||
mut index: GuardedIndex,
|
||||
module: &crate::Module,
|
||||
function: &crate::Function,
|
||||
info: &crate::valid::FunctionInfo,
|
||||
info: &valid::FunctionInfo,
|
||||
) -> Option<IndexableLength> {
|
||||
let base_inner = info[base].ty.inner_with(&module.types);
|
||||
// Unwrap safety: `Err` here indicates unindexable base types and invalid
|
||||
|
|
|
@ -72,8 +72,8 @@ impl Span {
|
|||
pub fn location(&self, source: &str) -> SourceLocation {
|
||||
let prefix = &source[..self.start as usize];
|
||||
let line_number = prefix.matches('\n').count() as u32 + 1;
|
||||
let line_start = prefix.rfind('\n').map(|pos| pos + 1).unwrap_or(0);
|
||||
let line_position = source[line_start..self.start as usize].chars().count() as u32 + 1;
|
||||
let line_start = prefix.rfind('\n').map(|pos| pos + 1).unwrap_or(0) as u32;
|
||||
let line_position = self.start - line_start + 1;
|
||||
|
||||
SourceLocation {
|
||||
line_number,
|
||||
|
@ -107,14 +107,14 @@ impl std::ops::Index<Span> for str {
|
|||
/// Roughly corresponds to the positional members of [`GPUCompilationMessage`][gcm] from
|
||||
/// the WebGPU specification, except
|
||||
/// - `offset` and `length` are in bytes (UTF-8 code units), instead of UTF-16 code units.
|
||||
/// - `line_position` counts entire Unicode code points, instead of UTF-16 code units.
|
||||
/// - `line_position` is in bytes (UTF-8 code units), instead of UTF-16 code units.
|
||||
///
|
||||
/// [gcm]: https://www.w3.org/TR/webgpu/#gpucompilationmessage
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct SourceLocation {
|
||||
/// 1-based line number.
|
||||
pub line_number: u32,
|
||||
/// 1-based column of the start of this span, counted in Unicode code points.
|
||||
/// 1-based column in code units (in bytes) of the start of the span.
|
||||
pub line_position: u32,
|
||||
/// 0-based Offset in code units (in bytes) of the start of the span.
|
||||
pub offset: u32,
|
||||
|
@ -136,7 +136,7 @@ impl<E> fmt::Display for WithSpan<E>
|
|||
where
|
||||
E: fmt::Display,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.inner.fmt(f)
|
||||
}
|
||||
}
|
||||
|
@ -304,7 +304,7 @@ impl<E> WithSpan<E> {
|
|||
use term::termcolor::NoColor;
|
||||
|
||||
let files = files::SimpleFile::new(path, source);
|
||||
let config = codespan_reporting::term::Config::default();
|
||||
let config = term::Config::default();
|
||||
let mut writer = NoColor::new(Vec::new());
|
||||
term::emit(&mut writer, &config, &files, &self.diagnostic()).expect("cannot write error");
|
||||
String::from_utf8(writer.into_inner()).unwrap()
|
||||
|
|
|
@ -835,7 +835,7 @@ impl FunctionInfo {
|
|||
let req = self.expressions[expr.index()].uniformity.requirements;
|
||||
if self
|
||||
.flags
|
||||
.contains(super::ValidationFlags::CONTROL_FLOW_UNIFORMITY)
|
||||
.contains(ValidationFlags::CONTROL_FLOW_UNIFORMITY)
|
||||
&& !req.is_empty()
|
||||
{
|
||||
if let Some(cause) = disruptor {
|
||||
|
|
|
@ -194,7 +194,7 @@ impl super::Validator {
|
|||
use crate::Expression as E;
|
||||
|
||||
if !global_expr_kind.is_const_or_override(handle) {
|
||||
return Err(super::ConstExpressionError::NonConstOrOverride);
|
||||
return Err(ConstExpressionError::NonConstOrOverride);
|
||||
}
|
||||
|
||||
match gctx.global_expressions[handle] {
|
||||
|
@ -211,10 +211,10 @@ impl super::Validator {
|
|||
}
|
||||
E::Splat { value, .. } => match *mod_info[value].inner_with(gctx.types) {
|
||||
crate::TypeInner::Scalar { .. } => {}
|
||||
_ => return Err(super::ConstExpressionError::InvalidSplatType(value)),
|
||||
_ => return Err(ConstExpressionError::InvalidSplatType(value)),
|
||||
},
|
||||
_ if global_expr_kind.is_const(handle) || !self.allow_overrides => {
|
||||
return Err(super::ConstExpressionError::NonFullyEvaluatedConst)
|
||||
return Err(ConstExpressionError::NonFullyEvaluatedConst)
|
||||
}
|
||||
// the constant evaluator will report errors about override-expressions
|
||||
_ => {}
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"e8335a4d3544795505ee88baaeba2d8974250deed141053b58c9bfcd8ee3b178","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","build.rs":"a99478d7f63fb41429e3834f4d0e5cd333f94ba1834c68295f929170e16987de","src/binding_model.rs":"f1279d3cd1f84eab37dc85658f32bb4b4f2687c9086f4b4f30e8a4b0d7c1a582","src/command/allocator.rs":"5ca1e40a735f7cb0531d3e5298767963a3c0ee9e264b44d3a356cd7ef16bcb52","src/command/bind.rs":"a37f042484b65d9fdea4cdab3667381623ee9a8943a6d32683d410b92736d306","src/command/bundle.rs":"1c7fceda77668ae5a055bf1d0184b78cc7362f7763d6b6a3c9d1687e4782f908","src/command/clear.rs":"1eb475a48e04a011be381720a420047a3d65fc85be3b9b55e6874c7fd14e40a8","src/command/compute.rs":"7a58ff8f492dc8926ab8cd580c7ae8bf8703df4472f093f4a027f4969f55b0f9","src/command/compute_command.rs":"b00623d80e9aa3bb78c1d8d24ccbc0cbd6f945ef3c9206b8fba5c3ce86753f5e","src/command/draw.rs":"15f9ad857504d8098279f9c789317feba321c9b6b8f0de20b8ba98f358c99d89","src/command/memory_init.rs":"71550dabbf7cc3c3ff6aa4ccd31af080bb5e1cb1e21422daea63fee30294476f","src/command/mod.rs":"947c0dc1e82301e5571579031f0b1b0627d1f6d9c8d3b5e510c37673ea661fc1","src/command/query.rs":"92b5aff8580631c51bc1ba72a45605e704c997684fc6a891640da945712db5ec","src/command/render.rs":"0d529644fe35bfb66aefe2e62ddd2c45adc620c5d5154abf7660e4b1f370fcee","src/command/transfer.rs":"d0324465a5637e8346276a0427446377c21acbb285ff819091673ba5fc365a9c","src/conv.rs":"7e3ffe33b47a6fd3617aabf9f11cc68f1ccbee2c7343b8dbbcd0e8f3447e1ad8","src/device/any_device.rs":"65f47b58939b60f88f47861e65d5d45209492df8e73e7c1b60b3b459f510c09e","src/device/bgl.rs":"f1c372cd632deacb9d0f0880846844c7cbe5f1ca88592ed35dbd59966958b33d","src/device/global.rs":"791faa82517e5eef501d7d77128d8cfaa2b99536b85c2e1c06739e97a3ff391c","src/device/life.rs":"a1d6a62c058b4626c9ed8c20c7bf8dacefe03bbf568e1fc0757fb7914bb07d40","src/device/mod.rs":"aa16ac918714c844820142b4d321ac4e9a51ffef37501c6f5ca48e3817353d16","src/device/queue.rs":"2c8f0a7c39f4b050526c895aa53fb1417c64ea7c018ff1a44c2c7715a77c6c1d","src/device/resource.rs":"207e823354c0077402838c7531bc9fcec75638474d2a870ab4333ffabaa15de2","src/device/trace.rs":"9deb1b083165e07253b4928ac2f564aba06f9089c3aca1c0a1d438d87d981542","src/error.rs":"e3b6b7a69877437f4e46af7f0e8ca1db1822beae7c8448db41c2bae0f64b2bb4","src/global.rs":"fe1ddd4863d50568780bf04382a4fd0d3d8441dd7baff9dacf57e860811b87c9","src/hal_api.rs":"fb65bfab0334cb8b0bbe823b1da6d1e82cd4a312c60a332ce65df9fbc2f74482","src/hash_utils.rs":"e8d484027c7ce81978e4679a5e20af9416ab7d2fa595f1ca95992b29d625b0ca","src/hub.rs":"59aeb5c902fd6707f651994fc9e335a6e7fdd998faebd29c087171e226101405","src/id.rs":"23634dec36eb171cb95c672519e69705d466044dcea29028b58d2288de35f8db","src/identity.rs":"b27d4e06b1f6c25ca2f4ad276fdf8c09a5d71f890b06cbabef7ef62369cb4df6","src/init_tracker/buffer.rs":"61eb9cfaa312135b7a937ff6a3117f531b5b7323fae6553a41d6de9bc106d7e0","src/init_tracker/mod.rs":"a0f64730cc025113b656b4690f9dcb0ec18b8770bc7ef24c7b4ad8bebae03d24","src/init_tracker/texture.rs":"030fd594bf9948fad391390d85c5e1fec7eaf67b6e812c60f2dd59bc4fda8fd5","src/instance.rs":"d4c46ff5d0cc13b09c7b364d6445d30eaf7ea6f50ac9d49b0022b3a6e9377445","src/lib.rs":"77ec01c43b6f5daab174e0831bd98771a708cdfd42b0203f45490b6977ef2923","src/lock/mod.rs":"d7ae9e2dda2d6f6732abe5ce784300708945d911697893522997bb04141decf8","src/lock/rank.rs":"cebf4d1063e2c0bee5015ffaf147f20d108ef4786d9a30acd315b7d0585a3abe","src/lock/ranked.rs":"783283c6152465f555778c51fda0e0c8df84d3e5dedce2fa6d5142dd7a3109c2","src/lock/vanilla.rs":"6db2fbc41ef4abae4700df33e28e74160bce4ea59fad2887d0613e6d5769444d","src/pipeline.rs":"c7a70b5c6323bcedf7cb0ad431a1f22c2d797084ccf5247f015ba398f821e6e3","src/pool.rs":"7899e74874da17c83ec39a88b360de12f564ef4bee2bb1240c37becdaeb57a86","src/present.rs":"a0142445b0ccaebdd097f24f063df9d8306583dbe2e434c8b478a706a89de4d3","src/registry.rs":"1a65f9a3b2a23476a5fa2f0a826d690853c29b80b512e364fbb8374a31999dcf","src/resource.rs":"90d36c359cec532f5955bd3a60dd59fc9754bf27c08e9099a08010c1ea984322","src/snatch.rs":"d5f3d512ae1148c0d63bb9161e643e97ae3097675cb9c75e72635ec55e650c15","src/storage.rs":"0c5a8a732e33ea565528b3a02e7a6c15178bc8dbc49a9cedcd76f8ebb1039b48","src/track/buffer.rs":"8571ebd57302ab9aba4aef4a310a02fe0848485f57ac3a7197393fbfbaddff2e","src/track/metadata.rs":"4b85341adc3b725e326dec0fe691f7e8e6c4e7c0a1ada1d86dd72a0a0b6397e6","src/track/mod.rs":"4d4ebbec98f4d2148767b34240b813d2b2978b52006100f69f71a90e0b584564","src/track/range.rs":"2a15794e79b0470d5ba6b3267173a42f34312878e1cb288f198d2854a7888e53","src/track/stateless.rs":"b49192d248434570c024078cf204ad47f9030ed7a541324bad525881b78f75a4","src/track/texture.rs":"f962f97b582d4b528483f09df8662484159b6f5d19b376de53462d411421cee5","src/validation.rs":"1433e035d656afda97ee047b3247cb1a63844360174d575acf52cac868e27a3c"},"package":null}
|
||||
{"files":{"Cargo.toml":"ef0dc61297a9dd672d3e0e71ced2973a97f0abdb705432816874867ec4dc873b","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","build.rs":"a99478d7f63fb41429e3834f4d0e5cd333f94ba1834c68295f929170e16987de","src/binding_model.rs":"f1279d3cd1f84eab37dc85658f32bb4b4f2687c9086f4b4f30e8a4b0d7c1a582","src/command/allocator.rs":"5ca1e40a735f7cb0531d3e5298767963a3c0ee9e264b44d3a356cd7ef16bcb52","src/command/bind.rs":"a37f042484b65d9fdea4cdab3667381623ee9a8943a6d32683d410b92736d306","src/command/bundle.rs":"1c7fceda77668ae5a055bf1d0184b78cc7362f7763d6b6a3c9d1687e4782f908","src/command/clear.rs":"1eb475a48e04a011be381720a420047a3d65fc85be3b9b55e6874c7fd14e40a8","src/command/compute.rs":"7a58ff8f492dc8926ab8cd580c7ae8bf8703df4472f093f4a027f4969f55b0f9","src/command/compute_command.rs":"b00623d80e9aa3bb78c1d8d24ccbc0cbd6f945ef3c9206b8fba5c3ce86753f5e","src/command/draw.rs":"15f9ad857504d8098279f9c789317feba321c9b6b8f0de20b8ba98f358c99d89","src/command/memory_init.rs":"71550dabbf7cc3c3ff6aa4ccd31af080bb5e1cb1e21422daea63fee30294476f","src/command/mod.rs":"947c0dc1e82301e5571579031f0b1b0627d1f6d9c8d3b5e510c37673ea661fc1","src/command/query.rs":"92b5aff8580631c51bc1ba72a45605e704c997684fc6a891640da945712db5ec","src/command/render.rs":"6d02d9a9f0c1e58a448cbd30e62e51dca5b8b61e576ece15655c343cc51e84b9","src/command/transfer.rs":"d0324465a5637e8346276a0427446377c21acbb285ff819091673ba5fc365a9c","src/conv.rs":"7e3ffe33b47a6fd3617aabf9f11cc68f1ccbee2c7343b8dbbcd0e8f3447e1ad8","src/device/any_device.rs":"8802f6d9d7fa9cd0b02c5ed57412a2ef01b9ad2b47182e18a914ce4ad5e24fde","src/device/bgl.rs":"f1c372cd632deacb9d0f0880846844c7cbe5f1ca88592ed35dbd59966958b33d","src/device/global.rs":"1881c6729b86423a4ab75db1ae0e3d6a8d34ab4600f3cd5e38bf8768d07b6905","src/device/life.rs":"a65cab56e0eb688d0776e719da785372a742d6a87bd3f3bef9042e9428453c3a","src/device/mod.rs":"aa16ac918714c844820142b4d321ac4e9a51ffef37501c6f5ca48e3817353d16","src/device/queue.rs":"33cc4bb3337d49810dc74bfc2eb8ad97a82023ad263d80700c769d0c0ad9bfe4","src/device/resource.rs":"b0a55d496ca59056854d5d41264f519992b342a4049d1b65a13220d8a76902a1","src/device/trace.rs":"9deb1b083165e07253b4928ac2f564aba06f9089c3aca1c0a1d438d87d981542","src/error.rs":"e3b6b7a69877437f4e46af7f0e8ca1db1822beae7c8448db41c2bae0f64b2bb4","src/global.rs":"fe1ddd4863d50568780bf04382a4fd0d3d8441dd7baff9dacf57e860811b87c9","src/hal_api.rs":"fb65bfab0334cb8b0bbe823b1da6d1e82cd4a312c60a332ce65df9fbc2f74482","src/hash_utils.rs":"e8d484027c7ce81978e4679a5e20af9416ab7d2fa595f1ca95992b29d625b0ca","src/hub.rs":"59aeb5c902fd6707f651994fc9e335a6e7fdd998faebd29c087171e226101405","src/id.rs":"23634dec36eb171cb95c672519e69705d466044dcea29028b58d2288de35f8db","src/identity.rs":"b27d4e06b1f6c25ca2f4ad276fdf8c09a5d71f890b06cbabef7ef62369cb4df6","src/init_tracker/buffer.rs":"61eb9cfaa312135b7a937ff6a3117f531b5b7323fae6553a41d6de9bc106d7e0","src/init_tracker/mod.rs":"a0f64730cc025113b656b4690f9dcb0ec18b8770bc7ef24c7b4ad8bebae03d24","src/init_tracker/texture.rs":"030fd594bf9948fad391390d85c5e1fec7eaf67b6e812c60f2dd59bc4fda8fd5","src/instance.rs":"d4c46ff5d0cc13b09c7b364d6445d30eaf7ea6f50ac9d49b0022b3a6e9377445","src/lib.rs":"77ec01c43b6f5daab174e0831bd98771a708cdfd42b0203f45490b6977ef2923","src/lock/mod.rs":"c7069f05341f1c63f478ed9176f4fbd1a6f633ea71f124c3b4d6c1b02d1febe8","src/lock/rank.rs":"acc3ef80c39297a440a53ec33e437be7fbb56a4bb09e326cfeb3d4bf76f60ac8","src/lock/ranked.rs":"94c2d929b54bc4ea68258bb4d58b692b61accc394dd48dbab5e69f1bdafaeb56","src/lock/vanilla.rs":"a6cd5cc3c1900271783ba146adf07e28424f6fecc5466d54624dbda237770fb4","src/pipeline.rs":"033335a759b801de7c606baf3f2ac8c706b1bbe27b209bcca73093569b604c0e","src/pool.rs":"7899e74874da17c83ec39a88b360de12f564ef4bee2bb1240c37becdaeb57a86","src/present.rs":"1147399ff3a62b69c944001639cd1cf19295e13cf0ddd3850b2736afdb0720b4","src/registry.rs":"1104d6972dad982c6cc6dfd25cbc52d0b8279d7989525d78ed49551434fa3cea","src/resource.rs":"ce469bbd6ae54efb989770b04079ee1a9c248b95f31ad5dae79603f87574878d","src/snatch.rs":"f9849b1050adba708c1b9be5a21ce806c83eef71c4f79b513768918f857fe814","src/storage.rs":"0c5a8a732e33ea565528b3a02e7a6c15178bc8dbc49a9cedcd76f8ebb1039b48","src/track/buffer.rs":"8571ebd57302ab9aba4aef4a310a02fe0848485f57ac3a7197393fbfbaddff2e","src/track/metadata.rs":"4b85341adc3b725e326dec0fe691f7e8e6c4e7c0a1ada1d86dd72a0a0b6397e6","src/track/mod.rs":"0056f0299fa71cc3acca9aa6becba15e0845b8e9000a11780d0b78da2ee01beb","src/track/range.rs":"2a15794e79b0470d5ba6b3267173a42f34312878e1cb288f198d2854a7888e53","src/track/stateless.rs":"b49192d248434570c024078cf204ad47f9030ed7a541324bad525881b78f75a4","src/track/texture.rs":"f962f97b582d4b528483f09df8662484159b6f5d19b376de53462d411421cee5","src/validation.rs":"1433e035d656afda97ee047b3247cb1a63844360174d575acf52cac868e27a3c"},"package":null}
|
|
@ -13,7 +13,7 @@
|
|||
edition = "2021"
|
||||
rust-version = "1.74"
|
||||
name = "wgpu-core"
|
||||
version = "0.19.3"
|
||||
version = "0.20.0"
|
||||
authors = ["gfx-rs developers"]
|
||||
description = "WebGPU core logic on wgpu-hal"
|
||||
homepage = "https://wgpu.rs/"
|
||||
|
@ -40,7 +40,6 @@ targets = [
|
|||
arrayvec = "0.7"
|
||||
bit-vec = "0.6"
|
||||
bitflags = "2"
|
||||
codespan-reporting = "0.11"
|
||||
document-features = "0.2.8"
|
||||
indexmap = "2"
|
||||
log = "0.4"
|
||||
|
@ -55,13 +54,13 @@ version = "1.14"
|
|||
optional = true
|
||||
|
||||
[dependencies.hal]
|
||||
version = "0.19.3"
|
||||
version = "0.20.0"
|
||||
path = "../wgpu-hal"
|
||||
default_features = false
|
||||
package = "wgpu-hal"
|
||||
|
||||
[dependencies.naga]
|
||||
version = "0.19.2"
|
||||
version = "0.20.0"
|
||||
path = "../naga"
|
||||
|
||||
[dependencies.profiling]
|
||||
|
@ -82,7 +81,7 @@ features = ["serde_derive"]
|
|||
optional = true
|
||||
|
||||
[dependencies.wgt]
|
||||
version = "0.19.2"
|
||||
version = "0.20.0"
|
||||
path = "../wgpu-types"
|
||||
package = "wgpu-types"
|
||||
|
||||
|
|
|
@ -2468,10 +2468,6 @@ pub mod render_commands {
|
|||
use std::{convert::TryInto, num::NonZeroU32};
|
||||
use wgt::{BufferAddress, BufferSize, Color, DynamicOffset, IndexFormat};
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe as there is no guarantee that the given pointer is
|
||||
/// valid for `offset_length` elements.
|
||||
pub fn wgpu_render_pass_set_bind_group(
|
||||
pass: &mut RenderPass,
|
||||
index: u32,
|
||||
|
@ -2571,10 +2567,6 @@ pub mod render_commands {
|
|||
.push(RenderCommand::SetScissor(Rect { x, y, w, h }));
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe as there is no guarantee that the given pointer is
|
||||
/// valid for `size_bytes` bytes.
|
||||
pub fn wgpu_render_pass_set_push_constants(
|
||||
pass: &mut RenderPass,
|
||||
stages: wgt::ShaderStages,
|
||||
|
|
|
@ -34,7 +34,7 @@ impl AnyDevice {
|
|||
unsafe fn drop_glue<A: HalApi>(ptr: *mut ()) {
|
||||
// Drop the arc this instance is holding.
|
||||
unsafe {
|
||||
_ = Arc::from_raw(ptr.cast::<A::Surface>());
|
||||
_ = Arc::from_raw(ptr.cast::<A::Device>());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ use crate::{
|
|||
id::{self, AdapterId, DeviceId, QueueId, SurfaceId},
|
||||
init_tracker::TextureInitTracker,
|
||||
instance::{self, Adapter, Surface},
|
||||
lock::{rank, RwLock},
|
||||
pipeline, present,
|
||||
resource::{self, BufferAccessResult},
|
||||
resource::{BufferAccessError, BufferMapOperation, CreateBufferError, Resource},
|
||||
|
@ -20,7 +21,6 @@ use crate::{
|
|||
|
||||
use arrayvec::ArrayVec;
|
||||
use hal::Device as _;
|
||||
use parking_lot::RwLock;
|
||||
|
||||
use wgt::{BufferAddress, TextureFormat};
|
||||
|
||||
|
@ -643,8 +643,10 @@ impl Global {
|
|||
texture.hal_usage |= hal::TextureUses::COPY_DST;
|
||||
}
|
||||
|
||||
texture.initialization_status =
|
||||
RwLock::new(TextureInitTracker::new(desc.mip_level_count, 0));
|
||||
texture.initialization_status = RwLock::new(
|
||||
rank::TEXTURE_INITIALIZATION_STATUS,
|
||||
TextureInitTracker::new(desc.mip_level_count, 0),
|
||||
);
|
||||
|
||||
let (id, resource) = fid.assign(Arc::new(texture));
|
||||
api_log!("Device::create_texture({desc:?}) -> {id:?}");
|
||||
|
@ -2031,7 +2033,6 @@ impl Global {
|
|||
// Wait for all work to finish before configuring the surface.
|
||||
let snatch_guard = device.snatchable_lock.read();
|
||||
let fence = device.fence.read();
|
||||
let fence = fence.as_ref().unwrap();
|
||||
match device.maintain(fence, wgt::Maintain::Wait, snatch_guard) {
|
||||
Ok((closures, _)) => {
|
||||
user_callbacks = closures;
|
||||
|
@ -2144,7 +2145,6 @@ impl Global {
|
|||
) -> Result<DevicePoll, WaitIdleError> {
|
||||
let snatch_guard = device.snatchable_lock.read();
|
||||
let fence = device.fence.read();
|
||||
let fence = fence.as_ref().unwrap();
|
||||
let (closures, queue_empty) = device.maintain(fence, maintain, snatch_guard)?;
|
||||
|
||||
// Some deferred destroys are scheduled in maintain so run this right after
|
||||
|
|
|
@ -93,7 +93,7 @@ impl<A: HalApi> ResourceMaps<A> {
|
|||
destroyed_textures.clear();
|
||||
}
|
||||
|
||||
pub(crate) fn extend(&mut self, mut other: Self) {
|
||||
pub(crate) fn extend(&mut self, other: &mut Self) {
|
||||
let ResourceMaps {
|
||||
buffers,
|
||||
staging_buffers,
|
||||
|
@ -596,6 +596,18 @@ impl<A: HalApi> LifetimeTracker<A> {
|
|||
&mut trackers.textures,
|
||||
|maps| &mut maps.textures,
|
||||
);
|
||||
|
||||
// We may have been suspected because a texture view or bind group
|
||||
// referring to us was dropped. Remove stale weak references, so that
|
||||
// the backlink table doesn't grow without bound.
|
||||
for texture in self.suspected_resources.textures.values() {
|
||||
texture.views.lock().retain(|view| view.strong_count() > 0);
|
||||
texture
|
||||
.bind_groups
|
||||
.lock()
|
||||
.retain(|bg| bg.strong_count() > 0);
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -621,6 +633,13 @@ impl<A: HalApi> LifetimeTracker<A> {
|
|||
|maps| &mut maps.buffers,
|
||||
);
|
||||
|
||||
// We may have been suspected because a bind group referring to us was
|
||||
// dropped. Remove stale weak references, so that the backlink table
|
||||
// doesn't grow without bound.
|
||||
for buffer in self.suspected_resources.buffers.values() {
|
||||
buffer.bind_groups.lock().retain(|bg| bg.strong_count() > 0);
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
@ -7,14 +7,14 @@ use crate::{
|
|||
ClearError, CommandAllocator, CommandBuffer, CopySide, ImageCopyTexture, TransferError,
|
||||
},
|
||||
conv,
|
||||
device::{life::ResourceMaps, DeviceError, WaitIdleError},
|
||||
device::{DeviceError, WaitIdleError},
|
||||
get_lowest_common_denom,
|
||||
global::Global,
|
||||
hal_api::HalApi,
|
||||
hal_label,
|
||||
id::{self, DeviceId, QueueId},
|
||||
init_tracker::{has_copy_partial_init_tracker_coverage, TextureInitRange},
|
||||
lock::{rank, Mutex},
|
||||
lock::{rank, Mutex, RwLockWriteGuard},
|
||||
resource::{
|
||||
Buffer, BufferAccessError, BufferMapState, DestroyedBuffer, DestroyedTexture, Resource,
|
||||
ResourceInfo, ResourceType, StagingBuffer, Texture, TextureInner,
|
||||
|
@ -1162,8 +1162,8 @@ impl Global {
|
|||
let snatch_guard = device.snatchable_lock.read();
|
||||
|
||||
// Fence lock must be acquired after the snatch lock everywhere to avoid deadlocks.
|
||||
let mut fence = device.fence.write();
|
||||
let fence = fence.as_mut().unwrap();
|
||||
let mut fence_guard = device.fence.write();
|
||||
let fence = fence_guard.as_mut().unwrap();
|
||||
let submit_index = device
|
||||
.active_submission_index
|
||||
.fetch_add(1, Ordering::Relaxed)
|
||||
|
@ -1183,11 +1183,6 @@ impl Global {
|
|||
//TODO: if multiple command buffers are submitted, we can re-use the last
|
||||
// native command buffer of the previous chain instead of always creating
|
||||
// a temporary one, since the chains are not finished.
|
||||
let mut temp_suspected = device.temp_suspected.lock();
|
||||
{
|
||||
let mut suspected = temp_suspected.replace(ResourceMaps::new()).unwrap();
|
||||
suspected.clear();
|
||||
}
|
||||
|
||||
// finish all the command buffers first
|
||||
for &cmb_id in command_buffer_ids {
|
||||
|
@ -1235,41 +1230,23 @@ impl Global {
|
|||
|
||||
// update submission IDs
|
||||
for buffer in cmd_buf_trackers.buffers.used_resources() {
|
||||
let tracker_index = buffer.info.tracker_index();
|
||||
let raw_buf = match buffer.raw.get(&snatch_guard) {
|
||||
Some(raw) => raw,
|
||||
None => {
|
||||
return Err(QueueSubmitError::DestroyedBuffer(
|
||||
buffer.info.id(),
|
||||
));
|
||||
}
|
||||
};
|
||||
if buffer.raw.get(&snatch_guard).is_none() {
|
||||
return Err(QueueSubmitError::DestroyedBuffer(
|
||||
buffer.info.id(),
|
||||
));
|
||||
}
|
||||
buffer.info.use_at(submit_index);
|
||||
if buffer.is_unique() {
|
||||
if let BufferMapState::Active { .. } = *buffer.map_state.lock()
|
||||
{
|
||||
log::warn!("Dropped buffer has a pending mapping.");
|
||||
unsafe { device.raw().unmap_buffer(raw_buf) }
|
||||
.map_err(DeviceError::from)?;
|
||||
}
|
||||
temp_suspected
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.buffers
|
||||
.insert(tracker_index, buffer.clone());
|
||||
} else {
|
||||
match *buffer.map_state.lock() {
|
||||
BufferMapState::Idle => (),
|
||||
_ => {
|
||||
return Err(QueueSubmitError::BufferStillMapped(
|
||||
buffer.info.id(),
|
||||
))
|
||||
}
|
||||
|
||||
match *buffer.map_state.lock() {
|
||||
BufferMapState::Idle => (),
|
||||
_ => {
|
||||
return Err(QueueSubmitError::BufferStillMapped(
|
||||
buffer.info.id(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
for texture in cmd_buf_trackers.textures.used_resources() {
|
||||
let tracker_index = texture.info.tracker_index();
|
||||
let should_extend = match texture.inner.get(&snatch_guard) {
|
||||
None => {
|
||||
return Err(QueueSubmitError::DestroyedTexture(
|
||||
|
@ -1286,13 +1263,6 @@ impl Global {
|
|||
}
|
||||
};
|
||||
texture.info.use_at(submit_index);
|
||||
if texture.is_unique() {
|
||||
temp_suspected
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.textures
|
||||
.insert(tracker_index, texture.clone());
|
||||
}
|
||||
if should_extend {
|
||||
unsafe {
|
||||
used_surface_textures
|
||||
|
@ -1303,12 +1273,6 @@ impl Global {
|
|||
}
|
||||
for texture_view in cmd_buf_trackers.views.used_resources() {
|
||||
texture_view.info.use_at(submit_index);
|
||||
if texture_view.is_unique() {
|
||||
temp_suspected.as_mut().unwrap().texture_views.insert(
|
||||
texture_view.as_info().tracker_index(),
|
||||
texture_view.clone(),
|
||||
);
|
||||
}
|
||||
}
|
||||
{
|
||||
for bg in cmd_buf_trackers.bind_groups.used_resources() {
|
||||
|
@ -1322,13 +1286,6 @@ impl Global {
|
|||
for sampler in bg.used.samplers.used_resources() {
|
||||
sampler.info.use_at(submit_index);
|
||||
}
|
||||
if bg.is_unique() {
|
||||
temp_suspected
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.bind_groups
|
||||
.insert(bg.as_info().tracker_index(), bg.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
// assert!(cmd_buf_trackers.samplers.is_empty());
|
||||
|
@ -1336,32 +1293,14 @@ impl Global {
|
|||
cmd_buf_trackers.compute_pipelines.used_resources()
|
||||
{
|
||||
compute_pipeline.info.use_at(submit_index);
|
||||
if compute_pipeline.is_unique() {
|
||||
temp_suspected.as_mut().unwrap().compute_pipelines.insert(
|
||||
compute_pipeline.as_info().tracker_index(),
|
||||
compute_pipeline.clone(),
|
||||
);
|
||||
}
|
||||
}
|
||||
for render_pipeline in
|
||||
cmd_buf_trackers.render_pipelines.used_resources()
|
||||
{
|
||||
render_pipeline.info.use_at(submit_index);
|
||||
if render_pipeline.is_unique() {
|
||||
temp_suspected.as_mut().unwrap().render_pipelines.insert(
|
||||
render_pipeline.as_info().tracker_index(),
|
||||
render_pipeline.clone(),
|
||||
);
|
||||
}
|
||||
}
|
||||
for query_set in cmd_buf_trackers.query_sets.used_resources() {
|
||||
query_set.info.use_at(submit_index);
|
||||
if query_set.is_unique() {
|
||||
temp_suspected.as_mut().unwrap().query_sets.insert(
|
||||
query_set.as_info().tracker_index(),
|
||||
query_set.clone(),
|
||||
);
|
||||
}
|
||||
}
|
||||
for bundle in cmd_buf_trackers.bundles.used_resources() {
|
||||
bundle.info.use_at(submit_index);
|
||||
|
@ -1376,13 +1315,6 @@ impl Global {
|
|||
for query_set in bundle.used.query_sets.read().used_resources() {
|
||||
query_set.info.use_at(submit_index);
|
||||
}
|
||||
if bundle.is_unique() {
|
||||
temp_suspected
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.render_bundles
|
||||
.insert(bundle.as_info().tracker_index(), bundle.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut baked = cmdbuf.from_arc_into_baked();
|
||||
|
@ -1459,8 +1391,8 @@ impl Global {
|
|||
}
|
||||
}
|
||||
|
||||
let mut pending_writes = device.pending_writes.lock();
|
||||
let pending_writes = pending_writes.as_mut().unwrap();
|
||||
let mut pending_writes_guard = device.pending_writes.lock();
|
||||
let pending_writes = pending_writes_guard.as_mut().unwrap();
|
||||
|
||||
{
|
||||
used_surface_textures.set_size(hub.textures.read().len());
|
||||
|
@ -1550,18 +1482,22 @@ impl Global {
|
|||
active_executions,
|
||||
);
|
||||
|
||||
// This will schedule destruction of all resources that are no longer needed
|
||||
// by the user but used in the command stream, among other things.
|
||||
let (closures, _) = match device.maintain(fence, wgt::Maintain::Poll, snatch_guard) {
|
||||
Ok(closures) => closures,
|
||||
Err(WaitIdleError::Device(err)) => return Err(QueueSubmitError::Queue(err)),
|
||||
Err(WaitIdleError::StuckGpu) => return Err(QueueSubmitError::StuckGpu),
|
||||
Err(WaitIdleError::WrongSubmissionIndex(..)) => unreachable!(),
|
||||
};
|
||||
|
||||
// pending_write_resources has been drained, so it's empty, but we
|
||||
// want to retain its heap allocation.
|
||||
pending_writes.temp_resources = pending_write_resources;
|
||||
drop(pending_writes_guard);
|
||||
|
||||
// This will schedule destruction of all resources that are no longer needed
|
||||
// by the user but used in the command stream, among other things.
|
||||
let fence_guard = RwLockWriteGuard::downgrade(fence_guard);
|
||||
let (closures, _) =
|
||||
match device.maintain(fence_guard, wgt::Maintain::Poll, snatch_guard) {
|
||||
Ok(closures) => closures,
|
||||
Err(WaitIdleError::Device(err)) => return Err(QueueSubmitError::Queue(err)),
|
||||
Err(WaitIdleError::StuckGpu) => return Err(QueueSubmitError::StuckGpu),
|
||||
Err(WaitIdleError::WrongSubmissionIndex(..)) => unreachable!(),
|
||||
};
|
||||
|
||||
device.lock_life().post_submit();
|
||||
|
||||
(submit_index, closures)
|
||||
|
|
|
@ -13,13 +13,14 @@ use crate::{
|
|||
hal_api::HalApi,
|
||||
hal_label,
|
||||
hub::Hub,
|
||||
id,
|
||||
init_tracker::{
|
||||
BufferInitTracker, BufferInitTrackerAction, MemoryInitKind, TextureInitRange,
|
||||
TextureInitTracker, TextureInitTrackerAction,
|
||||
},
|
||||
instance::Adapter,
|
||||
lock::{rank, Mutex, MutexGuard},
|
||||
pipeline,
|
||||
lock::{rank, Mutex, MutexGuard, RwLock},
|
||||
pipeline::{self},
|
||||
pool::ResourcePool,
|
||||
registry::Registry,
|
||||
resource::{
|
||||
|
@ -42,7 +43,6 @@ use crate::{
|
|||
use arrayvec::ArrayVec;
|
||||
use hal::{CommandEncoder as _, Device as _};
|
||||
use once_cell::sync::OnceCell;
|
||||
use parking_lot::RwLock;
|
||||
|
||||
use smallvec::SmallVec;
|
||||
use thiserror::Error;
|
||||
|
@ -127,9 +127,6 @@ pub struct Device<A: HalApi> {
|
|||
pub(crate) tracker_indices: TrackerIndexAllocators,
|
||||
// Life tracker should be locked right after the device and before anything else.
|
||||
life_tracker: Mutex<LifetimeTracker<A>>,
|
||||
/// 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,
|
||||
|
@ -142,6 +139,10 @@ pub struct Device<A: HalApi> {
|
|||
#[cfg(feature = "trace")]
|
||||
pub(crate) trace: Mutex<Option<trace::Trace>>,
|
||||
pub(crate) usage_scopes: UsageScopePool<A>,
|
||||
|
||||
/// Temporary storage, cleared at the start of every call,
|
||||
/// retained only to save allocations.
|
||||
temp_suspected: Mutex<Option<ResourceMaps<A>>>,
|
||||
}
|
||||
|
||||
pub(crate) enum DeferredDestroy<A: HalApi> {
|
||||
|
@ -272,8 +273,8 @@ impl<A: HalApi> Device<A> {
|
|||
info: ResourceInfo::new("<device>", None),
|
||||
command_allocator,
|
||||
active_submission_index: AtomicU64::new(0),
|
||||
fence: RwLock::new(Some(fence)),
|
||||
snatchable_lock: unsafe { SnatchLock::new() },
|
||||
fence: RwLock::new(rank::DEVICE_FENCE, Some(fence)),
|
||||
snatchable_lock: unsafe { SnatchLock::new(rank::DEVICE_SNATCHABLE_LOCK) },
|
||||
valid: AtomicBool::new(true),
|
||||
trackers: Mutex::new(rank::DEVICE_TRACKERS, Tracker::new()),
|
||||
tracker_indices: TrackerIndexAllocators::new(),
|
||||
|
@ -397,11 +398,12 @@ impl<A: HalApi> Device<A> {
|
|||
/// return it to our callers.)
|
||||
pub(crate) fn maintain<'this>(
|
||||
&'this self,
|
||||
fence: &A::Fence,
|
||||
fence_guard: crate::lock::RwLockReadGuard<Option<A::Fence>>,
|
||||
maintain: wgt::Maintain<queue::WrappedSubmissionIndex>,
|
||||
snatch_guard: SnatchGuard,
|
||||
) -> Result<(UserClosures, bool), WaitIdleError> {
|
||||
profiling::scope!("Device::maintain");
|
||||
let fence = fence_guard.as_ref().unwrap();
|
||||
let last_done_index = if maintain.is_wait() {
|
||||
let index_to_wait_for = match maintain {
|
||||
wgt::Maintain::WaitForSubmissionIndex(submission_index) => {
|
||||
|
@ -433,23 +435,9 @@ impl<A: HalApi> Device<A> {
|
|||
let submission_closures =
|
||||
life_tracker.triage_submissions(last_done_index, &self.command_allocator);
|
||||
|
||||
{
|
||||
// Normally, `temp_suspected` exists only to save heap
|
||||
// allocations: it's cleared at the start of the function
|
||||
// call, and cleared by the end. But `Global::queue_submit` is
|
||||
// fallible; if it exits early, it may leave some resources in
|
||||
// `temp_suspected`.
|
||||
let temp_suspected = self
|
||||
.temp_suspected
|
||||
.lock()
|
||||
.replace(ResourceMaps::new())
|
||||
.unwrap();
|
||||
life_tracker.triage_suspected(&self.trackers);
|
||||
|
||||
life_tracker.suspected_resources.extend(temp_suspected);
|
||||
|
||||
life_tracker.triage_suspected(&self.trackers);
|
||||
life_tracker.triage_mapped();
|
||||
}
|
||||
life_tracker.triage_mapped();
|
||||
|
||||
let mapping_closures =
|
||||
life_tracker.handle_mapping(self.raw(), &self.trackers, &snatch_guard);
|
||||
|
@ -481,6 +469,7 @@ impl<A: HalApi> Device<A> {
|
|||
|
||||
// Don't hold the locks while calling release_gpu_resources.
|
||||
drop(life_tracker);
|
||||
drop(fence_guard);
|
||||
drop(snatch_guard);
|
||||
|
||||
if should_release_gpu_resource {
|
||||
|
@ -496,12 +485,14 @@ impl<A: HalApi> Device<A> {
|
|||
}
|
||||
|
||||
pub(crate) fn untrack(&self, trackers: &Tracker<A>) {
|
||||
// If we have a previously allocated `ResourceMap`, just use that.
|
||||
let mut temp_suspected = self
|
||||
.temp_suspected
|
||||
.lock()
|
||||
.replace(ResourceMaps::new())
|
||||
.unwrap();
|
||||
.take()
|
||||
.unwrap_or_else(|| ResourceMaps::new());
|
||||
temp_suspected.clear();
|
||||
|
||||
// As the tracker is cleared/dropped, we need to consider all the resources
|
||||
// that it references for destruction in the next GC pass.
|
||||
{
|
||||
|
@ -562,7 +553,11 @@ impl<A: HalApi> Device<A> {
|
|||
}
|
||||
}
|
||||
}
|
||||
self.lock_life().suspected_resources.extend(temp_suspected);
|
||||
self.lock_life()
|
||||
.suspected_resources
|
||||
.extend(&mut temp_suspected);
|
||||
// Save this resource map for later reuse.
|
||||
*self.temp_suspected.lock() = Some(temp_suspected);
|
||||
}
|
||||
|
||||
pub(crate) fn create_buffer(
|
||||
|
@ -656,7 +651,10 @@ impl<A: HalApi> Device<A> {
|
|||
device: self.clone(),
|
||||
usage: desc.usage,
|
||||
size: desc.size,
|
||||
initialization_status: RwLock::new(BufferInitTracker::new(aligned_size)),
|
||||
initialization_status: RwLock::new(
|
||||
rank::BUFFER_INITIALIZATION_STATUS,
|
||||
BufferInitTracker::new(aligned_size),
|
||||
),
|
||||
sync_mapped_writes: Mutex::new(rank::BUFFER_SYNC_MAPPED_WRITES, None),
|
||||
map_state: Mutex::new(rank::BUFFER_MAP_STATE, resource::BufferMapState::Idle),
|
||||
info: ResourceInfo::new(
|
||||
|
@ -683,10 +681,10 @@ impl<A: HalApi> Device<A> {
|
|||
desc: desc.map_label(|_| ()),
|
||||
hal_usage,
|
||||
format_features,
|
||||
initialization_status: RwLock::new(TextureInitTracker::new(
|
||||
desc.mip_level_count,
|
||||
desc.array_layer_count(),
|
||||
)),
|
||||
initialization_status: RwLock::new(
|
||||
rank::TEXTURE_INITIALIZATION_STATUS,
|
||||
TextureInitTracker::new(desc.mip_level_count, desc.array_layer_count()),
|
||||
),
|
||||
full_range: TextureSelector {
|
||||
mips: 0..desc.mip_level_count,
|
||||
layers: 0..desc.array_layer_count(),
|
||||
|
@ -695,7 +693,7 @@ impl<A: HalApi> Device<A> {
|
|||
desc.label.borrow_or_default(),
|
||||
Some(self.tracker_indices.textures.clone()),
|
||||
),
|
||||
clear_mode: RwLock::new(clear_mode),
|
||||
clear_mode: RwLock::new(rank::TEXTURE_CLEAR_MODE, clear_mode),
|
||||
views: Mutex::new(rank::TEXTURE_VIEWS, Vec::new()),
|
||||
bind_groups: Mutex::new(rank::TEXTURE_BIND_GROUPS, Vec::new()),
|
||||
}
|
||||
|
@ -713,7 +711,10 @@ impl<A: HalApi> Device<A> {
|
|||
device: self.clone(),
|
||||
usage: desc.usage,
|
||||
size: desc.size,
|
||||
initialization_status: RwLock::new(BufferInitTracker::new(0)),
|
||||
initialization_status: RwLock::new(
|
||||
rank::BUFFER_INITIALIZATION_STATUS,
|
||||
BufferInitTracker::new(0),
|
||||
),
|
||||
sync_mapped_writes: Mutex::new(rank::BUFFER_SYNC_MAPPED_WRITES, None),
|
||||
map_state: Mutex::new(rank::BUFFER_MAP_STATE, resource::BufferMapState::Idle),
|
||||
info: ResourceInfo::new(
|
||||
|
@ -1424,7 +1425,7 @@ impl<A: HalApi> Device<A> {
|
|||
pipeline::ShaderModuleSource::Wgsl(code) => {
|
||||
profiling::scope!("naga::front::wgsl::parse_str");
|
||||
let module = naga::front::wgsl::parse_str(&code).map_err(|inner| {
|
||||
pipeline::CreateShaderModuleError::Parsing(pipeline::ShaderError {
|
||||
pipeline::CreateShaderModuleError::Parsing(naga::error::ShaderError {
|
||||
source: code.to_string(),
|
||||
label: desc.label.as_ref().map(|l| l.to_string()),
|
||||
inner: Box::new(inner),
|
||||
|
@ -1437,7 +1438,7 @@ impl<A: HalApi> Device<A> {
|
|||
let parser = naga::front::spv::Frontend::new(spv.iter().cloned(), &options);
|
||||
profiling::scope!("naga::front::spv::Frontend");
|
||||
let module = parser.parse().map_err(|inner| {
|
||||
pipeline::CreateShaderModuleError::ParsingSpirV(pipeline::ShaderError {
|
||||
pipeline::CreateShaderModuleError::ParsingSpirV(naga::error::ShaderError {
|
||||
source: String::new(),
|
||||
label: desc.label.as_ref().map(|l| l.to_string()),
|
||||
inner: Box::new(inner),
|
||||
|
@ -1450,7 +1451,7 @@ impl<A: HalApi> Device<A> {
|
|||
let mut parser = naga::front::glsl::Frontend::default();
|
||||
profiling::scope!("naga::front::glsl::Frontend.parse");
|
||||
let module = parser.parse(&options, &code).map_err(|inner| {
|
||||
pipeline::CreateShaderModuleError::ParsingGlsl(pipeline::ShaderError {
|
||||
pipeline::CreateShaderModuleError::ParsingGlsl(naga::error::ShaderError {
|
||||
source: code.to_string(),
|
||||
label: desc.label.as_ref().map(|l| l.to_string()),
|
||||
inner: Box::new(inner),
|
||||
|
@ -1474,9 +1475,78 @@ impl<A: HalApi> Device<A> {
|
|||
};
|
||||
}
|
||||
|
||||
use naga::valid::Capabilities as Caps;
|
||||
profiling::scope!("naga::validate");
|
||||
let debug_source =
|
||||
if self.instance_flags.contains(wgt::InstanceFlags::DEBUG) && !source.is_empty() {
|
||||
Some(hal::DebugSource {
|
||||
file_name: Cow::Owned(
|
||||
desc.label
|
||||
.as_ref()
|
||||
.map_or("shader".to_string(), |l| l.to_string()),
|
||||
),
|
||||
source_code: Cow::Owned(source.clone()),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let info = self
|
||||
.create_validator(naga::valid::ValidationFlags::all())
|
||||
.validate(&module)
|
||||
.map_err(|inner| {
|
||||
pipeline::CreateShaderModuleError::Validation(naga::error::ShaderError {
|
||||
source,
|
||||
label: desc.label.as_ref().map(|l| l.to_string()),
|
||||
inner: Box::new(inner),
|
||||
})
|
||||
})?;
|
||||
|
||||
let interface =
|
||||
validation::Interface::new(&module, &info, self.limits.clone(), self.features);
|
||||
let hal_shader = hal::ShaderInput::Naga(hal::NagaShader {
|
||||
module,
|
||||
info,
|
||||
debug_source,
|
||||
});
|
||||
let hal_desc = hal::ShaderModuleDescriptor {
|
||||
label: desc.label.to_hal(self.instance_flags),
|
||||
runtime_checks: desc.shader_bound_checks.runtime_checks(),
|
||||
};
|
||||
let raw = match unsafe {
|
||||
self.raw
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.create_shader_module(&hal_desc, hal_shader)
|
||||
} {
|
||||
Ok(raw) => raw,
|
||||
Err(error) => {
|
||||
return Err(match error {
|
||||
hal::ShaderError::Device(error) => {
|
||||
pipeline::CreateShaderModuleError::Device(error.into())
|
||||
}
|
||||
hal::ShaderError::Compilation(ref msg) => {
|
||||
log::error!("Shader error: {}", msg);
|
||||
pipeline::CreateShaderModuleError::Generation
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
Ok(pipeline::ShaderModule {
|
||||
raw: Some(raw),
|
||||
device: self.clone(),
|
||||
interface: Some(interface),
|
||||
info: ResourceInfo::new(desc.label.borrow_or_default(), None),
|
||||
label: desc.label.borrow_or_default().to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Create a validator with the given validation flags.
|
||||
pub fn create_validator(
|
||||
self: &Arc<Self>,
|
||||
flags: naga::valid::ValidationFlags,
|
||||
) -> naga::valid::Validator {
|
||||
use naga::valid::Capabilities as Caps;
|
||||
let mut caps = Caps::empty();
|
||||
caps.set(
|
||||
Caps::PUSH_CONSTANT,
|
||||
|
@ -1554,20 +1624,6 @@ impl<A: HalApi> Device<A> {
|
|||
self.features.intersects(wgt::Features::SUBGROUP_BARRIER),
|
||||
);
|
||||
|
||||
let debug_source =
|
||||
if self.instance_flags.contains(wgt::InstanceFlags::DEBUG) && !source.is_empty() {
|
||||
Some(hal::DebugSource {
|
||||
file_name: Cow::Owned(
|
||||
desc.label
|
||||
.as_ref()
|
||||
.map_or("shader".to_string(), |l| l.to_string()),
|
||||
),
|
||||
source_code: Cow::Owned(source.clone()),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mut subgroup_stages = naga::valid::ShaderStages::empty();
|
||||
subgroup_stages.set(
|
||||
naga::valid::ShaderStages::COMPUTE | naga::valid::ShaderStages::FRAGMENT,
|
||||
|
@ -1584,57 +1640,10 @@ impl<A: HalApi> Device<A> {
|
|||
} else {
|
||||
naga::valid::SubgroupOperationSet::empty()
|
||||
};
|
||||
|
||||
let info = naga::valid::Validator::new(naga::valid::ValidationFlags::all(), caps)
|
||||
.subgroup_stages(subgroup_stages)
|
||||
.subgroup_operations(subgroup_operations)
|
||||
.validate(&module)
|
||||
.map_err(|inner| {
|
||||
pipeline::CreateShaderModuleError::Validation(pipeline::ShaderError {
|
||||
source,
|
||||
label: desc.label.as_ref().map(|l| l.to_string()),
|
||||
inner: Box::new(inner),
|
||||
})
|
||||
})?;
|
||||
|
||||
let interface =
|
||||
validation::Interface::new(&module, &info, self.limits.clone(), self.features);
|
||||
let hal_shader = hal::ShaderInput::Naga(hal::NagaShader {
|
||||
module,
|
||||
info,
|
||||
debug_source,
|
||||
});
|
||||
let hal_desc = hal::ShaderModuleDescriptor {
|
||||
label: desc.label.to_hal(self.instance_flags),
|
||||
runtime_checks: desc.shader_bound_checks.runtime_checks(),
|
||||
};
|
||||
let raw = match unsafe {
|
||||
self.raw
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.create_shader_module(&hal_desc, hal_shader)
|
||||
} {
|
||||
Ok(raw) => raw,
|
||||
Err(error) => {
|
||||
return Err(match error {
|
||||
hal::ShaderError::Device(error) => {
|
||||
pipeline::CreateShaderModuleError::Device(error.into())
|
||||
}
|
||||
hal::ShaderError::Compilation(ref msg) => {
|
||||
log::error!("Shader error: {}", msg);
|
||||
pipeline::CreateShaderModuleError::Generation
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
Ok(pipeline::ShaderModule {
|
||||
raw: Some(raw),
|
||||
device: self.clone(),
|
||||
interface: Some(interface),
|
||||
info: ResourceInfo::new(desc.label.borrow_or_default(), None),
|
||||
label: desc.label.borrow_or_default().to_string(),
|
||||
})
|
||||
let mut validator = naga::valid::Validator::new(flags, caps);
|
||||
validator.subgroup_stages(subgroup_stages);
|
||||
validator.subgroup_operations(subgroup_operations);
|
||||
validator
|
||||
}
|
||||
|
||||
#[allow(unused_unsafe)]
|
||||
|
@ -1944,6 +1953,7 @@ impl<A: HalApi> Device<A> {
|
|||
used: &mut BindGroupStates<A>,
|
||||
storage: &'a Storage<Buffer<A>>,
|
||||
limits: &wgt::Limits,
|
||||
device_id: id::Id<id::markers::Device>,
|
||||
snatch_guard: &'a SnatchGuard<'a>,
|
||||
) -> Result<hal::BufferBinding<'a, A>, binding_model::CreateBindGroupError> {
|
||||
use crate::binding_model::CreateBindGroupError as Error;
|
||||
|
@ -1962,6 +1972,7 @@ impl<A: HalApi> Device<A> {
|
|||
})
|
||||
}
|
||||
};
|
||||
|
||||
let (pub_usage, internal_use, range_limit) = match binding_ty {
|
||||
wgt::BufferBindingType::Uniform => (
|
||||
wgt::BufferUsages::UNIFORM,
|
||||
|
@ -1994,6 +2005,10 @@ impl<A: HalApi> Device<A> {
|
|||
.add_single(storage, bb.buffer_id, internal_use)
|
||||
.ok_or(Error::InvalidBuffer(bb.buffer_id))?;
|
||||
|
||||
if buffer.device.as_info().id() != device_id {
|
||||
return Err(DeviceError::WrongDevice.into());
|
||||
}
|
||||
|
||||
check_buffer_usage(bb.buffer_id, buffer.usage, pub_usage)?;
|
||||
let raw_buffer = buffer
|
||||
.raw
|
||||
|
@ -2072,13 +2087,53 @@ impl<A: HalApi> Device<A> {
|
|||
})
|
||||
}
|
||||
|
||||
pub(crate) fn create_texture_binding(
|
||||
view: &TextureView<A>,
|
||||
internal_use: hal::TextureUses,
|
||||
pub_usage: wgt::TextureUsages,
|
||||
fn create_sampler_binding<'a>(
|
||||
used: &BindGroupStates<A>,
|
||||
storage: &'a Storage<Sampler<A>>,
|
||||
id: id::Id<id::markers::Sampler>,
|
||||
device_id: id::Id<id::markers::Device>,
|
||||
) -> Result<&'a Sampler<A>, binding_model::CreateBindGroupError> {
|
||||
use crate::binding_model::CreateBindGroupError as Error;
|
||||
|
||||
let sampler = used
|
||||
.samplers
|
||||
.add_single(storage, id)
|
||||
.ok_or(Error::InvalidSampler(id))?;
|
||||
|
||||
if sampler.device.as_info().id() != device_id {
|
||||
return Err(DeviceError::WrongDevice.into());
|
||||
}
|
||||
|
||||
Ok(sampler)
|
||||
}
|
||||
|
||||
pub(crate) fn create_texture_binding<'a>(
|
||||
self: &Arc<Self>,
|
||||
binding: u32,
|
||||
decl: &wgt::BindGroupLayoutEntry,
|
||||
storage: &'a Storage<TextureView<A>>,
|
||||
id: id::Id<id::markers::TextureView>,
|
||||
used: &mut BindGroupStates<A>,
|
||||
used_texture_ranges: &mut Vec<TextureInitTrackerAction<A>>,
|
||||
) -> Result<(), binding_model::CreateBindGroupError> {
|
||||
snatch_guard: &'a SnatchGuard<'a>,
|
||||
) -> Result<hal::TextureBinding<'a, A>, binding_model::CreateBindGroupError> {
|
||||
use crate::binding_model::CreateBindGroupError as Error;
|
||||
|
||||
let view = used
|
||||
.views
|
||||
.add_single(storage, id)
|
||||
.ok_or(Error::InvalidTextureView(id))?;
|
||||
|
||||
if view.device.as_info().id() != self.as_info().id() {
|
||||
return Err(DeviceError::WrongDevice.into());
|
||||
}
|
||||
|
||||
let (pub_usage, internal_use) = self.texture_use_parameters(
|
||||
binding,
|
||||
decl,
|
||||
view,
|
||||
"SampledTexture, ReadonlyStorageTexture or WriteonlyStorageTexture",
|
||||
)?;
|
||||
let texture = &view.parent;
|
||||
let texture_id = texture.as_info().id();
|
||||
// Careful here: the texture may no longer have its own ref count,
|
||||
|
@ -2108,7 +2163,12 @@ impl<A: HalApi> Device<A> {
|
|||
kind: MemoryInitKind::NeedsInitializedMemory,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
Ok(hal::TextureBinding {
|
||||
view: view
|
||||
.raw(snatch_guard)
|
||||
.ok_or(Error::InvalidTextureView(id))?,
|
||||
usage: internal_use,
|
||||
})
|
||||
}
|
||||
|
||||
// This function expects the provided bind group layout to be resolved
|
||||
|
@ -2170,6 +2230,7 @@ impl<A: HalApi> Device<A> {
|
|||
&mut used,
|
||||
&*buffer_guard,
|
||||
&self.limits,
|
||||
self.as_info().id(),
|
||||
&snatch_guard,
|
||||
)?;
|
||||
|
||||
|
@ -2193,105 +2254,86 @@ impl<A: HalApi> Device<A> {
|
|||
&mut used,
|
||||
&*buffer_guard,
|
||||
&self.limits,
|
||||
self.as_info().id(),
|
||||
&snatch_guard,
|
||||
)?;
|
||||
hal_buffers.push(bb);
|
||||
}
|
||||
(res_index, num_bindings)
|
||||
}
|
||||
Br::Sampler(id) => {
|
||||
match decl.ty {
|
||||
wgt::BindingType::Sampler(ty) => {
|
||||
let sampler = used
|
||||
.samplers
|
||||
.add_single(&*sampler_guard, id)
|
||||
.ok_or(Error::InvalidSampler(id))?;
|
||||
Br::Sampler(id) => match decl.ty {
|
||||
wgt::BindingType::Sampler(ty) => {
|
||||
let sampler = Self::create_sampler_binding(
|
||||
&used,
|
||||
&sampler_guard,
|
||||
id,
|
||||
self.as_info().id(),
|
||||
)?;
|
||||
|
||||
if sampler.device.as_info().id() != self.as_info().id() {
|
||||
return Err(DeviceError::WrongDevice.into());
|
||||
}
|
||||
|
||||
// Allowed sampler values for filtering and comparison
|
||||
let (allowed_filtering, allowed_comparison) = match ty {
|
||||
wgt::SamplerBindingType::Filtering => (None, false),
|
||||
wgt::SamplerBindingType::NonFiltering => (Some(false), false),
|
||||
wgt::SamplerBindingType::Comparison => (None, true),
|
||||
};
|
||||
|
||||
if let Some(allowed_filtering) = allowed_filtering {
|
||||
if allowed_filtering != sampler.filtering {
|
||||
return Err(Error::WrongSamplerFiltering {
|
||||
binding,
|
||||
layout_flt: allowed_filtering,
|
||||
sampler_flt: sampler.filtering,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if allowed_comparison != sampler.comparison {
|
||||
return Err(Error::WrongSamplerComparison {
|
||||
let (allowed_filtering, allowed_comparison) = match ty {
|
||||
wgt::SamplerBindingType::Filtering => (None, false),
|
||||
wgt::SamplerBindingType::NonFiltering => (Some(false), false),
|
||||
wgt::SamplerBindingType::Comparison => (None, true),
|
||||
};
|
||||
if let Some(allowed_filtering) = allowed_filtering {
|
||||
if allowed_filtering != sampler.filtering {
|
||||
return Err(Error::WrongSamplerFiltering {
|
||||
binding,
|
||||
layout_cmp: allowed_comparison,
|
||||
sampler_cmp: sampler.comparison,
|
||||
layout_flt: allowed_filtering,
|
||||
sampler_flt: sampler.filtering,
|
||||
});
|
||||
}
|
||||
|
||||
let res_index = hal_samplers.len();
|
||||
hal_samplers.push(sampler.raw());
|
||||
(res_index, 1)
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::WrongBindingType {
|
||||
if allowed_comparison != sampler.comparison {
|
||||
return Err(Error::WrongSamplerComparison {
|
||||
binding,
|
||||
actual: decl.ty,
|
||||
expected: "Sampler",
|
||||
})
|
||||
layout_cmp: allowed_comparison,
|
||||
sampler_cmp: sampler.comparison,
|
||||
});
|
||||
}
|
||||
|
||||
let res_index = hal_samplers.len();
|
||||
hal_samplers.push(sampler.raw());
|
||||
(res_index, 1)
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::WrongBindingType {
|
||||
binding,
|
||||
actual: decl.ty,
|
||||
expected: "Sampler",
|
||||
})
|
||||
}
|
||||
},
|
||||
Br::SamplerArray(ref bindings_array) => {
|
||||
let num_bindings = bindings_array.len();
|
||||
Self::check_array_binding(self.features, decl.count, num_bindings)?;
|
||||
|
||||
let res_index = hal_samplers.len();
|
||||
for &id in bindings_array.iter() {
|
||||
let sampler = used
|
||||
.samplers
|
||||
.add_single(&*sampler_guard, id)
|
||||
.ok_or(Error::InvalidSampler(id))?;
|
||||
if sampler.device.as_info().id() != self.as_info().id() {
|
||||
return Err(DeviceError::WrongDevice.into());
|
||||
}
|
||||
let sampler = Self::create_sampler_binding(
|
||||
&used,
|
||||
&sampler_guard,
|
||||
id,
|
||||
self.as_info().id(),
|
||||
)?;
|
||||
|
||||
hal_samplers.push(sampler.raw());
|
||||
}
|
||||
|
||||
(res_index, num_bindings)
|
||||
}
|
||||
Br::TextureView(id) => {
|
||||
let view = used
|
||||
.views
|
||||
.add_single(&*texture_view_guard, id)
|
||||
.ok_or(Error::InvalidTextureView(id))?;
|
||||
let (pub_usage, internal_use) = self.texture_use_parameters(
|
||||
let tb = self.create_texture_binding(
|
||||
binding,
|
||||
decl,
|
||||
view,
|
||||
"SampledTexture, ReadonlyStorageTexture or WriteonlyStorageTexture",
|
||||
)?;
|
||||
Self::create_texture_binding(
|
||||
view,
|
||||
internal_use,
|
||||
pub_usage,
|
||||
&texture_view_guard,
|
||||
id,
|
||||
&mut used,
|
||||
&mut used_texture_ranges,
|
||||
&snatch_guard,
|
||||
)?;
|
||||
let res_index = hal_textures.len();
|
||||
hal_textures.push(hal::TextureBinding {
|
||||
view: view
|
||||
.raw(&snatch_guard)
|
||||
.ok_or(Error::InvalidTextureView(id))?,
|
||||
usage: internal_use,
|
||||
});
|
||||
hal_textures.push(tb);
|
||||
(res_index, 1)
|
||||
}
|
||||
Br::TextureViewArray(ref bindings_array) => {
|
||||
|
@ -2300,26 +2342,17 @@ impl<A: HalApi> Device<A> {
|
|||
|
||||
let res_index = hal_textures.len();
|
||||
for &id in bindings_array.iter() {
|
||||
let view = used
|
||||
.views
|
||||
.add_single(&*texture_view_guard, id)
|
||||
.ok_or(Error::InvalidTextureView(id))?;
|
||||
let (pub_usage, internal_use) =
|
||||
self.texture_use_parameters(binding, decl, view,
|
||||
"SampledTextureArray, ReadonlyStorageTextureArray or WriteonlyStorageTextureArray")?;
|
||||
Self::create_texture_binding(
|
||||
view,
|
||||
internal_use,
|
||||
pub_usage,
|
||||
let tb = self.create_texture_binding(
|
||||
binding,
|
||||
decl,
|
||||
&texture_view_guard,
|
||||
id,
|
||||
&mut used,
|
||||
&mut used_texture_ranges,
|
||||
&snatch_guard,
|
||||
)?;
|
||||
hal_textures.push(hal::TextureBinding {
|
||||
view: view
|
||||
.raw(&snatch_guard)
|
||||
.ok_or(Error::InvalidTextureView(id))?,
|
||||
usage: internal_use,
|
||||
});
|
||||
|
||||
hal_textures.push(tb);
|
||||
}
|
||||
|
||||
(res_index, num_bindings)
|
||||
|
|
|
@ -35,7 +35,7 @@ mod ranked;
|
|||
mod vanilla;
|
||||
|
||||
#[cfg(wgpu_validate_locks)]
|
||||
pub use ranked::{Mutex, MutexGuard};
|
||||
pub use ranked::{Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
|
||||
#[cfg(not(wgpu_validate_locks))]
|
||||
pub use vanilla::{Mutex, MutexGuard};
|
||||
pub use vanilla::{Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
|
|
|
@ -45,7 +45,7 @@ macro_rules! define_lock_ranks {
|
|||
{
|
||||
$(
|
||||
$( #[ $attr:meta ] )*
|
||||
rank $name:ident $member:literal followed by { $( $follower:ident ),* $(,)? };
|
||||
rank $name:ident $member:literal followed by { $( $follower:ident ),* $(,)? }
|
||||
)*
|
||||
} => {
|
||||
// An enum that assigns a unique number to each rank.
|
||||
|
@ -55,9 +55,9 @@ macro_rules! define_lock_ranks {
|
|||
bitflags::bitflags! {
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
/// A bitflags type representing a set of lock ranks.
|
||||
pub struct LockRankSet: u32 {
|
||||
pub struct LockRankSet: u64 {
|
||||
$(
|
||||
const $name = 1 << (LockRankNumber:: $name as u32);
|
||||
const $name = 1 << (LockRankNumber:: $name as u64);
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
@ -87,57 +87,84 @@ macro_rules! define_lock_ranks {
|
|||
}
|
||||
|
||||
define_lock_ranks! {
|
||||
rank DEVICE_TEMP_SUSPECTED "Device::temp_suspected" followed by {
|
||||
SHARED_TRACKER_INDEX_ALLOCATOR_INNER,
|
||||
COMMAND_BUFFER_DATA,
|
||||
DEVICE_TRACKERS,
|
||||
}
|
||||
rank COMMAND_BUFFER_DATA "CommandBuffer::data" followed by {
|
||||
DEVICE_SNATCHABLE_LOCK,
|
||||
DEVICE_USAGE_SCOPES,
|
||||
SHARED_TRACKER_INDEX_ALLOCATOR_INNER,
|
||||
BUFFER_BIND_GROUP_STATE_BUFFERS,
|
||||
TEXTURE_BIND_GROUP_STATE_TEXTURES,
|
||||
BUFFER_MAP_STATE,
|
||||
STATELESS_BIND_GROUP_STATE_RESOURCES,
|
||||
};
|
||||
rank STAGING_BUFFER_RAW "StagingBuffer::raw" followed by { };
|
||||
rank COMMAND_ALLOCATOR_FREE_ENCODERS "CommandAllocator::free_encoders" followed by {
|
||||
}
|
||||
rank DEVICE_SNATCHABLE_LOCK "Device::snatchable_lock" followed by {
|
||||
SHARED_TRACKER_INDEX_ALLOCATOR_INNER,
|
||||
};
|
||||
rank DEVICE_TRACKERS "Device::trackers" followed by { };
|
||||
rank DEVICE_LIFE_TRACKER "Device::life_tracker" followed by {
|
||||
COMMAND_ALLOCATOR_FREE_ENCODERS,
|
||||
DEVICE_TRACE,
|
||||
BUFFER_MAP_STATE,
|
||||
BUFFER_BIND_GROUP_STATE_BUFFERS,
|
||||
TEXTURE_BIND_GROUP_STATE_TEXTURES,
|
||||
STATELESS_BIND_GROUP_STATE_RESOURCES,
|
||||
// Uncomment this to see an interesting cycle.
|
||||
// DEVICE_TEMP_SUSPECTED,
|
||||
};
|
||||
rank DEVICE_TEMP_SUSPECTED "Device::temp_suspected" followed by {
|
||||
// COMMAND_BUFFER_DATA,
|
||||
}
|
||||
rank BUFFER_MAP_STATE "Buffer::map_state" followed by {
|
||||
DEVICE_PENDING_WRITES,
|
||||
SHARED_TRACKER_INDEX_ALLOCATOR_INNER,
|
||||
COMMAND_BUFFER_DATA,
|
||||
DEVICE_TRACKERS,
|
||||
};
|
||||
DEVICE_TRACE,
|
||||
}
|
||||
rank DEVICE_PENDING_WRITES "Device::pending_writes" followed by {
|
||||
COMMAND_ALLOCATOR_FREE_ENCODERS,
|
||||
SHARED_TRACKER_INDEX_ALLOCATOR_INNER,
|
||||
DEVICE_LIFE_TRACKER,
|
||||
};
|
||||
rank DEVICE_DEFERRED_DESTROY "Device::deferred_destroy" followed by { };
|
||||
}
|
||||
rank DEVICE_LIFE_TRACKER "Device::life_tracker" followed by {
|
||||
COMMAND_ALLOCATOR_FREE_ENCODERS,
|
||||
// Uncomment this to see an interesting cycle.
|
||||
// DEVICE_TEMP_SUSPECTED,
|
||||
DEVICE_TRACE,
|
||||
}
|
||||
rank COMMAND_ALLOCATOR_FREE_ENCODERS "CommandAllocator::free_encoders" followed by {
|
||||
SHARED_TRACKER_INDEX_ALLOCATOR_INNER,
|
||||
}
|
||||
|
||||
rank BUFFER_BIND_GROUPS "Buffer::bind_groups" followed by { }
|
||||
rank BUFFER_BIND_GROUP_STATE_BUFFERS "BufferBindGroupState::buffers" followed by { }
|
||||
rank BUFFER_INITIALIZATION_STATUS "Buffer::initialization_status" followed by { }
|
||||
rank BUFFER_SYNC_MAPPED_WRITES "Buffer::sync_mapped_writes" followed by { }
|
||||
rank DEVICE_DEFERRED_DESTROY "Device::deferred_destroy" followed by { }
|
||||
rank DEVICE_FENCE "Device::fence" followed by { }
|
||||
#[allow(dead_code)]
|
||||
rank DEVICE_TRACE "Device::trace" followed by { };
|
||||
rank DEVICE_USAGE_SCOPES "Device::usage_scopes" followed by { };
|
||||
rank BUFFER_SYNC_MAPPED_WRITES "Buffer::sync_mapped_writes" followed by { };
|
||||
rank BUFFER_MAP_STATE "Buffer::map_state" followed by { DEVICE_PENDING_WRITES };
|
||||
rank BUFFER_BIND_GROUPS "Buffer::bind_groups" followed by { };
|
||||
rank TEXTURE_VIEWS "Texture::views" followed by { };
|
||||
rank TEXTURE_BIND_GROUPS "Texture::bind_groups" followed by { };
|
||||
rank IDENTITY_MANAGER_VALUES "IdentityManager::values" followed by { };
|
||||
rank RESOURCE_POOL_INNER "ResourcePool::inner" followed by { };
|
||||
rank BUFFER_BIND_GROUP_STATE_BUFFERS "BufferBindGroupState::buffers" followed by { };
|
||||
rank STATELESS_BIND_GROUP_STATE_RESOURCES "StatelessBindGroupState::resources" followed by { };
|
||||
rank TEXTURE_BIND_GROUP_STATE_TEXTURES "TextureBindGroupState::textures" followed by { };
|
||||
rank SHARED_TRACKER_INDEX_ALLOCATOR_INNER "SharedTrackerIndexAllocator::inner" followed by { };
|
||||
rank SURFACE_PRESENTATION "Surface::presentation" followed by { };
|
||||
rank DEVICE_TRACE "Device::trace" followed by { }
|
||||
rank DEVICE_TRACKERS "Device::trackers" followed by { }
|
||||
rank DEVICE_USAGE_SCOPES "Device::usage_scopes" followed by { }
|
||||
rank IDENTITY_MANAGER_VALUES "IdentityManager::values" followed by { }
|
||||
rank REGISTRY_STORAGE "Registry::storage" followed by { }
|
||||
rank RENDER_BUNDLE_SCOPE_BUFFERS "RenderBundleScope::buffers" followed by { }
|
||||
rank RENDER_BUNDLE_SCOPE_TEXTURES "RenderBundleScope::textures" followed by { }
|
||||
rank RENDER_BUNDLE_SCOPE_BIND_GROUPS "RenderBundleScope::bind_groups" followed by { }
|
||||
rank RENDER_BUNDLE_SCOPE_RENDER_PIPELINES "RenderBundleScope::render_pipelines" followed by { }
|
||||
rank RENDER_BUNDLE_SCOPE_QUERY_SETS "RenderBundleScope::query_sets" followed by { }
|
||||
rank RESOURCE_POOL_INNER "ResourcePool::inner" followed by { }
|
||||
rank SHARED_TRACKER_INDEX_ALLOCATOR_INNER "SharedTrackerIndexAllocator::inner" followed by { }
|
||||
rank STAGING_BUFFER_RAW "StagingBuffer::raw" followed by { }
|
||||
rank STATELESS_BIND_GROUP_STATE_RESOURCES "StatelessBindGroupState::resources" followed by { }
|
||||
rank SURFACE_PRESENTATION "Surface::presentation" followed by { }
|
||||
rank TEXTURE_BIND_GROUPS "Texture::bind_groups" followed by { }
|
||||
rank TEXTURE_BIND_GROUP_STATE_TEXTURES "TextureBindGroupState::textures" followed by { }
|
||||
rank TEXTURE_INITIALIZATION_STATUS "Texture::initialization_status" followed by { }
|
||||
rank TEXTURE_CLEAR_MODE "Texture::clear_mode" followed by { }
|
||||
rank TEXTURE_VIEWS "Texture::views" followed by { }
|
||||
|
||||
#[cfg(test)]
|
||||
rank PAWN "pawn" followed by { ROOK, BISHOP };
|
||||
rank PAWN "pawn" followed by { ROOK, BISHOP }
|
||||
#[cfg(test)]
|
||||
rank ROOK "rook" followed by { KNIGHT };
|
||||
rank ROOK "rook" followed by { KNIGHT }
|
||||
#[cfg(test)]
|
||||
rank KNIGHT "knight" followed by { };
|
||||
rank KNIGHT "knight" followed by { }
|
||||
#[cfg(test)]
|
||||
rank BISHOP "bishop" followed by { };
|
||||
rank BISHOP "bishop" followed by { }
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
//! Lock types that enforce well-ranked lock acquisition order.
|
||||
//!
|
||||
//! This module's [`Mutex`] type is instrumented to check that `wgpu-core`
|
||||
//! acquires locks according to their rank, to prevent deadlocks. To use it,
|
||||
//! put `--cfg wgpu_validate_locks` in `RUSTFLAGS`.
|
||||
//! This module's [`Mutex`] and [`RwLock` types are instrumented to check that
|
||||
//! `wgpu-core` acquires locks according to their rank, to prevent deadlocks. To
|
||||
//! use it, put `--cfg wgpu_validate_locks` in `RUSTFLAGS`.
|
||||
//!
|
||||
//! The [`LockRank`] constants in the [`lock::rank`] module describe edges in a
|
||||
//! directed graph of lock acquisitions: each lock's rank says, if this is the most
|
||||
|
@ -81,7 +81,11 @@ pub struct Mutex<T> {
|
|||
/// [mod]: crate::lock::ranked
|
||||
pub struct MutexGuard<'a, T> {
|
||||
inner: parking_lot::MutexGuard<'a, T>,
|
||||
saved: LockState,
|
||||
saved: LockStateGuard,
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
static LOCK_STATE: Cell<LockState> = const { Cell::new(LockState::INITIAL) };
|
||||
}
|
||||
|
||||
/// Per-thread state for the deadlock checker.
|
||||
|
@ -103,8 +107,77 @@ impl LockState {
|
|||
};
|
||||
}
|
||||
|
||||
/// A container that restores a [`LockState`] when dropped.
|
||||
///
|
||||
/// This type serves two purposes:
|
||||
///
|
||||
/// - Operations like `RwLockWriteGuard::downgrade` would like to be able to
|
||||
/// destructure lock guards and reassemble their pieces into new guards, but
|
||||
/// if the guard type itself implements `Drop`, we can't destructure it
|
||||
/// without unsafe code or pointless `Option`s whose state is almost always
|
||||
/// statically known.
|
||||
///
|
||||
/// - We can just implement `Drop` for this type once, and then use it in lock
|
||||
/// guards, rather than implementing `Drop` separately for each guard type.
|
||||
struct LockStateGuard(LockState);
|
||||
|
||||
impl Drop for LockStateGuard {
|
||||
fn drop(&mut self) {
|
||||
release(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Check and record the acquisition of a lock with `new_rank`.
|
||||
///
|
||||
/// Check that acquiring a lock with `new_rank` is permitted at this point, and
|
||||
/// update the per-thread state accordingly.
|
||||
///
|
||||
/// Return the `LockState` that must be restored when this thread is released.
|
||||
fn acquire(new_rank: LockRank, location: &'static Location<'static>) -> LockState {
|
||||
let state = LOCK_STATE.get();
|
||||
// Initially, it's fine to acquire any lock. So we only
|
||||
// need to check when `last_acquired` is `Some`.
|
||||
if let Some((ref last_rank, ref last_location)) = state.last_acquired {
|
||||
assert!(
|
||||
last_rank.followers.contains(new_rank.bit),
|
||||
"Attempt to acquire nested mutexes in wrong order:\n\
|
||||
last locked {:<35} at {}\n\
|
||||
now locking {:<35} at {}\n\
|
||||
Locking {} after locking {} is not permitted.",
|
||||
last_rank.bit.name(),
|
||||
last_location,
|
||||
new_rank.bit.name(),
|
||||
location,
|
||||
new_rank.bit.name(),
|
||||
last_rank.bit.name(),
|
||||
);
|
||||
}
|
||||
LOCK_STATE.set(LockState {
|
||||
last_acquired: Some((new_rank, location)),
|
||||
depth: state.depth + 1,
|
||||
});
|
||||
state
|
||||
}
|
||||
|
||||
/// Record the release of a lock whose saved state was `saved`.
|
||||
///
|
||||
/// Check that locks are being acquired in stacking order, and update the
|
||||
/// per-thread state accordingly.
|
||||
fn release(saved: LockState) {
|
||||
let prior = LOCK_STATE.replace(saved);
|
||||
|
||||
// Although Rust allows mutex guards to be dropped in any
|
||||
// order, this analysis requires that locks be acquired and
|
||||
// released in stack order: the next lock to be released must be
|
||||
// the most recently acquired lock still held.
|
||||
assert_eq!(
|
||||
prior.depth,
|
||||
saved.depth + 1,
|
||||
"Lock not released in stacking order"
|
||||
);
|
||||
}
|
||||
|
||||
impl<T> Mutex<T> {
|
||||
#[inline]
|
||||
pub fn new(rank: LockRank, value: T) -> Mutex<T> {
|
||||
Mutex {
|
||||
inner: parking_lot::Mutex::new(value),
|
||||
|
@ -112,59 +185,16 @@ impl<T> Mutex<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
pub fn lock(&self) -> MutexGuard<T> {
|
||||
let state = LOCK_STATE.get();
|
||||
let location = Location::caller();
|
||||
// Initially, it's fine to acquire any lock. So we only
|
||||
// need to check when `last_acquired` is `Some`.
|
||||
if let Some((ref last_rank, ref last_location)) = state.last_acquired {
|
||||
assert!(
|
||||
last_rank.followers.contains(self.rank.bit),
|
||||
"Attempt to acquire nested mutexes in wrong order:\n\
|
||||
last locked {:<35} at {}\n\
|
||||
now locking {:<35} at {}\n\
|
||||
Locking {} after locking {} is not permitted.",
|
||||
last_rank.bit.name(),
|
||||
last_location,
|
||||
self.rank.bit.name(),
|
||||
location,
|
||||
self.rank.bit.name(),
|
||||
last_rank.bit.name(),
|
||||
);
|
||||
}
|
||||
LOCK_STATE.set(LockState {
|
||||
last_acquired: Some((self.rank, location)),
|
||||
depth: state.depth + 1,
|
||||
});
|
||||
let saved = acquire(self.rank, Location::caller());
|
||||
MutexGuard {
|
||||
inner: self.inner.lock(),
|
||||
saved: state,
|
||||
saved: LockStateGuard(saved),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Drop for MutexGuard<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
let prior = LOCK_STATE.replace(self.saved);
|
||||
|
||||
// Although Rust allows mutex guards to be dropped in any
|
||||
// order, this analysis requires that locks be acquired and
|
||||
// released in stack order: the next lock to be released must be
|
||||
// the most recently acquired lock still held.
|
||||
assert_eq!(
|
||||
prior.depth,
|
||||
self.saved.depth + 1,
|
||||
"Lock not released in stacking order"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
static LOCK_STATE: Cell<LockState> = const { Cell::new(LockState::INITIAL) };
|
||||
}
|
||||
|
||||
impl<'a, T> std::ops::Deref for MutexGuard<'a, T> {
|
||||
type Target = T;
|
||||
|
||||
|
@ -185,6 +215,109 @@ impl<T: std::fmt::Debug> std::fmt::Debug for Mutex<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// An `RwLock` instrumented for deadlock prevention.
|
||||
///
|
||||
/// This is just a wrapper around a [`parking_lot::RwLock`], along with
|
||||
/// its rank in the `wgpu_core` lock ordering.
|
||||
///
|
||||
/// For details, see [the module documentation][mod].
|
||||
///
|
||||
/// [mod]: crate::lock::ranked
|
||||
pub struct RwLock<T> {
|
||||
inner: parking_lot::RwLock<T>,
|
||||
rank: LockRank,
|
||||
}
|
||||
|
||||
/// A read guard produced by locking [`RwLock`] for reading.
|
||||
///
|
||||
/// This is just a wrapper around a [`parking_lot::RwLockReadGuard`], along with
|
||||
/// the state needed to track lock acquisition.
|
||||
///
|
||||
/// For details, see [the module documentation][mod].
|
||||
///
|
||||
/// [mod]: crate::lock::ranked
|
||||
pub struct RwLockReadGuard<'a, T> {
|
||||
inner: parking_lot::RwLockReadGuard<'a, T>,
|
||||
saved: LockStateGuard,
|
||||
}
|
||||
|
||||
/// A write guard produced by locking [`RwLock`] for writing.
|
||||
///
|
||||
/// This is just a wrapper around a [`parking_lot::RwLockWriteGuard`], along
|
||||
/// with the state needed to track lock acquisition.
|
||||
///
|
||||
/// For details, see [the module documentation][mod].
|
||||
///
|
||||
/// [mod]: crate::lock::ranked
|
||||
pub struct RwLockWriteGuard<'a, T> {
|
||||
inner: parking_lot::RwLockWriteGuard<'a, T>,
|
||||
saved: LockStateGuard,
|
||||
}
|
||||
|
||||
impl<T> RwLock<T> {
|
||||
pub fn new(rank: LockRank, value: T) -> RwLock<T> {
|
||||
RwLock {
|
||||
inner: parking_lot::RwLock::new(value),
|
||||
rank,
|
||||
}
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn read(&self) -> RwLockReadGuard<T> {
|
||||
let saved = acquire(self.rank, Location::caller());
|
||||
RwLockReadGuard {
|
||||
inner: self.inner.read(),
|
||||
saved: LockStateGuard(saved),
|
||||
}
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn write(&self) -> RwLockWriteGuard<T> {
|
||||
let saved = acquire(self.rank, Location::caller());
|
||||
RwLockWriteGuard {
|
||||
inner: self.inner.write(),
|
||||
saved: LockStateGuard(saved),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> RwLockWriteGuard<'a, T> {
|
||||
pub fn downgrade(this: Self) -> RwLockReadGuard<'a, T> {
|
||||
RwLockReadGuard {
|
||||
inner: parking_lot::RwLockWriteGuard::downgrade(this.inner),
|
||||
saved: this.saved,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: std::fmt::Debug> std::fmt::Debug for RwLock<T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.inner.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> std::ops::Deref for RwLockReadGuard<'a, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.inner.deref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> std::ops::Deref for RwLockWriteGuard<'a, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.inner.deref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> std::ops::DerefMut for RwLockWriteGuard<'a, T> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.inner.deref_mut()
|
||||
}
|
||||
}
|
||||
|
||||
/// Locks can be acquired in the order indicated by their ranks.
|
||||
#[test]
|
||||
fn permitted() {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
/// A plain wrapper around [`parking_lot::Mutex`].
|
||||
///
|
||||
/// This is just like [`parking_lot::Mutex`], except that our [`new`]
|
||||
/// method takes a rank, indicating where the new mutex should sitc in
|
||||
/// method takes a rank, indicating where the new mutex should sit in
|
||||
/// `wgpu-core`'s lock ordering. The rank is ignored.
|
||||
///
|
||||
/// See the [`lock`] module documentation for other wrappers.
|
||||
|
@ -21,12 +21,10 @@ pub struct Mutex<T>(parking_lot::Mutex<T>);
|
|||
pub struct MutexGuard<'a, T>(parking_lot::MutexGuard<'a, T>);
|
||||
|
||||
impl<T> Mutex<T> {
|
||||
#[inline]
|
||||
pub fn new(_rank: super::rank::LockRank, value: T) -> Mutex<T> {
|
||||
Mutex(parking_lot::Mutex::new(value))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn lock(&self) -> MutexGuard<T> {
|
||||
MutexGuard(self.0.lock())
|
||||
}
|
||||
|
@ -51,3 +49,73 @@ impl<T: std::fmt::Debug> std::fmt::Debug for Mutex<T> {
|
|||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
/// A plain wrapper around [`parking_lot::RwLock`].
|
||||
///
|
||||
/// This is just like [`parking_lot::RwLock`], except that our [`new`]
|
||||
/// method takes a rank, indicating where the new mutex should sit in
|
||||
/// `wgpu-core`'s lock ordering. The rank is ignored.
|
||||
///
|
||||
/// See the [`lock`] module documentation for other wrappers.
|
||||
///
|
||||
/// [`new`]: RwLock::new
|
||||
/// [`lock`]: crate::lock
|
||||
pub struct RwLock<T>(parking_lot::RwLock<T>);
|
||||
|
||||
/// A read guard produced by locking [`RwLock`] as a reader.
|
||||
///
|
||||
/// This is just a wrapper around a [`parking_lot::RwLockReadGuard`].
|
||||
pub struct RwLockReadGuard<'a, T>(parking_lot::RwLockReadGuard<'a, T>);
|
||||
|
||||
/// A write guard produced by locking [`RwLock`] as a writer.
|
||||
///
|
||||
/// This is just a wrapper around a [`parking_lot::RwLockWriteGuard`].
|
||||
pub struct RwLockWriteGuard<'a, T>(parking_lot::RwLockWriteGuard<'a, T>);
|
||||
|
||||
impl<T> RwLock<T> {
|
||||
pub fn new(_rank: super::rank::LockRank, value: T) -> RwLock<T> {
|
||||
RwLock(parking_lot::RwLock::new(value))
|
||||
}
|
||||
|
||||
pub fn read(&self) -> RwLockReadGuard<T> {
|
||||
RwLockReadGuard(self.0.read())
|
||||
}
|
||||
|
||||
pub fn write(&self) -> RwLockWriteGuard<T> {
|
||||
RwLockWriteGuard(self.0.write())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> RwLockWriteGuard<'a, T> {
|
||||
pub fn downgrade(this: Self) -> RwLockReadGuard<'a, T> {
|
||||
RwLockReadGuard(parking_lot::RwLockWriteGuard::downgrade(this.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: std::fmt::Debug> std::fmt::Debug for RwLock<T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> std::ops::Deref for RwLockReadGuard<'a, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.0.deref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> std::ops::Deref for RwLockWriteGuard<'a, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.0.deref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> std::ops::DerefMut for RwLockWriteGuard<'a, T> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.0.deref_mut()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,8 @@ use crate::{
|
|||
resource_log, validation, Label,
|
||||
};
|
||||
use arrayvec::ArrayVec;
|
||||
use std::{borrow::Cow, error::Error, fmt, marker::PhantomData, num::NonZeroU32, sync::Arc};
|
||||
use naga::error::ShaderError;
|
||||
use std::{borrow::Cow, marker::PhantomData, num::NonZeroU32, sync::Arc};
|
||||
use thiserror::Error;
|
||||
|
||||
/// Information about buffer bindings, which
|
||||
|
@ -107,79 +108,8 @@ impl<A: HalApi> ShaderModule<A> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ShaderError<E> {
|
||||
pub source: String,
|
||||
pub label: Option<String>,
|
||||
pub inner: Box<E>,
|
||||
}
|
||||
#[cfg(feature = "wgsl")]
|
||||
impl fmt::Display for ShaderError<naga::front::wgsl::ParseError> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let label = self.label.as_deref().unwrap_or_default();
|
||||
let string = self.inner.emit_to_string(&self.source);
|
||||
write!(f, "\nShader '{label}' parsing {string}")
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "glsl")]
|
||||
impl fmt::Display for ShaderError<naga::front::glsl::ParseError> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let label = self.label.as_deref().unwrap_or_default();
|
||||
let string = self.inner.emit_to_string(&self.source);
|
||||
write!(f, "\nShader '{label}' parsing {string}")
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "spirv")]
|
||||
impl fmt::Display for ShaderError<naga::front::spv::Error> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let label = self.label.as_deref().unwrap_or_default();
|
||||
let string = self.inner.emit_to_string(&self.source);
|
||||
write!(f, "\nShader '{label}' parsing {string}")
|
||||
}
|
||||
}
|
||||
impl fmt::Display for ShaderError<naga::WithSpan<naga::valid::ValidationError>> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use codespan_reporting::{
|
||||
diagnostic::{Diagnostic, Label},
|
||||
files::SimpleFile,
|
||||
term,
|
||||
};
|
||||
|
||||
let label = self.label.as_deref().unwrap_or_default();
|
||||
let files = SimpleFile::new(label, &self.source);
|
||||
let config = term::Config::default();
|
||||
let mut writer = term::termcolor::NoColor::new(Vec::new());
|
||||
|
||||
let diagnostic = Diagnostic::error().with_labels(
|
||||
self.inner
|
||||
.spans()
|
||||
.map(|&(span, ref desc)| {
|
||||
Label::primary((), span.to_range().unwrap()).with_message(desc.to_owned())
|
||||
})
|
||||
.collect(),
|
||||
);
|
||||
|
||||
term::emit(&mut writer, &config, &files, &diagnostic).expect("cannot write error");
|
||||
|
||||
write!(
|
||||
f,
|
||||
"\nShader validation {}",
|
||||
String::from_utf8_lossy(&writer.into_inner())
|
||||
)
|
||||
}
|
||||
}
|
||||
impl<E> Error for ShaderError<E>
|
||||
where
|
||||
ShaderError<E>: fmt::Display,
|
||||
E: Error + 'static,
|
||||
{
|
||||
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
Some(&self.inner)
|
||||
}
|
||||
}
|
||||
|
||||
//Note: `Clone` would require `WithSpan: Clone`.
|
||||
#[derive(Debug, Error)]
|
||||
#[derive(Clone, Debug, Error)]
|
||||
#[non_exhaustive]
|
||||
pub enum CreateShaderModuleError {
|
||||
#[cfg(feature = "wgsl")]
|
||||
|
@ -187,7 +117,7 @@ pub enum CreateShaderModuleError {
|
|||
Parsing(#[from] ShaderError<naga::front::wgsl::ParseError>),
|
||||
#[cfg(feature = "glsl")]
|
||||
#[error(transparent)]
|
||||
ParsingGlsl(#[from] ShaderError<naga::front::glsl::ParseError>),
|
||||
ParsingGlsl(#[from] ShaderError<naga::front::glsl::ParseErrors>),
|
||||
#[cfg(feature = "spirv")]
|
||||
#[error(transparent)]
|
||||
ParsingSpirV(#[from] ShaderError<naga::front::spv::Error>),
|
||||
|
@ -209,17 +139,6 @@ pub enum CreateShaderModuleError {
|
|||
},
|
||||
}
|
||||
|
||||
impl CreateShaderModuleError {
|
||||
pub fn location(&self, source: &str) -> Option<naga::SourceLocation> {
|
||||
match *self {
|
||||
#[cfg(feature = "wgsl")]
|
||||
CreateShaderModuleError::Parsing(ref err) => err.inner.location(source),
|
||||
CreateShaderModuleError::Validation(ref err) => err.inner.location(source),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes a programmable pipeline stage.
|
||||
#[derive(Clone, Debug)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
|
|
|
@ -21,14 +21,13 @@ use crate::{
|
|||
hal_api::HalApi,
|
||||
hal_label, id,
|
||||
init_tracker::TextureInitTracker,
|
||||
lock::{rank, Mutex},
|
||||
lock::{rank, Mutex, RwLock},
|
||||
resource::{self, ResourceInfo},
|
||||
snatch::Snatchable,
|
||||
track,
|
||||
};
|
||||
|
||||
use hal::{Queue as _, Surface as _};
|
||||
use parking_lot::RwLock;
|
||||
use thiserror::Error;
|
||||
use wgt::SurfaceStatus as Status;
|
||||
|
||||
|
@ -216,7 +215,10 @@ impl Global {
|
|||
desc: texture_desc,
|
||||
hal_usage,
|
||||
format_features,
|
||||
initialization_status: RwLock::new(TextureInitTracker::new(1, 1)),
|
||||
initialization_status: RwLock::new(
|
||||
rank::TEXTURE_INITIALIZATION_STATUS,
|
||||
TextureInitTracker::new(1, 1),
|
||||
),
|
||||
full_range: track::TextureSelector {
|
||||
layers: 0..1,
|
||||
mips: 0..1,
|
||||
|
@ -225,9 +227,12 @@ impl Global {
|
|||
"<Surface Texture>",
|
||||
Some(device.tracker_indices.textures.clone()),
|
||||
),
|
||||
clear_mode: RwLock::new(resource::TextureClearMode::Surface {
|
||||
clear_view: Some(clear_view),
|
||||
}),
|
||||
clear_mode: RwLock::new(
|
||||
rank::TEXTURE_CLEAR_MODE,
|
||||
resource::TextureClearMode::Surface {
|
||||
clear_view: Some(clear_view),
|
||||
},
|
||||
),
|
||||
views: Mutex::new(rank::TEXTURE_VIEWS, Vec::new()),
|
||||
bind_groups: Mutex::new(rank::TEXTURE_BIND_GROUPS, Vec::new()),
|
||||
};
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
use wgt::Backend;
|
||||
|
||||
use crate::{
|
||||
id::Id,
|
||||
identity::IdentityManager,
|
||||
lock::{rank, RwLock, RwLockReadGuard, RwLockWriteGuard},
|
||||
resource::Resource,
|
||||
storage::{Element, InvalidId, Storage},
|
||||
};
|
||||
|
@ -48,7 +48,7 @@ impl<T: Resource> Registry<T> {
|
|||
pub(crate) fn new(backend: Backend) -> Self {
|
||||
Self {
|
||||
identity: Arc::new(IdentityManager::new()),
|
||||
storage: RwLock::new(Storage::new()),
|
||||
storage: RwLock::new(rank::REGISTRY_STORAGE, Storage::new()),
|
||||
backend,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ use crate::{
|
|||
TextureViewId,
|
||||
},
|
||||
init_tracker::{BufferInitTracker, TextureInitTracker},
|
||||
lock::Mutex,
|
||||
lock::{Mutex, RwLock},
|
||||
resource, resource_log,
|
||||
snatch::{ExclusiveSnatchGuard, SnatchGuard, Snatchable},
|
||||
track::{SharedTrackerIndexAllocator, TextureSelector, TrackerIndex},
|
||||
|
@ -22,7 +22,6 @@ use crate::{
|
|||
};
|
||||
|
||||
use hal::CommandEncoder;
|
||||
use parking_lot::RwLock;
|
||||
use smallvec::SmallVec;
|
||||
use thiserror::Error;
|
||||
use wgt::WasmNotSendSync;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#![allow(unused)]
|
||||
|
||||
use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
use crate::lock::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
use std::{
|
||||
backtrace::Backtrace,
|
||||
cell::{Cell, RefCell, UnsafeCell},
|
||||
|
@ -8,6 +8,8 @@ use std::{
|
|||
thread,
|
||||
};
|
||||
|
||||
use crate::lock::rank;
|
||||
|
||||
/// A guard that provides read access to snatchable data.
|
||||
pub struct SnatchGuard<'a>(RwLockReadGuard<'a, ()>);
|
||||
/// A guard that allows snatching the snatchable data.
|
||||
|
@ -128,9 +130,9 @@ impl SnatchLock {
|
|||
/// right SnatchLock (the one associated to the same device). This method is unsafe
|
||||
/// to force force sers to think twice about creating a SnatchLock. The only place this
|
||||
/// method should be called is when creating the device.
|
||||
pub unsafe fn new() -> Self {
|
||||
pub unsafe fn new(rank: rank::LockRank) -> Self {
|
||||
SnatchLock {
|
||||
lock: RwLock::new(()),
|
||||
lock: RwLock::new(rank, ()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -105,12 +105,11 @@ use crate::{
|
|||
binding_model, command, conv,
|
||||
hal_api::HalApi,
|
||||
id,
|
||||
lock::{rank, Mutex},
|
||||
lock::{rank, Mutex, RwLock},
|
||||
pipeline, resource,
|
||||
snatch::SnatchGuard,
|
||||
};
|
||||
|
||||
use parking_lot::RwLock;
|
||||
use std::{fmt, ops, sync::Arc};
|
||||
use thiserror::Error;
|
||||
|
||||
|
@ -489,11 +488,26 @@ impl<A: HalApi> RenderBundleScope<A> {
|
|||
/// Create the render bundle scope and pull the maximum IDs from the hubs.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
buffers: RwLock::new(BufferUsageScope::default()),
|
||||
textures: RwLock::new(TextureUsageScope::default()),
|
||||
bind_groups: RwLock::new(StatelessTracker::new()),
|
||||
render_pipelines: RwLock::new(StatelessTracker::new()),
|
||||
query_sets: RwLock::new(StatelessTracker::new()),
|
||||
buffers: RwLock::new(
|
||||
rank::RENDER_BUNDLE_SCOPE_BUFFERS,
|
||||
BufferUsageScope::default(),
|
||||
),
|
||||
textures: RwLock::new(
|
||||
rank::RENDER_BUNDLE_SCOPE_TEXTURES,
|
||||
TextureUsageScope::default(),
|
||||
),
|
||||
bind_groups: RwLock::new(
|
||||
rank::RENDER_BUNDLE_SCOPE_BIND_GROUPS,
|
||||
StatelessTracker::new(),
|
||||
),
|
||||
render_pipelines: RwLock::new(
|
||||
rank::RENDER_BUNDLE_SCOPE_RENDER_PIPELINES,
|
||||
StatelessTracker::new(),
|
||||
),
|
||||
query_sets: RwLock::new(
|
||||
rank::RENDER_BUNDLE_SCOPE_QUERY_SETS,
|
||||
StatelessTracker::new(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -13,7 +13,7 @@
|
|||
edition = "2021"
|
||||
rust-version = "1.74"
|
||||
name = "wgpu-hal"
|
||||
version = "0.19.3"
|
||||
version = "0.20.0"
|
||||
authors = ["gfx-rs developers"]
|
||||
description = "WebGPU hardware abstraction layer"
|
||||
homepage = "https://wgpu.rs/"
|
||||
|
@ -63,7 +63,7 @@ version = "0.13.1"
|
|||
optional = true
|
||||
|
||||
[dependencies.naga]
|
||||
version = "0.19.2"
|
||||
version = "0.20.0"
|
||||
path = "../naga"
|
||||
|
||||
[dependencies.profiling]
|
||||
|
@ -71,17 +71,17 @@ version = "1"
|
|||
default-features = false
|
||||
|
||||
[dependencies.wgt]
|
||||
version = "0.19.2"
|
||||
version = "0.20.0"
|
||||
path = "../wgpu-types"
|
||||
package = "wgpu-types"
|
||||
|
||||
[dev-dependencies]
|
||||
cfg-if = "1"
|
||||
env_logger = "0.11"
|
||||
glam = "0.25.0"
|
||||
glam = "0.27.0"
|
||||
|
||||
[dev-dependencies.naga]
|
||||
version = "0.19.2"
|
||||
version = "0.20.0"
|
||||
path = "../naga"
|
||||
features = ["wgsl-in"]
|
||||
|
||||
|
@ -162,9 +162,7 @@ version = "0.1"
|
|||
optional = true
|
||||
|
||||
[target."cfg(any(target_os=\"macos\", target_os=\"ios\"))".dependencies.metal]
|
||||
version = "0.27.0"
|
||||
git = "https://github.com/gfx-rs/metal-rs"
|
||||
rev = "ff8fd3d6dc7792852f8a015458d7e6d42d7fb352"
|
||||
version = "0.28.0"
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.ash]
|
||||
version = "0.37.3"
|
||||
|
@ -226,7 +224,7 @@ version = "0.5"
|
|||
optional = true
|
||||
|
||||
[target."cfg(windows)".dependencies.d3d12]
|
||||
version = "0.19.0"
|
||||
version = "0.20.0"
|
||||
path = "../d3d12/"
|
||||
features = ["libloading"]
|
||||
optional = true
|
||||
|
|
|
@ -845,6 +845,7 @@ fn main() {
|
|||
}
|
||||
}
|
||||
ex.render();
|
||||
window.request_redraw();
|
||||
}
|
||||
_ => {
|
||||
example.as_mut().unwrap().update(event);
|
||||
|
|
|
@ -224,7 +224,7 @@ pub fn map_polygon_mode(mode: wgt::PolygonMode) -> d3d12_ty::D3D12_FILL_MODE {
|
|||
}
|
||||
|
||||
/// D3D12 doesn't support passing factors ending in `_COLOR` for alpha blending
|
||||
/// (see https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ns-d3d12-d3d12_render_target_blend_desc).
|
||||
/// (see <https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ns-d3d12-d3d12_render_target_blend_desc>).
|
||||
/// Therefore this function takes an additional `is_alpha` argument
|
||||
/// which if set will return an equivalent `_ALPHA` factor.
|
||||
fn map_blend_factor(factor: wgt::BlendFactor, is_alpha: bool) -> d3d12_ty::D3D12_BLEND {
|
||||
|
|
|
@ -440,7 +440,7 @@ impl Texture {
|
|||
}
|
||||
}
|
||||
|
||||
/// see https://learn.microsoft.com/en-us/windows/win32/direct3d12/subresources#plane-slice
|
||||
/// see <https://learn.microsoft.com/en-us/windows/win32/direct3d12/subresources#plane-slice>
|
||||
fn calc_subresource(&self, mip_level: u32, array_layer: u32, plane: u32) -> u32 {
|
||||
mip_level + (array_layer + plane * self.array_layer_count()) * self.mip_level_count
|
||||
}
|
||||
|
|
|
@ -549,22 +549,28 @@ impl Inner {
|
|||
let mut khr_context_flags = 0;
|
||||
let supports_khr_context = display_extensions.contains("EGL_KHR_create_context");
|
||||
|
||||
//TODO: make it so `Device` == EGL Context
|
||||
let mut context_attributes = vec![
|
||||
khronos_egl::CONTEXT_MAJOR_VERSION,
|
||||
3, // Request GLES 3.0 or higher
|
||||
];
|
||||
|
||||
if force_gles_minor_version != wgt::Gles3MinorVersion::Automatic {
|
||||
let mut context_attributes = vec![];
|
||||
if supports_opengl {
|
||||
context_attributes.push(khronos_egl::CONTEXT_MAJOR_VERSION);
|
||||
context_attributes.push(3);
|
||||
context_attributes.push(khronos_egl::CONTEXT_MINOR_VERSION);
|
||||
context_attributes.push(match force_gles_minor_version {
|
||||
wgt::Gles3MinorVersion::Version0 => 0,
|
||||
wgt::Gles3MinorVersion::Version1 => 1,
|
||||
wgt::Gles3MinorVersion::Version2 => 2,
|
||||
_ => unreachable!(),
|
||||
});
|
||||
context_attributes.push(3);
|
||||
if force_gles_minor_version != wgt::Gles3MinorVersion::Automatic {
|
||||
log::warn!("Ignoring specified GLES minor version as OpenGL is used");
|
||||
}
|
||||
} else {
|
||||
context_attributes.push(khronos_egl::CONTEXT_MAJOR_VERSION);
|
||||
context_attributes.push(3); // Request GLES 3.0 or higher
|
||||
if force_gles_minor_version != wgt::Gles3MinorVersion::Automatic {
|
||||
context_attributes.push(khronos_egl::CONTEXT_MINOR_VERSION);
|
||||
context_attributes.push(match force_gles_minor_version {
|
||||
wgt::Gles3MinorVersion::Automatic => unreachable!(),
|
||||
wgt::Gles3MinorVersion::Version0 => 0,
|
||||
wgt::Gles3MinorVersion::Version1 => 1,
|
||||
wgt::Gles3MinorVersion::Version2 => 2,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if flags.contains(wgt::InstanceFlags::DEBUG) {
|
||||
if version >= (1, 5) {
|
||||
log::debug!("\tEGL context: +debug");
|
||||
|
@ -594,8 +600,6 @@ impl Inner {
|
|||
// because it's for desktop GL only, not GLES.
|
||||
log::warn!("\tEGL context: -robust access");
|
||||
}
|
||||
|
||||
//TODO do we need `khronos_egl::CONTEXT_OPENGL_NOTIFICATION_STRATEGY_EXT`?
|
||||
}
|
||||
if khr_context_flags != 0 {
|
||||
context_attributes.push(EGL_CONTEXT_FLAGS_KHR);
|
||||
|
@ -1130,6 +1134,13 @@ impl Surface {
|
|||
|
||||
unsafe { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, None) };
|
||||
unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(sc.framebuffer)) };
|
||||
|
||||
if !matches!(self.srgb_kind, SrgbFrameBufferKind::None) {
|
||||
// Disable sRGB conversions for `glBlitFramebuffer` as behavior does diverge between
|
||||
// drivers and formats otherwise and we want to ensure no sRGB conversions happen.
|
||||
unsafe { gl.disable(glow::FRAMEBUFFER_SRGB) };
|
||||
}
|
||||
|
||||
// Note the Y-flipping here. GL's presentation is not flipped,
|
||||
// but main rendering is. Therefore, we Y-flip the output positions
|
||||
// in the shader, and also this blit.
|
||||
|
@ -1147,6 +1158,11 @@ impl Surface {
|
|||
glow::NEAREST,
|
||||
)
|
||||
};
|
||||
|
||||
if !matches!(self.srgb_kind, SrgbFrameBufferKind::None) {
|
||||
unsafe { gl.enable(glow::FRAMEBUFFER_SRGB) };
|
||||
}
|
||||
|
||||
unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None) };
|
||||
|
||||
self.egl
|
||||
|
|
|
@ -406,6 +406,24 @@ pub trait Api: Clone + fmt::Debug + Sized {
|
|||
type TextureView: fmt::Debug + WasmNotSendSync;
|
||||
type Sampler: fmt::Debug + WasmNotSendSync;
|
||||
type QuerySet: fmt::Debug + WasmNotSendSync;
|
||||
|
||||
/// A value you can block on to wait for something to finish.
|
||||
///
|
||||
/// A `Fence` holds a monotonically increasing [`FenceValue`]. You can call
|
||||
/// [`Device::wait`] to block until a fence reaches or passes a value you
|
||||
/// choose. [`Queue::submit`] can take a `Fence` and a [`FenceValue`] to
|
||||
/// store in it when the submitted work is complete.
|
||||
///
|
||||
/// Attempting to set a fence to a value less than its current value has no
|
||||
/// effect.
|
||||
///
|
||||
/// Waiting on a fence returns as soon as the fence reaches *or passes* the
|
||||
/// requested value. This implies that, in order to reliably determine when
|
||||
/// an operation has completed, operations must finish in order of
|
||||
/// increasing fence values: if a higher-valued operation were to finish
|
||||
/// before a lower-valued operation, then waiting for the fence to reach the
|
||||
/// lower value could return before the lower-valued operation has actually
|
||||
/// finished.
|
||||
type Fence: fmt::Debug + WasmNotSendSync;
|
||||
|
||||
type BindGroupLayout: fmt::Debug + WasmNotSendSync;
|
||||
|
@ -605,7 +623,25 @@ pub trait Device: WasmNotSendSync {
|
|||
&self,
|
||||
fence: &<Self::A as Api>::Fence,
|
||||
) -> Result<FenceValue, DeviceError>;
|
||||
/// Calling wait with a lower value than the current fence value will immediately return.
|
||||
|
||||
/// Wait for `fence` to reach `value`.
|
||||
///
|
||||
/// Operations like [`Queue::submit`] can accept a [`Fence`] and a
|
||||
/// [`FenceValue`] to store in it, so you can use this `wait` function
|
||||
/// to wait for a given queue submission to finish execution.
|
||||
///
|
||||
/// The `value` argument must be a value that some actual operation you have
|
||||
/// already presented to the device is going to store in `fence`. You cannot
|
||||
/// wait for values yet to be submitted. (This restriction accommodates
|
||||
/// implementations like the `vulkan` backend's [`FencePool`] that must
|
||||
/// allocate a distinct synchronization object for each fence value one is
|
||||
/// able to wait for.)
|
||||
///
|
||||
/// Calling `wait` with a lower [`FenceValue`] than `fence`'s current value
|
||||
/// returns immediately.
|
||||
///
|
||||
/// [`Fence`]: Api::Fence
|
||||
/// [`FencePool`]: vulkan/enum.Fence.html#variant.FencePool
|
||||
unsafe fn wait(
|
||||
&self,
|
||||
fence: &<Self::A as Api>::Fence,
|
||||
|
@ -637,7 +673,30 @@ pub trait Device: WasmNotSendSync {
|
|||
pub trait Queue: WasmNotSendSync {
|
||||
type A: Api;
|
||||
|
||||
/// Submits the command buffers for execution on GPU.
|
||||
/// Submit `command_buffers` for execution on GPU.
|
||||
///
|
||||
/// If `signal_fence` is `Some(fence, value)`, update `fence` to `value`
|
||||
/// when the operation is complete. See [`Fence`] for details.
|
||||
///
|
||||
/// If two calls to `submit` on a single `Queue` occur in a particular order
|
||||
/// (that is, they happen on the same thread, or on two threads that have
|
||||
/// synchronized to establish an ordering), then the first submission's
|
||||
/// commands all complete execution before any of the second submission's
|
||||
/// commands begin. All results produced by one submission are visible to
|
||||
/// the next.
|
||||
///
|
||||
/// Within a submission, command buffers execute in the order in which they
|
||||
/// appear in `command_buffers`. All results produced by one buffer are
|
||||
/// visible to the next.
|
||||
///
|
||||
/// If two calls to `submit` on a single `Queue` from different threads are
|
||||
/// not synchronized to occur in a particular order, they must pass distinct
|
||||
/// [`Fence`]s. As explained in the [`Fence`] documentation, waiting for
|
||||
/// operations to complete is only trustworthy when operations finish in
|
||||
/// order of increasing fence value, but submissions from different threads
|
||||
/// cannot determine how to order the fence values if the submissions
|
||||
/// themselves are unordered. If each thread uses a separate [`Fence`], this
|
||||
/// problem does not arise.
|
||||
///
|
||||
/// Valid usage:
|
||||
///
|
||||
|
@ -652,6 +711,7 @@ pub trait Queue: WasmNotSendSync {
|
|||
/// - All of the [`SurfaceTexture`][st]s that the command buffers
|
||||
/// write to appear in the `surface_textures` argument.
|
||||
///
|
||||
/// [`Fence`]: Api::Fence
|
||||
/// [cb]: Api::CommandBuffer
|
||||
/// [ce]: Api::CommandEncoder
|
||||
/// [st]: Api::SurfaceTexture
|
||||
|
|
|
@ -817,6 +817,10 @@ impl super::PrivateCapabilities {
|
|||
&& (device.supports_family(MTLGPUFamily::Metal3)
|
||||
|| device.supports_family(MTLGPUFamily::Mac2)
|
||||
|| device.supports_family(MTLGPUFamily::Apple7)),
|
||||
// https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf#page=5
|
||||
int64: family_check
|
||||
&& (device.supports_family(MTLGPUFamily::Apple3)
|
||||
|| device.supports_family(MTLGPUFamily::Metal3)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -890,7 +894,7 @@ impl super::PrivateCapabilities {
|
|||
}
|
||||
features.set(
|
||||
F::SHADER_INT64,
|
||||
self.msl_version >= MTLLanguageVersion::V2_3,
|
||||
self.int64 && self.msl_version >= MTLLanguageVersion::V2_3,
|
||||
);
|
||||
|
||||
features.set(
|
||||
|
|
|
@ -270,6 +270,7 @@ struct PrivateCapabilities {
|
|||
has_unified_memory: Option<bool>,
|
||||
timestamp_query_support: TimestampQuerySupport,
|
||||
supports_simd_scoped_operations: bool,
|
||||
int64: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -650,7 +651,7 @@ struct BufferResource {
|
|||
/// Buffers with the [`wgt::BufferBindingType::Storage`] binding type can
|
||||
/// hold WGSL runtime-sized arrays. When one does, we must pass its size to
|
||||
/// shader entry points to implement bounds checks and WGSL's `arrayLength`
|
||||
/// function. See [`device::CompiledShader::sized_bindings`] for details.
|
||||
/// function. See `device::CompiledShader::sized_bindings` for details.
|
||||
///
|
||||
/// [`Storage`]: wgt::BufferBindingType::Storage
|
||||
binding_size: Option<wgt::BufferSize>,
|
||||
|
@ -681,12 +682,12 @@ struct PipelineStageInfo {
|
|||
|
||||
/// The buffer argument table index at which we pass runtime-sized arrays' buffer sizes.
|
||||
///
|
||||
/// See [`device::CompiledShader::sized_bindings`] for more details.
|
||||
/// See `device::CompiledShader::sized_bindings` for more details.
|
||||
sizes_slot: Option<naga::back::msl::Slot>,
|
||||
|
||||
/// Bindings of all WGSL `storage` globals that contain runtime-sized arrays.
|
||||
///
|
||||
/// See [`device::CompiledShader::sized_bindings`] for more details.
|
||||
/// See `device::CompiledShader::sized_bindings` for more details.
|
||||
sized_bindings: Vec<naga::ResourceBinding>,
|
||||
}
|
||||
|
||||
|
@ -802,7 +803,7 @@ struct CommandState {
|
|||
///
|
||||
/// Specifically:
|
||||
///
|
||||
/// - The keys are ['ResourceBinding`] values (that is, the WGSL `@group`
|
||||
/// - The keys are [`ResourceBinding`] values (that is, the WGSL `@group`
|
||||
/// and `@binding` attributes) for `var<storage>` global variables in the
|
||||
/// current module that contain runtime-sized arrays.
|
||||
///
|
||||
|
@ -814,7 +815,7 @@ struct CommandState {
|
|||
/// of the buffers listed in [`stage_infos.S.sized_bindings`], which we must
|
||||
/// pass to the entry point.
|
||||
///
|
||||
/// See [`device::CompiledShader::sized_bindings`] for more details.
|
||||
/// See `device::CompiledShader::sized_bindings` for more details.
|
||||
///
|
||||
/// [`ResourceBinding`]: naga::ResourceBinding
|
||||
storage_buffer_length_map: rustc_hash::FxHashMap<naga::ResourceBinding, wgt::BufferSize>,
|
||||
|
|
|
@ -35,6 +35,8 @@ fn indexing_features() -> wgt::Features {
|
|||
/// [`PhysicalDeviceFeatures::from_extensions_and_requested_features`]
|
||||
/// constructs an value of this type indicating which Vulkan features to
|
||||
/// enable, based on the `wgpu_types::Features` requested.
|
||||
///
|
||||
/// [`Instance::expose_adapter`]: super::Instance::expose_adapter
|
||||
#[derive(Debug, Default)]
|
||||
pub struct PhysicalDeviceFeatures {
|
||||
/// Basic Vulkan 1.0 features.
|
||||
|
@ -86,6 +88,9 @@ pub struct PhysicalDeviceFeatures {
|
|||
///
|
||||
/// However, we do populate this when creating a device if
|
||||
/// [`Features::RAY_TRACING_ACCELERATION_STRUCTURE`] is requested.
|
||||
///
|
||||
/// [`Instance::expose_adapter`]: super::Instance::expose_adapter
|
||||
/// [`Features::RAY_TRACING_ACCELERATION_STRUCTURE`]: wgt::Features::RAY_TRACING_ACCELERATION_STRUCTURE
|
||||
buffer_device_address: Option<vk::PhysicalDeviceBufferDeviceAddressFeaturesKHR>,
|
||||
|
||||
/// Features provided by `VK_KHR_ray_query`,
|
||||
|
@ -95,6 +100,8 @@ pub struct PhysicalDeviceFeatures {
|
|||
/// this from `vkGetPhysicalDeviceFeatures2`.
|
||||
///
|
||||
/// However, we do populate this when creating a device if ray tracing is requested.
|
||||
///
|
||||
/// [`Instance::expose_adapter`]: super::Instance::expose_adapter
|
||||
ray_query: Option<vk::PhysicalDeviceRayQueryFeaturesKHR>,
|
||||
|
||||
/// Features provided by `VK_KHR_zero_initialize_workgroup_memory`, promoted
|
||||
|
@ -181,6 +188,7 @@ impl PhysicalDeviceFeatures {
|
|||
/// [`Features`]: wgt::Features
|
||||
/// [`DownlevelFlags`]: wgt::DownlevelFlags
|
||||
/// [`PrivateCapabilities`]: super::PrivateCapabilities
|
||||
/// [`add_to_device_create_builder`]: PhysicalDeviceFeatures::add_to_device_create_builder
|
||||
/// [`DeviceCreateInfoBuilder`]: vk::DeviceCreateInfoBuilder
|
||||
/// [`Adapter::required_device_extensions`]: super::Adapter::required_device_extensions
|
||||
fn from_extensions_and_requested_features(
|
||||
|
@ -459,6 +467,9 @@ impl PhysicalDeviceFeatures {
|
|||
/// Given `self`, together with the instance and physical device it was
|
||||
/// built from, and a `caps` also built from those, determine which wgpu
|
||||
/// features and downlevel flags the device can support.
|
||||
///
|
||||
/// [`Features`]: wgt::Features
|
||||
/// [`DownlevelFlags`]: wgt::DownlevelFlags
|
||||
fn to_wgpu(
|
||||
&self,
|
||||
instance: &ash::Instance,
|
||||
|
|
|
@ -559,9 +559,47 @@ pub struct QuerySet {
|
|||
raw: vk::QueryPool,
|
||||
}
|
||||
|
||||
/// The [`Api::Fence`] type for [`vulkan::Api`].
|
||||
///
|
||||
/// This is an `enum` because there are two possible implementations of
|
||||
/// `wgpu-hal` fences on Vulkan: Vulkan fences, which work on any version of
|
||||
/// Vulkan, and Vulkan timeline semaphores, which are easier and cheaper but
|
||||
/// require non-1.0 features.
|
||||
///
|
||||
/// [`Device::create_fence`] returns a [`TimelineSemaphore`] if
|
||||
/// [`VK_KHR_timeline_semaphore`] is available and enabled, and a [`FencePool`]
|
||||
/// otherwise.
|
||||
///
|
||||
/// [`Api::Fence`]: crate::Api::Fence
|
||||
/// [`vulkan::Api`]: Api
|
||||
/// [`Device::create_fence`]: crate::Device::create_fence
|
||||
/// [`TimelineSemaphore`]: Fence::TimelineSemaphore
|
||||
/// [`VK_KHR_timeline_semaphore`]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VK_KHR_timeline_semaphore
|
||||
/// [`FencePool`]: Fence::FencePool
|
||||
#[derive(Debug)]
|
||||
pub enum Fence {
|
||||
/// A Vulkan [timeline semaphore].
|
||||
///
|
||||
/// These are simpler to use than Vulkan fences, since timeline semaphores
|
||||
/// work exactly the way [`wpgu_hal::Api::Fence`] is specified to work.
|
||||
///
|
||||
/// [timeline semaphore]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#synchronization-semaphores
|
||||
/// [`wpgu_hal::Api::Fence`]: crate::Api::Fence
|
||||
TimelineSemaphore(vk::Semaphore),
|
||||
|
||||
/// A collection of Vulkan [fence]s, each associated with a [`FenceValue`].
|
||||
///
|
||||
/// The effective [`FenceValue`] of this variant is the greater of
|
||||
/// `last_completed` and the maximum value associated with a signalled fence
|
||||
/// in `active`.
|
||||
///
|
||||
/// Fences are available in all versions of Vulkan, but since they only have
|
||||
/// two states, "signaled" and "unsignaled", we need to use a separate fence
|
||||
/// for each queue submission we might want to wait for, and remember which
|
||||
/// [`FenceValue`] each one represents.
|
||||
///
|
||||
/// [fence]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#synchronization-fences
|
||||
/// [`FenceValue`]: crate::FenceValue
|
||||
FencePool {
|
||||
last_completed: crate::FenceValue,
|
||||
/// The pending fence values have to be ascending.
|
||||
|
@ -571,21 +609,32 @@ pub enum Fence {
|
|||
}
|
||||
|
||||
impl Fence {
|
||||
/// Return the highest [`FenceValue`] among the signalled fences in `active`.
|
||||
///
|
||||
/// As an optimization, assume that we already know that the fence has
|
||||
/// reached `last_completed`, and don't bother checking fences whose values
|
||||
/// are less than that: those fences remain in the `active` array only
|
||||
/// because we haven't called `maintain` yet to clean them up.
|
||||
///
|
||||
/// [`FenceValue`]: crate::FenceValue
|
||||
fn check_active(
|
||||
device: &ash::Device,
|
||||
mut max_value: crate::FenceValue,
|
||||
mut last_completed: crate::FenceValue,
|
||||
active: &[(crate::FenceValue, vk::Fence)],
|
||||
) -> Result<crate::FenceValue, crate::DeviceError> {
|
||||
for &(value, raw) in active.iter() {
|
||||
unsafe {
|
||||
if value > max_value && device.get_fence_status(raw)? {
|
||||
max_value = value;
|
||||
if value > last_completed && device.get_fence_status(raw)? {
|
||||
last_completed = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(max_value)
|
||||
Ok(last_completed)
|
||||
}
|
||||
|
||||
/// Return the highest signalled [`FenceValue`] for `self`.
|
||||
///
|
||||
/// [`FenceValue`]: crate::FenceValue
|
||||
fn get_latest(
|
||||
&self,
|
||||
device: &ash::Device,
|
||||
|
@ -606,6 +655,18 @@ impl Fence {
|
|||
}
|
||||
}
|
||||
|
||||
/// Trim the internal state of this [`Fence`].
|
||||
///
|
||||
/// This function has no externally visible effect, but you should call it
|
||||
/// periodically to keep this fence's resource consumption under control.
|
||||
///
|
||||
/// For fences using the [`FencePool`] implementation, this function
|
||||
/// recycles fences that have been signaled. If you don't call this,
|
||||
/// [`Queue::submit`] will just keep allocating a new Vulkan fence every
|
||||
/// time it's called.
|
||||
///
|
||||
/// [`FencePool`]: Fence::FencePool
|
||||
/// [`Queue::submit`]: crate::Queue::submit
|
||||
fn maintain(&mut self, device: &ash::Device) -> Result<(), crate::DeviceError> {
|
||||
match *self {
|
||||
Self::TimelineSemaphore(_) => {}
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"9c95789feb6b72f758d225f0931bfa1c4cbe768cc8292a78324d89e58b9803c9","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","src/assertions.rs":"3fe98027aa73970c8ab7874a3e13dbfd6faa87df2081beb5c83aeec4c60f372f","src/lib.rs":"1426b5ed459028bd41a1e0d5e89e681f2bc3c34c60e68ba07cf16dc90054aa57","src/math.rs":"4d03039736dd6926feb139bc68734cb59df34ede310427bbf059e5c925e0af3b"},"package":null}
|
||||
{"files":{"Cargo.toml":"d8f88446d6c1740116442320eca91e06ce9a2f4713179195c1be44e8ab1fc42d","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","src/assertions.rs":"3fe98027aa73970c8ab7874a3e13dbfd6faa87df2081beb5c83aeec4c60f372f","src/lib.rs":"0e844b150863abdecee2a2cb44245330f22ab48d8ab14f15f06c13f96213bdf3","src/math.rs":"4d03039736dd6926feb139bc68734cb59df34ede310427bbf059e5c925e0af3b"},"package":null}
|
|
@ -13,7 +13,7 @@
|
|||
edition = "2021"
|
||||
rust-version = "1.74"
|
||||
name = "wgpu-types"
|
||||
version = "0.19.2"
|
||||
version = "0.20.0"
|
||||
authors = ["gfx-rs developers"]
|
||||
description = "WebGPU types"
|
||||
homepage = "https://wgpu.rs/"
|
||||
|
|
|
@ -1143,7 +1143,7 @@ pub struct Limits {
|
|||
/// pipeline output data, across all color attachments.
|
||||
pub max_color_attachment_bytes_per_sample: u32,
|
||||
/// Maximum number of bytes used for workgroup memory in a compute entry point. Defaults to
|
||||
/// 16352. Higher is "better".
|
||||
/// 16384. Higher is "better".
|
||||
pub max_compute_workgroup_storage_size: u32,
|
||||
/// Maximum value of the product of the `workgroup_size` dimensions for a compute entry-point.
|
||||
/// Defaults to 256. Higher is "better".
|
||||
|
@ -1184,6 +1184,14 @@ pub struct Limits {
|
|||
|
||||
impl Default for Limits {
|
||||
fn default() -> Self {
|
||||
Self::defaults()
|
||||
}
|
||||
}
|
||||
|
||||
impl Limits {
|
||||
// Rust doesn't allow const in trait implementations, so we break this out
|
||||
// to allow reusing these defaults in const contexts like `downlevel_defaults`
|
||||
const fn defaults() -> Self {
|
||||
Self {
|
||||
max_texture_dimension_1d: 8192,
|
||||
max_texture_dimension_2d: 8192,
|
||||
|
@ -1198,10 +1206,10 @@ impl Default for Limits {
|
|||
max_storage_buffers_per_shader_stage: 8,
|
||||
max_storage_textures_per_shader_stage: 4,
|
||||
max_uniform_buffers_per_shader_stage: 12,
|
||||
max_uniform_buffer_binding_size: 64 << 10,
|
||||
max_storage_buffer_binding_size: 128 << 20,
|
||||
max_uniform_buffer_binding_size: 64 << 10, // (64 KiB)
|
||||
max_storage_buffer_binding_size: 128 << 20, // (128 MiB)
|
||||
max_vertex_buffers: 8,
|
||||
max_buffer_size: 256 << 20,
|
||||
max_buffer_size: 256 << 20, // (256 MiB)
|
||||
max_vertex_attributes: 16,
|
||||
max_vertex_buffer_array_stride: 2048,
|
||||
min_uniform_buffer_offset_alignment: 256,
|
||||
|
@ -1221,9 +1229,7 @@ impl Default for Limits {
|
|||
max_non_sampler_bindings: 1_000_000,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Limits {
|
||||
/// These default limits are guaranteed to be compatible with GLES-3.1, and D3D11
|
||||
///
|
||||
/// Those limits are as follows (different from default are marked with *):
|
||||
|
@ -1256,7 +1262,7 @@ impl Limits {
|
|||
/// max_inter_stage_shader_components: 60,
|
||||
/// max_color_attachments: 8,
|
||||
/// max_color_attachment_bytes_per_sample: 32,
|
||||
/// max_compute_workgroup_storage_size: 16352,
|
||||
/// max_compute_workgroup_storage_size: 16352, // *
|
||||
/// max_compute_invocations_per_workgroup: 256,
|
||||
/// max_compute_workgroup_size_x: 256,
|
||||
/// max_compute_workgroup_size_y: 256,
|
||||
|
@ -1271,37 +1277,11 @@ impl Limits {
|
|||
max_texture_dimension_1d: 2048,
|
||||
max_texture_dimension_2d: 2048,
|
||||
max_texture_dimension_3d: 256,
|
||||
max_texture_array_layers: 256,
|
||||
max_bind_groups: 4,
|
||||
max_bindings_per_bind_group: 1000,
|
||||
max_dynamic_uniform_buffers_per_pipeline_layout: 8,
|
||||
max_dynamic_storage_buffers_per_pipeline_layout: 4,
|
||||
max_sampled_textures_per_shader_stage: 16,
|
||||
max_samplers_per_shader_stage: 16,
|
||||
max_storage_buffers_per_shader_stage: 4,
|
||||
max_storage_textures_per_shader_stage: 4,
|
||||
max_uniform_buffers_per_shader_stage: 12,
|
||||
max_uniform_buffer_binding_size: 16 << 10,
|
||||
max_storage_buffer_binding_size: 128 << 20,
|
||||
max_vertex_buffers: 8,
|
||||
max_vertex_attributes: 16,
|
||||
max_vertex_buffer_array_stride: 2048,
|
||||
min_subgroup_size: 0,
|
||||
max_subgroup_size: 0,
|
||||
max_push_constant_size: 0,
|
||||
min_uniform_buffer_offset_alignment: 256,
|
||||
min_storage_buffer_offset_alignment: 256,
|
||||
max_inter_stage_shader_components: 60,
|
||||
max_color_attachments: 8,
|
||||
max_color_attachment_bytes_per_sample: 32,
|
||||
max_uniform_buffer_binding_size: 16 << 10, // (16 KiB)
|
||||
// see: https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf#page=7
|
||||
max_compute_workgroup_storage_size: 16352,
|
||||
max_compute_invocations_per_workgroup: 256,
|
||||
max_compute_workgroup_size_x: 256,
|
||||
max_compute_workgroup_size_y: 256,
|
||||
max_compute_workgroup_size_z: 64,
|
||||
max_compute_workgroups_per_dimension: 65535,
|
||||
max_buffer_size: 256 << 20,
|
||||
max_non_sampler_bindings: 1_000_000,
|
||||
..Self::defaults()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7114,7 +7094,7 @@ pub struct InstanceDescriptor {
|
|||
pub flags: InstanceFlags,
|
||||
/// Which DX12 shader compiler to use.
|
||||
pub dx12_shader_compiler: Dx12Compiler,
|
||||
/// Which OpenGL ES 3 minor version to request.
|
||||
/// Which OpenGL ES 3 minor version to request. Will be ignored if OpenGL is available.
|
||||
pub gles_minor_version: Gles3MinorVersion,
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче