mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 14:52:16 +00:00
Bug 1917102: Update wgpu crates to ec2100052 (2024-09-05). r=supply-chain-reviewers,webgpu-reviewers,nical,ErichDonGubler
Demote some tests to backlog (filed as https://github.com/gfx-rs/wgpu/issues/6232): - webgpu:shader,validation,const_assert,const_assert:constant_expression_assert:* - webgpu:shader,validation,const_assert,const_assert:constant_expression_logical_and_assert:* - webgpu:shader,validation,const_assert,const_assert:constant_expression_logical_or_assert:* Differential Revision: https://phabricator.services.mozilla.com/D221272
This commit is contained in:
parent
7abf66380c
commit
e6535b1d07
@ -25,9 +25,9 @@ git = "https://github.com/franziskuskiefer/cose-rust"
|
||||
rev = "43c22248d136c8b38fe42ea709d08da6355cf04b"
|
||||
replace-with = "vendored-sources"
|
||||
|
||||
[source."git+https://github.com/gfx-rs/wgpu?rev=bbdbafdf8a947b563b46f632a778632b906d9eb4"]
|
||||
[source."git+https://github.com/gfx-rs/wgpu?rev=ec2100052132a047fe0799c084696d6c0ee7629d"]
|
||||
git = "https://github.com/gfx-rs/wgpu"
|
||||
rev = "bbdbafdf8a947b563b46f632a778632b906d9eb4"
|
||||
rev = "ec2100052132a047fe0799c084696d6c0ee7629d"
|
||||
replace-with = "vendored-sources"
|
||||
|
||||
[source."git+https://github.com/hsivonen/any_all_workaround?rev=7fb1b7034c9f172aade21ee1c8554e8d8a48af80"]
|
||||
|
8
Cargo.lock
generated
8
Cargo.lock
generated
@ -4025,7 +4025,7 @@ checksum = "a2983372caf4480544083767bf2d27defafe32af49ab4df3a0b7fc90793a3664"
|
||||
[[package]]
|
||||
name = "naga"
|
||||
version = "22.0.0"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=bbdbafdf8a947b563b46f632a778632b906d9eb4#bbdbafdf8a947b563b46f632a778632b906d9eb4"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=ec2100052132a047fe0799c084696d6c0ee7629d#ec2100052132a047fe0799c084696d6c0ee7629d"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bit-set",
|
||||
@ -6794,7 +6794,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "wgpu-core"
|
||||
version = "22.0.0"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=bbdbafdf8a947b563b46f632a778632b906d9eb4#bbdbafdf8a947b563b46f632a778632b906d9eb4"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=ec2100052132a047fe0799c084696d6c0ee7629d#ec2100052132a047fe0799c084696d6c0ee7629d"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bit-vec",
|
||||
@ -6819,7 +6819,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "wgpu-hal"
|
||||
version = "22.0.0"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=bbdbafdf8a947b563b46f632a778632b906d9eb4#bbdbafdf8a947b563b46f632a778632b906d9eb4"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=ec2100052132a047fe0799c084696d6c0ee7629d#ec2100052132a047fe0799c084696d6c0ee7629d"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"arrayvec",
|
||||
@ -6858,7 +6858,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "wgpu-types"
|
||||
version = "22.0.0"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=bbdbafdf8a947b563b46f632a778632b906d9eb4#bbdbafdf8a947b563b46f632a778632b906d9eb4"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=ec2100052132a047fe0799c084696d6c0ee7629d#ec2100052132a047fe0799c084696d6c0ee7629d"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"js-sys",
|
||||
|
@ -17,7 +17,7 @@ default = []
|
||||
[dependencies.wgc]
|
||||
package = "wgpu-core"
|
||||
git = "https://github.com/gfx-rs/wgpu"
|
||||
rev = "bbdbafdf8a947b563b46f632a778632b906d9eb4"
|
||||
rev = "ec2100052132a047fe0799c084696d6c0ee7629d"
|
||||
# TODO: remove the replay feature on the next update containing https://github.com/gfx-rs/wgpu/pull/5182
|
||||
features = ["serde", "replay", "trace", "strict_asserts", "wgsl", "api_log_info"]
|
||||
|
||||
@ -26,32 +26,32 @@ features = ["serde", "replay", "trace", "strict_asserts", "wgsl", "api_log_info"
|
||||
[target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies.wgc]
|
||||
package = "wgpu-core"
|
||||
git = "https://github.com/gfx-rs/wgpu"
|
||||
rev = "bbdbafdf8a947b563b46f632a778632b906d9eb4"
|
||||
rev = "ec2100052132a047fe0799c084696d6c0ee7629d"
|
||||
features = ["metal"]
|
||||
|
||||
# We want the wgpu-core Direct3D backends on Windows.
|
||||
[target.'cfg(windows)'.dependencies.wgc]
|
||||
package = "wgpu-core"
|
||||
git = "https://github.com/gfx-rs/wgpu"
|
||||
rev = "bbdbafdf8a947b563b46f632a778632b906d9eb4"
|
||||
rev = "ec2100052132a047fe0799c084696d6c0ee7629d"
|
||||
features = ["dx12"]
|
||||
|
||||
# We want the wgpu-core Vulkan backend on Linux and Windows.
|
||||
[target.'cfg(any(windows, all(unix, not(any(target_os = "macos", target_os = "ios")))))'.dependencies.wgc]
|
||||
package = "wgpu-core"
|
||||
git = "https://github.com/gfx-rs/wgpu"
|
||||
rev = "bbdbafdf8a947b563b46f632a778632b906d9eb4"
|
||||
rev = "ec2100052132a047fe0799c084696d6c0ee7629d"
|
||||
features = ["vulkan"]
|
||||
|
||||
[dependencies.wgt]
|
||||
package = "wgpu-types"
|
||||
git = "https://github.com/gfx-rs/wgpu"
|
||||
rev = "bbdbafdf8a947b563b46f632a778632b906d9eb4"
|
||||
rev = "ec2100052132a047fe0799c084696d6c0ee7629d"
|
||||
|
||||
[dependencies.wgh]
|
||||
package = "wgpu-hal"
|
||||
git = "https://github.com/gfx-rs/wgpu"
|
||||
rev = "bbdbafdf8a947b563b46f632a778632b906d9eb4"
|
||||
rev = "ec2100052132a047fe0799c084696d6c0ee7629d"
|
||||
features = ["oom_panic", "device_lost_panic", "internal_error_panic"]
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
|
@ -20,11 +20,11 @@ origin:
|
||||
|
||||
# Human-readable identifier for this version/release
|
||||
# Generally "version NNN", "tag SSS", "bookmark SSS"
|
||||
release: bbdbafdf8a947b563b46f632a778632b906d9eb4 (2024-08-29T02:44:20Z).
|
||||
release: ec2100052132a047fe0799c084696d6c0ee7629d (Thu Sep 5 11:08:51 2024).
|
||||
|
||||
# Revision to pull in
|
||||
# Must be a long or short commit SHA (long preferred)
|
||||
revision: bbdbafdf8a947b563b46f632a778632b906d9eb4
|
||||
revision: ec2100052132a047fe0799c084696d6c0ee7629d
|
||||
|
||||
license: ['MIT', 'Apache-2.0']
|
||||
|
||||
|
@ -3112,12 +3112,12 @@ delta = "0.20.0 -> 22.0.0"
|
||||
|
||||
[[audits.naga]]
|
||||
who = [
|
||||
"Jim Blandy <jimb@red-bean.com>",
|
||||
"Teodor Tanasoaia <ttanasoaia@mozilla.com>",
|
||||
"Erich Gubler <erichdongubler@gmail.com>",
|
||||
"Jim Blandy <jimb@red-bean.com>",
|
||||
]
|
||||
criteria = "safe-to-deploy"
|
||||
delta = "22.0.0 -> 22.0.0@git:bbdbafdf8a947b563b46f632a778632b906d9eb4"
|
||||
delta = "22.0.0 -> 22.0.0@git:ec2100052132a047fe0799c084696d6c0ee7629d"
|
||||
importable = false
|
||||
|
||||
[[audits.net2]]
|
||||
@ -5096,12 +5096,12 @@ delta = "0.20.0 -> 22.0.0"
|
||||
|
||||
[[audits.wgpu-core]]
|
||||
who = [
|
||||
"Jim Blandy <jimb@red-bean.com>",
|
||||
"Teodor Tanasoaia <ttanasoaia@mozilla.com>",
|
||||
"Erich Gubler <erichdongubler@gmail.com>",
|
||||
"Jim Blandy <jimb@red-bean.com>",
|
||||
]
|
||||
criteria = "safe-to-deploy"
|
||||
delta = "22.0.0 -> 22.0.0@git:bbdbafdf8a947b563b46f632a778632b906d9eb4"
|
||||
delta = "22.0.0 -> 22.0.0@git:ec2100052132a047fe0799c084696d6c0ee7629d"
|
||||
importable = false
|
||||
|
||||
[[audits.wgpu-hal]]
|
||||
@ -5169,12 +5169,12 @@ delta = "0.20.0 -> 22.0.0"
|
||||
|
||||
[[audits.wgpu-hal]]
|
||||
who = [
|
||||
"Jim Blandy <jimb@red-bean.com>",
|
||||
"Teodor Tanasoaia <ttanasoaia@mozilla.com>",
|
||||
"Erich Gubler <erichdongubler@gmail.com>",
|
||||
"Jim Blandy <jimb@red-bean.com>",
|
||||
]
|
||||
criteria = "safe-to-deploy"
|
||||
delta = "22.0.0 -> 22.0.0@git:bbdbafdf8a947b563b46f632a778632b906d9eb4"
|
||||
delta = "22.0.0 -> 22.0.0@git:ec2100052132a047fe0799c084696d6c0ee7629d"
|
||||
importable = false
|
||||
|
||||
[[audits.wgpu-types]]
|
||||
@ -5242,12 +5242,12 @@ delta = "0.20.0 -> 22.0.0"
|
||||
|
||||
[[audits.wgpu-types]]
|
||||
who = [
|
||||
"Jim Blandy <jimb@red-bean.com>",
|
||||
"Teodor Tanasoaia <ttanasoaia@mozilla.com>",
|
||||
"Erich Gubler <erichdongubler@gmail.com>",
|
||||
"Jim Blandy <jimb@red-bean.com>",
|
||||
]
|
||||
criteria = "safe-to-deploy"
|
||||
delta = "22.0.0 -> 22.0.0@git:bbdbafdf8a947b563b46f632a778632b906d9eb4"
|
||||
delta = "22.0.0 -> 22.0.0@git:ec2100052132a047fe0799c084696d6c0ee7629d"
|
||||
importable = false
|
||||
|
||||
[[audits.whatsys]]
|
||||
|
@ -1,13 +1,19 @@
|
||||
[cts.https.html?q=webgpu:shader,validation,const_assert,const_assert:constant_expression_assert:*]
|
||||
implementation-status: backlog
|
||||
[:scope="function"]
|
||||
expected: FAIL
|
||||
|
||||
[:scope="module"]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[cts.https.html?q=webgpu:shader,validation,const_assert,const_assert:constant_expression_logical_and_assert:*]
|
||||
implementation-status: backlog
|
||||
[:scope="function"]
|
||||
expected: FAIL
|
||||
|
||||
[:scope="module"]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[cts.https.html?q=webgpu:shader,validation,const_assert,const_assert:constant_expression_logical_and_no_assert:*]
|
||||
@ -20,9 +26,12 @@
|
||||
|
||||
|
||||
[cts.https.html?q=webgpu:shader,validation,const_assert,const_assert:constant_expression_logical_or_assert:*]
|
||||
implementation-status: backlog
|
||||
[:scope="function"]
|
||||
expected: FAIL
|
||||
|
||||
[:scope="module"]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[cts.https.html?q=webgpu:shader,validation,const_assert,const_assert:constant_expression_logical_or_no_assert:*]
|
||||
|
2
third_party/rust/naga/.cargo-checksum.json
vendored
2
third_party/rust/naga/.cargo-checksum.json
vendored
File diff suppressed because one or more lines are too long
5
third_party/rust/naga/Cargo.toml
vendored
5
third_party/rust/naga/Cargo.toml
vendored
@ -92,7 +92,7 @@ optional = true
|
||||
version = "1.1.0"
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0.208"
|
||||
version = "1.0.209"
|
||||
features = ["derive"]
|
||||
optional = true
|
||||
|
||||
@ -120,6 +120,9 @@ version = "0.11"
|
||||
[dev-dependencies.hlsl-snapshots]
|
||||
path = "./hlsl-snapshots"
|
||||
|
||||
[dev-dependencies.itertools]
|
||||
version = "0.10.5"
|
||||
|
||||
[dev-dependencies.rspirv]
|
||||
version = "0.11"
|
||||
git = "https://github.com/gfx-rs/rspirv"
|
||||
|
17
third_party/rust/naga/src/back/glsl/mod.rs
vendored
17
third_party/rust/naga/src/back/glsl/mod.rs
vendored
@ -47,7 +47,7 @@ pub use features::Features;
|
||||
|
||||
use crate::{
|
||||
back::{self, Baked},
|
||||
proc::{self, NameKey},
|
||||
proc::{self, ExpressionKindTracker, NameKey},
|
||||
valid, Handle, ShaderStage, TypeInner,
|
||||
};
|
||||
use features::FeaturesManager;
|
||||
@ -498,6 +498,9 @@ pub enum Error {
|
||||
Custom(String),
|
||||
#[error("overrides should not be present at this stage")]
|
||||
Override,
|
||||
/// [`crate::Sampling::First`] is unsupported.
|
||||
#[error("`{:?}` sampling is unsupported", crate::Sampling::First)]
|
||||
FirstSamplingNotSupported,
|
||||
}
|
||||
|
||||
/// Binary operation with a different logic on the GLSL side.
|
||||
@ -1534,7 +1537,7 @@ impl<'a, W: Write> Writer<'a, W> {
|
||||
// here, regardless of the version.
|
||||
if let Some(sampling) = sampling {
|
||||
if emit_interpolation_and_auxiliary {
|
||||
if let Some(qualifier) = glsl_sampling(sampling) {
|
||||
if let Some(qualifier) = glsl_sampling(sampling)? {
|
||||
write!(self.out, "{qualifier} ")?;
|
||||
}
|
||||
}
|
||||
@ -1584,6 +1587,7 @@ impl<'a, W: Write> Writer<'a, W> {
|
||||
info,
|
||||
expressions: &func.expressions,
|
||||
named_expressions: &func.named_expressions,
|
||||
expr_kind_tracker: ExpressionKindTracker::from_arena(&func.expressions),
|
||||
};
|
||||
|
||||
self.named_expressions.clear();
|
||||
@ -4770,14 +4774,15 @@ const fn glsl_interpolation(interpolation: crate::Interpolation) -> &'static str
|
||||
}
|
||||
|
||||
/// Return the GLSL auxiliary qualifier for the given sampling value.
|
||||
const fn glsl_sampling(sampling: crate::Sampling) -> Option<&'static str> {
|
||||
const fn glsl_sampling(sampling: crate::Sampling) -> BackendResult<Option<&'static str>> {
|
||||
use crate::Sampling as S;
|
||||
|
||||
match sampling {
|
||||
S::Center => None,
|
||||
Ok(match sampling {
|
||||
S::First => return Err(Error::FirstSamplingNotSupported),
|
||||
S::Center | S::Either => None,
|
||||
S::Centroid => Some("centroid"),
|
||||
S::Sample => Some("sample"),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Helper function that returns the glsl dimension string of [`ImageDimension`](crate::ImageDimension)
|
||||
|
2
third_party/rust/naga/src/back/hlsl/conv.rs
vendored
2
third_party/rust/naga/src/back/hlsl/conv.rs
vendored
@ -202,7 +202,7 @@ impl crate::Sampling {
|
||||
/// Return the HLSL auxiliary qualifier for the given sampling value.
|
||||
pub(super) const fn to_hlsl_str(self) -> Option<&'static str> {
|
||||
match self {
|
||||
Self::Center => None,
|
||||
Self::Center | Self::First | Self::Either => None,
|
||||
Self::Centroid => Some("centroid"),
|
||||
Self::Sample => Some("sample"),
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ use super::{
|
||||
};
|
||||
use crate::{
|
||||
back::{self, Baked},
|
||||
proc::{self, NameKey},
|
||||
proc::{self, ExpressionKindTracker, NameKey},
|
||||
valid, Handle, Module, Scalar, ScalarKind, ShaderStage, TypeInner,
|
||||
};
|
||||
use std::{fmt, mem};
|
||||
@ -346,6 +346,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
|
||||
info,
|
||||
expressions: &function.expressions,
|
||||
named_expressions: &function.named_expressions,
|
||||
expr_kind_tracker: ExpressionKindTracker::from_arena(&function.expressions),
|
||||
};
|
||||
let name = self.names[&NameKey::Function(handle)].clone();
|
||||
|
||||
@ -386,6 +387,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
|
||||
info,
|
||||
expressions: &ep.function.expressions,
|
||||
named_expressions: &ep.function.named_expressions,
|
||||
expr_kind_tracker: ExpressionKindTracker::from_arena(&ep.function.expressions),
|
||||
};
|
||||
|
||||
self.write_wrapped_functions(module, &ctx)?;
|
||||
|
4
third_party/rust/naga/src/back/mod.rs
vendored
4
third_party/rust/naga/src/back/mod.rs
vendored
@ -3,6 +3,8 @@ Backend functions that export shader [`Module`](super::Module)s into binary and
|
||||
*/
|
||||
#![allow(dead_code)] // can be dead if none of the enabled backends need it
|
||||
|
||||
use crate::proc::ExpressionKindTracker;
|
||||
|
||||
#[cfg(dot_out)]
|
||||
pub mod dot;
|
||||
#[cfg(glsl_out)]
|
||||
@ -118,6 +120,8 @@ pub struct FunctionCtx<'a> {
|
||||
pub expressions: &'a crate::Arena<crate::Expression>,
|
||||
/// Map of expressions that have associated variable names
|
||||
pub named_expressions: &'a crate::NamedExpressions,
|
||||
/// For constness checks
|
||||
pub expr_kind_tracker: ExpressionKindTracker,
|
||||
}
|
||||
|
||||
impl FunctionCtx<'_> {
|
||||
|
1
third_party/rust/naga/src/back/msl/mod.rs
vendored
1
third_party/rust/naga/src/back/msl/mod.rs
vendored
@ -627,6 +627,7 @@ impl ResolvedInterpolation {
|
||||
(I::Linear, S::Centroid) => Self::CentroidNoPerspective,
|
||||
(I::Linear, S::Sample) => Self::SampleNoPerspective,
|
||||
(I::Flat, _) => Self::Flat,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -289,6 +289,7 @@ fn process_function(
|
||||
&mut local_expression_kind_tracker,
|
||||
&mut emitter,
|
||||
&mut block,
|
||||
false,
|
||||
);
|
||||
|
||||
for (old_h, mut expr, span) in expressions.drain() {
|
||||
|
7
third_party/rust/naga/src/back/spv/writer.rs
vendored
7
third_party/rust/naga/src/back/spv/writer.rs
vendored
@ -1511,7 +1511,12 @@ impl Writer {
|
||||
}
|
||||
match sampling {
|
||||
// Center sampling is the default in SPIR-V.
|
||||
None | Some(crate::Sampling::Center) => (),
|
||||
None
|
||||
| Some(
|
||||
crate::Sampling::Center
|
||||
| crate::Sampling::First
|
||||
| crate::Sampling::Either,
|
||||
) => (),
|
||||
Some(crate::Sampling::Centroid) => {
|
||||
self.decorate(id, Decoration::Centroid, &[]);
|
||||
}
|
||||
|
14
third_party/rust/naga/src/back/wgsl/writer.rs
vendored
14
third_party/rust/naga/src/back/wgsl/writer.rs
vendored
@ -1,7 +1,7 @@
|
||||
use super::Error;
|
||||
use crate::{
|
||||
back::{self, Baked},
|
||||
proc::{self, NameKey},
|
||||
proc::{self, ExpressionKindTracker, NameKey},
|
||||
valid, Handle, Module, ShaderStage, TypeInner,
|
||||
};
|
||||
use std::fmt::Write;
|
||||
@ -166,6 +166,7 @@ impl<W: Write> Writer<W> {
|
||||
info: fun_info,
|
||||
expressions: &function.expressions,
|
||||
named_expressions: &function.named_expressions,
|
||||
expr_kind_tracker: ExpressionKindTracker::from_arena(&function.expressions),
|
||||
};
|
||||
|
||||
// Write the function
|
||||
@ -193,6 +194,7 @@ impl<W: Write> Writer<W> {
|
||||
info: info.get_entry_point(index),
|
||||
expressions: &ep.function.expressions,
|
||||
named_expressions: &ep.function.named_expressions,
|
||||
expr_kind_tracker: ExpressionKindTracker::from_arena(&ep.function.expressions),
|
||||
};
|
||||
self.write_function(module, &ep.function, &func_ctx)?;
|
||||
|
||||
@ -1115,8 +1117,14 @@ impl<W: Write> Writer<W> {
|
||||
func_ctx: &back::FunctionCtx,
|
||||
name: &str,
|
||||
) -> BackendResult {
|
||||
// Some functions are marked as const, but are not yet implemented as constant expression
|
||||
let quantifier = if func_ctx.expr_kind_tracker.is_impl_const(handle) {
|
||||
"const"
|
||||
} else {
|
||||
"let"
|
||||
};
|
||||
// Write variable name
|
||||
write!(self.out, "let {name}")?;
|
||||
write!(self.out, "{quantifier} {name}")?;
|
||||
if self.flags.contains(WriterFlags::EXPLICIT_TYPES) {
|
||||
write!(self.out, ": ")?;
|
||||
let ty = &func_ctx.info[handle].ty;
|
||||
@ -2053,6 +2061,8 @@ const fn sampling_str(sampling: crate::Sampling) -> &'static str {
|
||||
S::Center => "",
|
||||
S::Centroid => "centroid",
|
||||
S::Sample => "sample",
|
||||
S::First => "first",
|
||||
S::Either => "either",
|
||||
}
|
||||
}
|
||||
|
||||
|
18
third_party/rust/naga/src/front/wgsl/error.rs
vendored
18
third_party/rust/naga/src/front/wgsl/error.rs
vendored
@ -263,6 +263,8 @@ pub(crate) enum Error<'a> {
|
||||
limit: u8,
|
||||
},
|
||||
PipelineConstantIDValue(Span),
|
||||
NotBool(Span),
|
||||
ConstAssertFailed(Span),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@ -815,6 +817,22 @@ impl<'a> Error<'a> {
|
||||
)],
|
||||
notes: vec![],
|
||||
},
|
||||
Error::NotBool(span) => ParseError {
|
||||
message: "must be a const-expression that resolves to a bool".to_string(),
|
||||
labels: vec![(
|
||||
span,
|
||||
"must resolve to bool".into(),
|
||||
)],
|
||||
notes: vec![],
|
||||
},
|
||||
Error::ConstAssertFailed(span) => ParseError {
|
||||
message: "const_assert failure".to_string(),
|
||||
labels: vec![(
|
||||
span,
|
||||
"evaluates to false".into(),
|
||||
)],
|
||||
notes: vec![],
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
43
third_party/rust/naga/src/front/wgsl/index.rs
vendored
43
third_party/rust/naga/src/front/wgsl/index.rs
vendored
@ -20,13 +20,16 @@ impl<'a> Index<'a> {
|
||||
// While doing so, reject conflicting definitions.
|
||||
let mut globals = FastHashMap::with_capacity_and_hasher(tu.decls.len(), Default::default());
|
||||
for (handle, decl) in tu.decls.iter() {
|
||||
let ident = decl_ident(decl);
|
||||
let name = ident.name;
|
||||
if let Some(old) = globals.insert(name, handle) {
|
||||
return Err(Error::Redefinition {
|
||||
previous: decl_ident(&tu.decls[old]).span,
|
||||
current: ident.span,
|
||||
});
|
||||
if let Some(ident) = decl_ident(decl) {
|
||||
let name = ident.name;
|
||||
if let Some(old) = globals.insert(name, handle) {
|
||||
return Err(Error::Redefinition {
|
||||
previous: decl_ident(&tu.decls[old])
|
||||
.expect("decl should have ident for redefinition")
|
||||
.span,
|
||||
current: ident.span,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -130,7 +133,7 @@ impl<'a> DependencySolver<'a, '_> {
|
||||
return if dep_id == id {
|
||||
// A declaration refers to itself directly.
|
||||
Err(Error::RecursiveDeclaration {
|
||||
ident: decl_ident(decl).span,
|
||||
ident: decl_ident(decl).expect("decl should have ident").span,
|
||||
usage: dep.usage,
|
||||
})
|
||||
} else {
|
||||
@ -146,14 +149,19 @@ impl<'a> DependencySolver<'a, '_> {
|
||||
.unwrap_or(0);
|
||||
|
||||
Err(Error::CyclicDeclaration {
|
||||
ident: decl_ident(&self.module.decls[dep_id]).span,
|
||||
ident: decl_ident(&self.module.decls[dep_id])
|
||||
.expect("decl should have ident")
|
||||
.span,
|
||||
path: self.path[start_at..]
|
||||
.iter()
|
||||
.map(|curr_dep| {
|
||||
let curr_id = curr_dep.decl;
|
||||
let curr_decl = &self.module.decls[curr_id];
|
||||
|
||||
(decl_ident(curr_decl).span, curr_dep.usage)
|
||||
(
|
||||
decl_ident(curr_decl).expect("decl should have ident").span,
|
||||
curr_dep.usage,
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
})
|
||||
@ -182,13 +190,14 @@ impl<'a> DependencySolver<'a, '_> {
|
||||
}
|
||||
}
|
||||
|
||||
const fn decl_ident<'a>(decl: &ast::GlobalDecl<'a>) -> ast::Ident<'a> {
|
||||
const fn decl_ident<'a>(decl: &ast::GlobalDecl<'a>) -> Option<ast::Ident<'a>> {
|
||||
match decl.kind {
|
||||
ast::GlobalDeclKind::Fn(ref f) => f.name,
|
||||
ast::GlobalDeclKind::Var(ref v) => v.name,
|
||||
ast::GlobalDeclKind::Const(ref c) => c.name,
|
||||
ast::GlobalDeclKind::Override(ref o) => o.name,
|
||||
ast::GlobalDeclKind::Struct(ref s) => s.name,
|
||||
ast::GlobalDeclKind::Type(ref t) => t.name,
|
||||
ast::GlobalDeclKind::Fn(ref f) => Some(f.name),
|
||||
ast::GlobalDeclKind::Var(ref v) => Some(v.name),
|
||||
ast::GlobalDeclKind::Const(ref c) => Some(c.name),
|
||||
ast::GlobalDeclKind::Override(ref o) => Some(o.name),
|
||||
ast::GlobalDeclKind::Struct(ref s) => Some(s.name),
|
||||
ast::GlobalDeclKind::Type(ref t) => Some(t.name),
|
||||
ast::GlobalDeclKind::ConstAssert(_) => None,
|
||||
}
|
||||
}
|
||||
|
@ -578,8 +578,13 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
|
||||
Constructor::Type(ty)
|
||||
}
|
||||
ast::ConstructorType::PartialVector { size } => Constructor::PartialVector { size },
|
||||
ast::ConstructorType::Vector { size, scalar } => {
|
||||
let ty = ctx.ensure_type_exists(scalar.to_inner_vector(size));
|
||||
ast::ConstructorType::Vector { size, ty, ty_span } => {
|
||||
let ty = self.resolve_ast_type(ty, &mut ctx.as_global())?;
|
||||
let scalar = match ctx.module.types[ty].inner {
|
||||
crate::TypeInner::Scalar(sc) => sc,
|
||||
_ => return Err(Error::UnknownScalarType(ty_span)),
|
||||
};
|
||||
let ty = ctx.ensure_type_exists(crate::TypeInner::Vector { size, scalar });
|
||||
Constructor::Type(ty)
|
||||
}
|
||||
ast::ConstructorType::PartialMatrix { columns, rows } => {
|
||||
@ -588,13 +593,22 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
|
||||
ast::ConstructorType::Matrix {
|
||||
rows,
|
||||
columns,
|
||||
width,
|
||||
ty,
|
||||
ty_span,
|
||||
} => {
|
||||
let ty = ctx.ensure_type_exists(crate::TypeInner::Matrix {
|
||||
columns,
|
||||
rows,
|
||||
scalar: crate::Scalar::float(width),
|
||||
});
|
||||
let ty = self.resolve_ast_type(ty, &mut ctx.as_global())?;
|
||||
let scalar = match ctx.module.types[ty].inner {
|
||||
crate::TypeInner::Scalar(sc) => sc,
|
||||
_ => return Err(Error::UnknownScalarType(ty_span)),
|
||||
};
|
||||
let ty = match scalar.kind {
|
||||
crate::ScalarKind::Float => ctx.ensure_type_exists(crate::TypeInner::Matrix {
|
||||
columns,
|
||||
rows,
|
||||
scalar,
|
||||
}),
|
||||
_ => return Err(Error::BadMatrixScalarKind(ty_span, scalar)),
|
||||
};
|
||||
Constructor::Type(ty)
|
||||
}
|
||||
ast::ConstructorType::PartialArray => Constructor::PartialArray,
|
||||
|
314
third_party/rust/naga/src/front/wgsl/lower/mod.rs
vendored
314
third_party/rust/naga/src/front/wgsl/lower/mod.rs
vendored
@ -98,7 +98,7 @@ impl<'source> GlobalContext<'source, '_, '_> {
|
||||
types: self.types,
|
||||
module: self.module,
|
||||
const_typifier: self.const_typifier,
|
||||
expr_type: ExpressionContextType::Constant,
|
||||
expr_type: ExpressionContextType::Constant(None),
|
||||
global_expression_kind_tracker: self.global_expression_kind_tracker,
|
||||
}
|
||||
}
|
||||
@ -160,7 +160,8 @@ pub struct StatementContext<'source, 'temp, 'out> {
|
||||
///
|
||||
/// [`LocalVariable`]: crate::Expression::LocalVariable
|
||||
/// [`FunctionArgument`]: crate::Expression::FunctionArgument
|
||||
local_table: &'temp mut FastHashMap<Handle<ast::Local>, Typed<Handle<crate::Expression>>>,
|
||||
local_table:
|
||||
&'temp mut FastHashMap<Handle<ast::Local>, Declared<Typed<Handle<crate::Expression>>>>,
|
||||
|
||||
const_typifier: &'temp mut Typifier,
|
||||
typifier: &'temp mut Typifier,
|
||||
@ -184,6 +185,32 @@ pub struct StatementContext<'source, 'temp, 'out> {
|
||||
}
|
||||
|
||||
impl<'a, 'temp> StatementContext<'a, 'temp, '_> {
|
||||
fn as_const<'t>(
|
||||
&'t mut self,
|
||||
block: &'t mut crate::Block,
|
||||
emitter: &'t mut Emitter,
|
||||
) -> ExpressionContext<'a, 't, '_>
|
||||
where
|
||||
'temp: 't,
|
||||
{
|
||||
ExpressionContext {
|
||||
globals: self.globals,
|
||||
types: self.types,
|
||||
ast_expressions: self.ast_expressions,
|
||||
const_typifier: self.const_typifier,
|
||||
global_expression_kind_tracker: self.global_expression_kind_tracker,
|
||||
module: self.module,
|
||||
expr_type: ExpressionContextType::Constant(Some(LocalExpressionContext {
|
||||
local_table: self.local_table,
|
||||
function: self.function,
|
||||
block,
|
||||
emitter,
|
||||
typifier: self.typifier,
|
||||
local_expression_kind_tracker: self.local_expression_kind_tracker,
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
fn as_expression<'t>(
|
||||
&'t mut self,
|
||||
block: &'t mut crate::Block,
|
||||
@ -199,7 +226,7 @@ impl<'a, 'temp> StatementContext<'a, 'temp, '_> {
|
||||
const_typifier: self.const_typifier,
|
||||
global_expression_kind_tracker: self.global_expression_kind_tracker,
|
||||
module: self.module,
|
||||
expr_type: ExpressionContextType::Runtime(RuntimeExpressionContext {
|
||||
expr_type: ExpressionContextType::Runtime(LocalExpressionContext {
|
||||
local_table: self.local_table,
|
||||
function: self.function,
|
||||
block,
|
||||
@ -235,12 +262,12 @@ impl<'a, 'temp> StatementContext<'a, 'temp, '_> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RuntimeExpressionContext<'temp, 'out> {
|
||||
pub struct LocalExpressionContext<'temp, 'out> {
|
||||
/// A map from [`ast::Local`] handles to the Naga expressions we've built for them.
|
||||
///
|
||||
/// This is always [`StatementContext::local_table`] for the
|
||||
/// enclosing statement; see that documentation for details.
|
||||
local_table: &'temp FastHashMap<Handle<ast::Local>, Typed<Handle<crate::Expression>>>,
|
||||
local_table: &'temp FastHashMap<Handle<ast::Local>, Declared<Typed<Handle<crate::Expression>>>>,
|
||||
|
||||
function: &'out mut crate::Function,
|
||||
block: &'temp mut crate::Block,
|
||||
@ -259,18 +286,18 @@ pub enum ExpressionContextType<'temp, 'out> {
|
||||
/// We are lowering to an arbitrary runtime expression, to be
|
||||
/// included in a function's body.
|
||||
///
|
||||
/// The given [`RuntimeExpressionContext`] holds information about local
|
||||
/// The given [`LocalExpressionContext`] holds information about local
|
||||
/// variables, arguments, and other definitions available only to runtime
|
||||
/// expressions, not constant or override expressions.
|
||||
Runtime(RuntimeExpressionContext<'temp, 'out>),
|
||||
Runtime(LocalExpressionContext<'temp, 'out>),
|
||||
|
||||
/// We are lowering to a constant expression, to be included in the module's
|
||||
/// constant expression arena.
|
||||
///
|
||||
/// Everything constant expressions are allowed to refer to is
|
||||
/// available in the [`ExpressionContext`], so this variant
|
||||
/// carries no further information.
|
||||
Constant,
|
||||
/// Everything global constant expressions are allowed to refer to is
|
||||
/// available in the [`ExpressionContext`], but local constant expressions can
|
||||
/// also refer to other
|
||||
Constant(Option<LocalExpressionContext<'temp, 'out>>),
|
||||
|
||||
/// We are lowering to an override expression, to be included in the module's
|
||||
/// constant expression arena.
|
||||
@ -352,7 +379,7 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> {
|
||||
ast_expressions: self.ast_expressions,
|
||||
const_typifier: self.const_typifier,
|
||||
module: self.module,
|
||||
expr_type: ExpressionContextType::Constant,
|
||||
expr_type: ExpressionContextType::Constant(None),
|
||||
global_expression_kind_tracker: self.global_expression_kind_tracker,
|
||||
}
|
||||
}
|
||||
@ -376,8 +403,19 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> {
|
||||
rctx.local_expression_kind_tracker,
|
||||
rctx.emitter,
|
||||
rctx.block,
|
||||
false,
|
||||
),
|
||||
ExpressionContextType::Constant => ConstantEvaluator::for_wgsl_module(
|
||||
ExpressionContextType::Constant(Some(ref mut rctx)) => {
|
||||
ConstantEvaluator::for_wgsl_function(
|
||||
self.module,
|
||||
&mut rctx.function.expressions,
|
||||
rctx.local_expression_kind_tracker,
|
||||
rctx.emitter,
|
||||
rctx.block,
|
||||
true,
|
||||
)
|
||||
}
|
||||
ExpressionContextType::Constant(None) => ConstantEvaluator::for_wgsl_module(
|
||||
self.module,
|
||||
self.global_expression_kind_tracker,
|
||||
false,
|
||||
@ -412,15 +450,27 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> {
|
||||
.eval_expr_to_u32_from(handle, &ctx.function.expressions)
|
||||
.ok()
|
||||
}
|
||||
ExpressionContextType::Constant => self.module.to_ctx().eval_expr_to_u32(handle).ok(),
|
||||
ExpressionContextType::Constant(Some(ref ctx)) => {
|
||||
assert!(ctx.local_expression_kind_tracker.is_const(handle));
|
||||
self.module
|
||||
.to_ctx()
|
||||
.eval_expr_to_u32_from(handle, &ctx.function.expressions)
|
||||
.ok()
|
||||
}
|
||||
ExpressionContextType::Constant(None) => {
|
||||
self.module.to_ctx().eval_expr_to_u32(handle).ok()
|
||||
}
|
||||
ExpressionContextType::Override => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_expression_span(&self, handle: Handle<crate::Expression>) -> Span {
|
||||
match self.expr_type {
|
||||
ExpressionContextType::Runtime(ref ctx) => ctx.function.expressions.get_span(handle),
|
||||
ExpressionContextType::Constant | ExpressionContextType::Override => {
|
||||
ExpressionContextType::Runtime(ref ctx)
|
||||
| ExpressionContextType::Constant(Some(ref ctx)) => {
|
||||
ctx.function.expressions.get_span(handle)
|
||||
}
|
||||
ExpressionContextType::Constant(None) | ExpressionContextType::Override => {
|
||||
self.module.global_expressions.get_span(handle)
|
||||
}
|
||||
}
|
||||
@ -428,20 +478,35 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> {
|
||||
|
||||
fn typifier(&self) -> &Typifier {
|
||||
match self.expr_type {
|
||||
ExpressionContextType::Runtime(ref ctx) => ctx.typifier,
|
||||
ExpressionContextType::Constant | ExpressionContextType::Override => {
|
||||
ExpressionContextType::Runtime(ref ctx)
|
||||
| ExpressionContextType::Constant(Some(ref ctx)) => ctx.typifier,
|
||||
ExpressionContextType::Constant(None) | ExpressionContextType::Override => {
|
||||
self.const_typifier
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn local(
|
||||
&mut self,
|
||||
local: &Handle<ast::Local>,
|
||||
span: Span,
|
||||
) -> Result<Typed<Handle<crate::Expression>>, Error<'source>> {
|
||||
match self.expr_type {
|
||||
ExpressionContextType::Runtime(ref ctx) => Ok(ctx.local_table[local].runtime()),
|
||||
ExpressionContextType::Constant(Some(ref ctx)) => ctx.local_table[local]
|
||||
.const_time()
|
||||
.ok_or(Error::UnexpectedOperationInConstContext(span)),
|
||||
_ => Err(Error::UnexpectedOperationInConstContext(span)),
|
||||
}
|
||||
}
|
||||
|
||||
fn runtime_expression_ctx(
|
||||
&mut self,
|
||||
span: Span,
|
||||
) -> Result<&mut RuntimeExpressionContext<'temp, 'out>, Error<'source>> {
|
||||
) -> Result<&mut LocalExpressionContext<'temp, 'out>, Error<'source>> {
|
||||
match self.expr_type {
|
||||
ExpressionContextType::Runtime(ref mut ctx) => Ok(ctx),
|
||||
ExpressionContextType::Constant | ExpressionContextType::Override => {
|
||||
ExpressionContextType::Constant(_) | ExpressionContextType::Override => {
|
||||
Err(Error::UnexpectedOperationInConstContext(span))
|
||||
}
|
||||
}
|
||||
@ -480,7 +545,7 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> {
|
||||
}
|
||||
// This means a `gather` operation appeared in a constant expression.
|
||||
// This error refers to the `gather` itself, not its "component" argument.
|
||||
ExpressionContextType::Constant | ExpressionContextType::Override => {
|
||||
ExpressionContextType::Constant(_) | ExpressionContextType::Override => {
|
||||
Err(Error::UnexpectedOperationInConstContext(gather_span))
|
||||
}
|
||||
}
|
||||
@ -505,8 +570,9 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> {
|
||||
// except that this lets the borrow checker see that it's okay
|
||||
// to also borrow self.module.types mutably below.
|
||||
let typifier = match self.expr_type {
|
||||
ExpressionContextType::Runtime(ref ctx) => ctx.typifier,
|
||||
ExpressionContextType::Constant | ExpressionContextType::Override => {
|
||||
ExpressionContextType::Runtime(ref ctx)
|
||||
| ExpressionContextType::Constant(Some(ref ctx)) => ctx.typifier,
|
||||
ExpressionContextType::Constant(None) | ExpressionContextType::Override => {
|
||||
&*self.const_typifier
|
||||
}
|
||||
};
|
||||
@ -542,7 +608,8 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> {
|
||||
let typifier;
|
||||
let expressions;
|
||||
match self.expr_type {
|
||||
ExpressionContextType::Runtime(ref mut ctx) => {
|
||||
ExpressionContextType::Runtime(ref mut ctx)
|
||||
| ExpressionContextType::Constant(Some(ref mut ctx)) => {
|
||||
resolve_ctx = ResolveContext::with_locals(
|
||||
self.module,
|
||||
&ctx.function.local_variables,
|
||||
@ -551,7 +618,7 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> {
|
||||
typifier = &mut *ctx.typifier;
|
||||
expressions = &ctx.function.expressions;
|
||||
}
|
||||
ExpressionContextType::Constant | ExpressionContextType::Override => {
|
||||
ExpressionContextType::Constant(None) | ExpressionContextType::Override => {
|
||||
resolve_ctx = ResolveContext::with_locals(self.module, &empty_arena, &[]);
|
||||
typifier = self.const_typifier;
|
||||
expressions = &self.module.global_expressions;
|
||||
@ -643,18 +710,20 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> {
|
||||
span: Span,
|
||||
) -> Result<Handle<crate::Expression>, Error<'source>> {
|
||||
match self.expr_type {
|
||||
ExpressionContextType::Runtime(ref mut rctx) => {
|
||||
ExpressionContextType::Runtime(ref mut rctx)
|
||||
| ExpressionContextType::Constant(Some(ref mut rctx)) => {
|
||||
rctx.block
|
||||
.extend(rctx.emitter.finish(&rctx.function.expressions));
|
||||
}
|
||||
ExpressionContextType::Constant | ExpressionContextType::Override => {}
|
||||
ExpressionContextType::Constant(None) | ExpressionContextType::Override => {}
|
||||
}
|
||||
let result = self.append_expression(expression, span);
|
||||
match self.expr_type {
|
||||
ExpressionContextType::Runtime(ref mut rctx) => {
|
||||
ExpressionContextType::Runtime(ref mut rctx)
|
||||
| ExpressionContextType::Constant(Some(ref mut rctx)) => {
|
||||
rctx.emitter.start(&rctx.function.expressions);
|
||||
}
|
||||
ExpressionContextType::Constant | ExpressionContextType::Override => {}
|
||||
ExpressionContextType::Constant(None) | ExpressionContextType::Override => {}
|
||||
}
|
||||
result
|
||||
}
|
||||
@ -718,6 +787,30 @@ impl<'source> ArgumentContext<'_, 'source> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
enum Declared<T> {
|
||||
/// Value declared as const
|
||||
Const(T),
|
||||
|
||||
/// Value declared as non-const
|
||||
Runtime(T),
|
||||
}
|
||||
|
||||
impl<T> Declared<T> {
|
||||
fn runtime(self) -> T {
|
||||
match self {
|
||||
Declared::Const(t) | Declared::Runtime(t) => t,
|
||||
}
|
||||
}
|
||||
|
||||
fn const_time(self) -> Option<T> {
|
||||
match self {
|
||||
Declared::Const(t) => Some(t),
|
||||
Declared::Runtime(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// WGSL type annotations on expressions, types, values, etc.
|
||||
///
|
||||
/// Naga and WGSL types are very close, but Naga lacks WGSL's `ref` types, which
|
||||
@ -814,7 +907,13 @@ impl Components {
|
||||
*comp = Self::letter_component(ch).ok_or(Error::BadAccessor(name_span))?;
|
||||
}
|
||||
|
||||
Ok(Components::Swizzle { size, pattern })
|
||||
if name.chars().all(|c| matches!(c, 'x' | 'y' | 'z' | 'w'))
|
||||
|| name.chars().all(|c| matches!(c, 'r' | 'g' | 'b' | 'a'))
|
||||
{
|
||||
Ok(Components::Swizzle { size, pattern })
|
||||
} else {
|
||||
Err(Error::BadAccessor(name_span))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -935,16 +1034,21 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
|
||||
ctx.globals.insert(f.name.name, lowered_decl);
|
||||
}
|
||||
ast::GlobalDeclKind::Var(ref v) => {
|
||||
let ty = self.resolve_ast_type(v.ty, &mut ctx)?;
|
||||
let explicit_ty =
|
||||
v.ty.map(|ast| self.resolve_ast_type(ast, &mut ctx))
|
||||
.transpose()?;
|
||||
|
||||
let init;
|
||||
if let Some(init_ast) = v.init {
|
||||
let mut ectx = ctx.as_override();
|
||||
let lowered = self.expression_for_abstract(init_ast, &mut ectx)?;
|
||||
let ty_res = crate::proc::TypeResolution::Handle(ty);
|
||||
let converted = ectx
|
||||
.try_automatic_conversions(lowered, &ty_res, v.name.span)
|
||||
.map_err(|error| match error {
|
||||
let mut ectx = ctx.as_override();
|
||||
|
||||
let ty;
|
||||
let initializer;
|
||||
match (v.init, explicit_ty) {
|
||||
(Some(init), Some(explicit_ty)) => {
|
||||
let init = self.expression_for_abstract(init, &mut ectx)?;
|
||||
let ty_res = crate::proc::TypeResolution::Handle(explicit_ty);
|
||||
let init = ectx
|
||||
.try_automatic_conversions(init, &ty_res, v.name.span)
|
||||
.map_err(|error| match error {
|
||||
Error::AutoConversion(e) => Error::InitializationTypeMismatch {
|
||||
name: v.name.span,
|
||||
expected: e.dest_type,
|
||||
@ -952,9 +1056,19 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
|
||||
},
|
||||
other => other,
|
||||
})?;
|
||||
init = Some(converted);
|
||||
} else {
|
||||
init = None;
|
||||
ty = explicit_ty;
|
||||
initializer = Some(init);
|
||||
}
|
||||
(Some(init), None) => {
|
||||
let concretized = self.expression(init, &mut ectx)?;
|
||||
ty = ectx.register_type(concretized)?;
|
||||
initializer = Some(concretized);
|
||||
}
|
||||
(None, Some(explicit_ty)) => {
|
||||
ty = explicit_ty;
|
||||
initializer = None;
|
||||
}
|
||||
(None, None) => return Err(Error::DeclMissingTypeAndInit(v.name.span)),
|
||||
}
|
||||
|
||||
let binding = if let Some(ref binding) = v.binding {
|
||||
@ -972,7 +1086,7 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
|
||||
space: v.space,
|
||||
binding,
|
||||
ty,
|
||||
init,
|
||||
init: initializer,
|
||||
},
|
||||
span,
|
||||
);
|
||||
@ -1090,6 +1204,20 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
|
||||
ctx.globals
|
||||
.insert(alias.name.name, LoweredGlobalDecl::Type(ty));
|
||||
}
|
||||
ast::GlobalDeclKind::ConstAssert(condition) => {
|
||||
let condition = self.expression(condition, &mut ctx.as_const())?;
|
||||
|
||||
let span = ctx.module.global_expressions.get_span(condition);
|
||||
match ctx
|
||||
.module
|
||||
.to_ctx()
|
||||
.eval_expr_to_bool_from(condition, &ctx.module.global_expressions)
|
||||
{
|
||||
Some(true) => Ok(()),
|
||||
Some(false) => Err(Error::ConstAssertFailed(span)),
|
||||
_ => Err(Error::NotBool(span)),
|
||||
}?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1120,7 +1248,7 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
|
||||
let ty = self.resolve_ast_type(arg.ty, ctx)?;
|
||||
let expr = expressions
|
||||
.append(crate::Expression::FunctionArgument(i as u32), arg.name.span);
|
||||
local_table.insert(arg.handle, Typed::Plain(expr));
|
||||
local_table.insert(arg.handle, Declared::Runtime(Typed::Plain(expr)));
|
||||
named_expressions.insert(expr, (arg.name.name.to_string(), arg.name.span));
|
||||
local_expression_kind_tracker.insert(expr, crate::proc::ExpressionKind::Runtime);
|
||||
|
||||
@ -1268,7 +1396,8 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
|
||||
}
|
||||
|
||||
block.extend(emitter.finish(&ctx.function.expressions));
|
||||
ctx.local_table.insert(l.handle, Typed::Plain(value));
|
||||
ctx.local_table
|
||||
.insert(l.handle, Declared::Runtime(Typed::Plain(value)));
|
||||
ctx.named_expressions
|
||||
.insert(value, (l.name.name.to_string(), l.name.span));
|
||||
|
||||
@ -1350,7 +1479,8 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
|
||||
Span::UNDEFINED,
|
||||
)?;
|
||||
block.extend(emitter.finish(&ctx.function.expressions));
|
||||
ctx.local_table.insert(v.handle, Typed::Reference(handle));
|
||||
ctx.local_table
|
||||
.insert(v.handle, Declared::Runtime(Typed::Reference(handle)));
|
||||
|
||||
match initializer {
|
||||
Some(initializer) => crate::Statement::Store {
|
||||
@ -1360,6 +1490,41 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
|
||||
None => return Ok(()),
|
||||
}
|
||||
}
|
||||
ast::LocalDecl::Const(ref c) => {
|
||||
let mut emitter = Emitter::default();
|
||||
emitter.start(&ctx.function.expressions);
|
||||
|
||||
let ectx = &mut ctx.as_const(block, &mut emitter);
|
||||
|
||||
let mut init = self.expression_for_abstract(c.init, ectx)?;
|
||||
|
||||
if let Some(explicit_ty) = c.ty {
|
||||
let explicit_ty =
|
||||
self.resolve_ast_type(explicit_ty, &mut ectx.as_global())?;
|
||||
let explicit_ty_res = crate::proc::TypeResolution::Handle(explicit_ty);
|
||||
init = ectx
|
||||
.try_automatic_conversions(init, &explicit_ty_res, c.name.span)
|
||||
.map_err(|error| match error {
|
||||
Error::AutoConversion(error) => Error::InitializationTypeMismatch {
|
||||
name: c.name.span,
|
||||
expected: error.dest_type,
|
||||
got: error.source_type,
|
||||
},
|
||||
other => other,
|
||||
})?;
|
||||
} else {
|
||||
init = ectx.concretize(init)?;
|
||||
ectx.register_type(init)?;
|
||||
}
|
||||
|
||||
block.extend(emitter.finish(&ctx.function.expressions));
|
||||
ctx.local_table
|
||||
.insert(c.handle, Declared::Const(Typed::Plain(init)));
|
||||
ctx.named_expressions
|
||||
.insert(init, (c.name.name.to_string(), c.name.span));
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
},
|
||||
ast::StatementKind::If {
|
||||
condition,
|
||||
@ -1591,6 +1756,28 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
|
||||
value,
|
||||
}
|
||||
}
|
||||
ast::StatementKind::ConstAssert(condition) => {
|
||||
let mut emitter = Emitter::default();
|
||||
emitter.start(&ctx.function.expressions);
|
||||
|
||||
let condition =
|
||||
self.expression(condition, &mut ctx.as_const(block, &mut emitter))?;
|
||||
|
||||
let span = ctx.function.expressions.get_span(condition);
|
||||
match ctx
|
||||
.module
|
||||
.to_ctx()
|
||||
.eval_expr_to_bool_from(condition, &ctx.function.expressions)
|
||||
{
|
||||
Some(true) => Ok(()),
|
||||
Some(false) => Err(Error::ConstAssertFailed(span)),
|
||||
_ => Err(Error::NotBool(span)),
|
||||
}?;
|
||||
|
||||
block.extend(emitter.finish(&ctx.function.expressions));
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
ast::StatementKind::Ignore(expr) => {
|
||||
let mut emitter = Emitter::default();
|
||||
emitter.start(&ctx.function.expressions);
|
||||
@ -1658,8 +1845,7 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
|
||||
return Ok(Typed::Plain(handle));
|
||||
}
|
||||
ast::Expression::Ident(ast::IdentExpr::Local(local)) => {
|
||||
let rctx = ctx.runtime_expression_ctx(span)?;
|
||||
return Ok(rctx.local_table[&local]);
|
||||
return ctx.local(&local, span);
|
||||
}
|
||||
ast::Expression::Ident(ast::IdentExpr::Unresolved(name)) => {
|
||||
let global = ctx
|
||||
@ -2830,16 +3016,34 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
|
||||
) -> Result<Handle<crate::Type>, Error<'source>> {
|
||||
let inner = match ctx.types[handle] {
|
||||
ast::Type::Scalar(scalar) => scalar.to_inner_scalar(),
|
||||
ast::Type::Vector { size, scalar } => scalar.to_inner_vector(size),
|
||||
ast::Type::Vector { size, ty, ty_span } => {
|
||||
let ty = self.resolve_ast_type(ty, ctx)?;
|
||||
let scalar = match ctx.module.types[ty].inner {
|
||||
crate::TypeInner::Scalar(sc) => sc,
|
||||
_ => return Err(Error::UnknownScalarType(ty_span)),
|
||||
};
|
||||
crate::TypeInner::Vector { size, scalar }
|
||||
}
|
||||
ast::Type::Matrix {
|
||||
rows,
|
||||
columns,
|
||||
width,
|
||||
} => crate::TypeInner::Matrix {
|
||||
columns,
|
||||
rows,
|
||||
scalar: crate::Scalar::float(width),
|
||||
},
|
||||
ty,
|
||||
ty_span,
|
||||
} => {
|
||||
let ty = self.resolve_ast_type(ty, ctx)?;
|
||||
let scalar = match ctx.module.types[ty].inner {
|
||||
crate::TypeInner::Scalar(sc) => sc,
|
||||
_ => return Err(Error::UnknownScalarType(ty_span)),
|
||||
};
|
||||
match scalar.kind {
|
||||
crate::ScalarKind::Float => crate::TypeInner::Matrix {
|
||||
columns,
|
||||
rows,
|
||||
scalar,
|
||||
},
|
||||
_ => return Err(Error::BadMatrixScalarKind(ty_span, scalar)),
|
||||
}
|
||||
}
|
||||
ast::Type::Atomic(scalar) => scalar.to_inner_atomic(),
|
||||
ast::Type::Pointer { base, space } => {
|
||||
let base = self.resolve_ast_type(base, ctx)?;
|
||||
|
@ -85,6 +85,7 @@ pub enum GlobalDeclKind<'a> {
|
||||
Override(Override<'a>),
|
||||
Struct(Struct<'a>),
|
||||
Type(TypeAlias<'a>),
|
||||
ConstAssert(Handle<Expression<'a>>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -109,7 +110,7 @@ pub struct EntryPoint<'a> {
|
||||
}
|
||||
|
||||
#[cfg(doc)]
|
||||
use crate::front::wgsl::lower::{RuntimeExpressionContext, StatementContext};
|
||||
use crate::front::wgsl::lower::{LocalExpressionContext, StatementContext};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Function<'a> {
|
||||
@ -142,7 +143,7 @@ pub struct GlobalVariable<'a> {
|
||||
pub name: Ident<'a>,
|
||||
pub space: crate::AddressSpace,
|
||||
pub binding: Option<ResourceBinding<'a>>,
|
||||
pub ty: Handle<Type<'a>>,
|
||||
pub ty: Option<Handle<Type<'a>>>,
|
||||
pub init: Option<Handle<Expression<'a>>>,
|
||||
}
|
||||
|
||||
@ -198,12 +199,14 @@ pub enum Type<'a> {
|
||||
Scalar(Scalar),
|
||||
Vector {
|
||||
size: crate::VectorSize,
|
||||
scalar: Scalar,
|
||||
ty: Handle<Type<'a>>,
|
||||
ty_span: Span,
|
||||
},
|
||||
Matrix {
|
||||
columns: crate::VectorSize,
|
||||
rows: crate::VectorSize,
|
||||
width: crate::Bytes,
|
||||
ty: Handle<Type<'a>>,
|
||||
ty_span: Span,
|
||||
},
|
||||
Atomic(Scalar),
|
||||
Pointer {
|
||||
@ -282,6 +285,7 @@ pub enum StatementKind<'a> {
|
||||
Increment(Handle<Expression<'a>>),
|
||||
Decrement(Handle<Expression<'a>>),
|
||||
Ignore(Handle<Expression<'a>>),
|
||||
ConstAssert(Handle<Expression<'a>>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -330,7 +334,8 @@ pub enum ConstructorType<'a> {
|
||||
/// `vec3<f32>(1.0)`.
|
||||
Vector {
|
||||
size: crate::VectorSize,
|
||||
scalar: Scalar,
|
||||
ty: Handle<Type<'a>>,
|
||||
ty_span: Span,
|
||||
},
|
||||
|
||||
/// A matrix construction whose component type is inferred from the
|
||||
@ -345,7 +350,8 @@ pub enum ConstructorType<'a> {
|
||||
Matrix {
|
||||
columns: crate::VectorSize,
|
||||
rows: crate::VectorSize,
|
||||
width: crate::Bytes,
|
||||
ty: Handle<Type<'a>>,
|
||||
ty_span: Span,
|
||||
},
|
||||
|
||||
/// An array whose component type and size are inferred from the arguments:
|
||||
@ -460,14 +466,23 @@ pub struct Let<'a> {
|
||||
pub handle: Handle<Local>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LocalConst<'a> {
|
||||
pub name: Ident<'a>,
|
||||
pub ty: Option<Handle<Type<'a>>>,
|
||||
pub init: Handle<Expression<'a>>,
|
||||
pub handle: Handle<Local>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum LocalDecl<'a> {
|
||||
Var(LocalVariable<'a>),
|
||||
Let(Let<'a>),
|
||||
Const(LocalConst<'a>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
/// A placeholder for a local variable declaration.
|
||||
///
|
||||
/// See [`Function::locals`] for more information.
|
||||
/// See [`super::ExpressionContext::locals`] for more information.
|
||||
pub struct Local;
|
||||
|
@ -58,6 +58,8 @@ pub fn map_sampling(word: &str, span: Span) -> Result<crate::Sampling, Error<'_>
|
||||
"center" => Ok(crate::Sampling::Center),
|
||||
"centroid" => Ok(crate::Sampling::Centroid),
|
||||
"sample" => Ok(crate::Sampling::Sample),
|
||||
"first" => Ok(crate::Sampling::First),
|
||||
"either" => Ok(crate::Sampling::Either),
|
||||
_ => Err(Error::UnknownAttribute(span)),
|
||||
}
|
||||
}
|
||||
|
314
third_party/rust/naga/src/front/wgsl/parse/mod.rs
vendored
314
third_party/rust/naga/src/front/wgsl/parse/mod.rs
vendored
@ -31,20 +31,20 @@ struct ExpressionContext<'input, 'temp, 'out> {
|
||||
|
||||
/// A map from identifiers in scope to the locals/arguments they represent.
|
||||
///
|
||||
/// The handles refer to the [`Function::locals`] area; see that field's
|
||||
/// The handles refer to the [`locals`] arena; see that field's
|
||||
/// documentation for details.
|
||||
///
|
||||
/// [`Function::locals`]: ast::Function::locals
|
||||
/// [`locals`]: ExpressionContext::locals
|
||||
local_table: &'temp mut SymbolTable<&'input str, Handle<ast::Local>>,
|
||||
|
||||
/// Local variable and function argument arena for the function we're building.
|
||||
///
|
||||
/// Note that the `Local` here is actually a zero-sized type. The AST keeps
|
||||
/// all the detailed information about locals - names, types, etc. - in
|
||||
/// [`LocalDecl`] statements. For arguments, that information is kept in
|
||||
/// [`arguments`]. This `Arena`'s only role is to assign a unique `Handle`
|
||||
/// to each of them, and track their definitions' spans for use in
|
||||
/// diagnostics.
|
||||
/// Note that the [`ast::Local`] here is actually a zero-sized type. This
|
||||
/// `Arena`'s only role is to assign a unique `Handle` to each local
|
||||
/// identifier, and track its definition's span for use in diagnostics. All
|
||||
/// the detailed information about locals - names, types, etc. - is kept in
|
||||
/// the [`LocalDecl`] statements we parsed from their declarations. For
|
||||
/// arguments, that information is kept in [`arguments`].
|
||||
///
|
||||
/// In the AST, when an [`Ident`] expression refers to a local variable or
|
||||
/// argument, its [`IdentExpr`] holds the referent's `Handle<Local>` in this
|
||||
@ -53,14 +53,15 @@ struct ExpressionContext<'input, 'temp, 'out> {
|
||||
/// During lowering, [`LocalDecl`] statements add entries to a per-function
|
||||
/// table that maps `Handle<Local>` values to their Naga representations,
|
||||
/// accessed via [`StatementContext::local_table`] and
|
||||
/// [`RuntimeExpressionContext::local_table`]. This table is then consulted when
|
||||
/// [`LocalExpressionContext::local_table`]. This table is then consulted when
|
||||
/// lowering subsequent [`Ident`] expressions.
|
||||
///
|
||||
/// [`LocalDecl`]: StatementKind::LocalDecl
|
||||
/// [`arguments`]: Function::arguments
|
||||
/// [`Ident`]: Expression::Ident
|
||||
/// [`StatementContext::local_table`]: StatementContext::local_table
|
||||
/// [`RuntimeExpressionContext::local_table`]: RuntimeExpressionContext::local_table
|
||||
/// [`LocalDecl`]: ast::StatementKind::LocalDecl
|
||||
/// [`arguments`]: ast::Function::arguments
|
||||
/// [`Ident`]: ast::Expression::Ident
|
||||
/// [`IdentExpr`]: ast::IdentExpr
|
||||
/// [`StatementContext::local_table`]: super::lower::StatementContext::local_table
|
||||
/// [`LocalExpressionContext::local_table`]: super::lower::LocalExpressionContext::local_table
|
||||
locals: &'out mut Arena<ast::Local>,
|
||||
|
||||
/// Identifiers used by the current global declaration that have no local definition.
|
||||
@ -111,6 +112,11 @@ impl<'a> ExpressionContext<'a, '_, '_> {
|
||||
Ok(handle)
|
||||
}
|
||||
}
|
||||
|
||||
fn new_scalar(&mut self, scalar: Scalar) -> Handle<ast::Type<'a>> {
|
||||
self.types
|
||||
.append(ast::Type::Scalar(scalar), Span::UNDEFINED)
|
||||
}
|
||||
}
|
||||
|
||||
/// Which grammar rule we are in the midst of parsing.
|
||||
@ -310,25 +316,22 @@ impl Parser {
|
||||
"vec2i" => {
|
||||
return Ok(Some(ast::ConstructorType::Vector {
|
||||
size: crate::VectorSize::Bi,
|
||||
scalar: Scalar {
|
||||
kind: crate::ScalarKind::Sint,
|
||||
width: 4,
|
||||
},
|
||||
ty: ctx.new_scalar(Scalar::I32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
}))
|
||||
}
|
||||
"vec2u" => {
|
||||
return Ok(Some(ast::ConstructorType::Vector {
|
||||
size: crate::VectorSize::Bi,
|
||||
scalar: Scalar {
|
||||
kind: crate::ScalarKind::Uint,
|
||||
width: 4,
|
||||
},
|
||||
ty: ctx.new_scalar(Scalar::U32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
}))
|
||||
}
|
||||
"vec2f" => {
|
||||
return Ok(Some(ast::ConstructorType::Vector {
|
||||
size: crate::VectorSize::Bi,
|
||||
scalar: Scalar::F32,
|
||||
ty: ctx.new_scalar(Scalar::F32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
}))
|
||||
}
|
||||
"vec3" => ast::ConstructorType::PartialVector {
|
||||
@ -337,19 +340,22 @@ impl Parser {
|
||||
"vec3i" => {
|
||||
return Ok(Some(ast::ConstructorType::Vector {
|
||||
size: crate::VectorSize::Tri,
|
||||
scalar: Scalar::I32,
|
||||
ty: ctx.new_scalar(Scalar::I32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
}))
|
||||
}
|
||||
"vec3u" => {
|
||||
return Ok(Some(ast::ConstructorType::Vector {
|
||||
size: crate::VectorSize::Tri,
|
||||
scalar: Scalar::U32,
|
||||
ty: ctx.new_scalar(Scalar::U32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
}))
|
||||
}
|
||||
"vec3f" => {
|
||||
return Ok(Some(ast::ConstructorType::Vector {
|
||||
size: crate::VectorSize::Tri,
|
||||
scalar: Scalar::F32,
|
||||
ty: ctx.new_scalar(Scalar::F32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
}))
|
||||
}
|
||||
"vec4" => ast::ConstructorType::PartialVector {
|
||||
@ -358,19 +364,22 @@ impl Parser {
|
||||
"vec4i" => {
|
||||
return Ok(Some(ast::ConstructorType::Vector {
|
||||
size: crate::VectorSize::Quad,
|
||||
scalar: Scalar::I32,
|
||||
ty: ctx.new_scalar(Scalar::I32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
}))
|
||||
}
|
||||
"vec4u" => {
|
||||
return Ok(Some(ast::ConstructorType::Vector {
|
||||
size: crate::VectorSize::Quad,
|
||||
scalar: Scalar::U32,
|
||||
ty: ctx.new_scalar(Scalar::U32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
}))
|
||||
}
|
||||
"vec4f" => {
|
||||
return Ok(Some(ast::ConstructorType::Vector {
|
||||
size: crate::VectorSize::Quad,
|
||||
scalar: Scalar::F32,
|
||||
ty: ctx.new_scalar(Scalar::F32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
}))
|
||||
}
|
||||
"mat2x2" => ast::ConstructorType::PartialMatrix {
|
||||
@ -381,7 +390,8 @@ impl Parser {
|
||||
return Ok(Some(ast::ConstructorType::Matrix {
|
||||
columns: crate::VectorSize::Bi,
|
||||
rows: crate::VectorSize::Bi,
|
||||
width: 4,
|
||||
ty: ctx.new_scalar(Scalar::F32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
}))
|
||||
}
|
||||
"mat2x3" => ast::ConstructorType::PartialMatrix {
|
||||
@ -392,7 +402,8 @@ impl Parser {
|
||||
return Ok(Some(ast::ConstructorType::Matrix {
|
||||
columns: crate::VectorSize::Bi,
|
||||
rows: crate::VectorSize::Tri,
|
||||
width: 4,
|
||||
ty: ctx.new_scalar(Scalar::F32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
}))
|
||||
}
|
||||
"mat2x4" => ast::ConstructorType::PartialMatrix {
|
||||
@ -403,7 +414,8 @@ impl Parser {
|
||||
return Ok(Some(ast::ConstructorType::Matrix {
|
||||
columns: crate::VectorSize::Bi,
|
||||
rows: crate::VectorSize::Quad,
|
||||
width: 4,
|
||||
ty: ctx.new_scalar(Scalar::F32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
}))
|
||||
}
|
||||
"mat3x2" => ast::ConstructorType::PartialMatrix {
|
||||
@ -414,7 +426,8 @@ impl Parser {
|
||||
return Ok(Some(ast::ConstructorType::Matrix {
|
||||
columns: crate::VectorSize::Tri,
|
||||
rows: crate::VectorSize::Bi,
|
||||
width: 4,
|
||||
ty: ctx.new_scalar(Scalar::F32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
}))
|
||||
}
|
||||
"mat3x3" => ast::ConstructorType::PartialMatrix {
|
||||
@ -425,7 +438,8 @@ impl Parser {
|
||||
return Ok(Some(ast::ConstructorType::Matrix {
|
||||
columns: crate::VectorSize::Tri,
|
||||
rows: crate::VectorSize::Tri,
|
||||
width: 4,
|
||||
ty: ctx.new_scalar(Scalar::F32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
}))
|
||||
}
|
||||
"mat3x4" => ast::ConstructorType::PartialMatrix {
|
||||
@ -436,7 +450,8 @@ impl Parser {
|
||||
return Ok(Some(ast::ConstructorType::Matrix {
|
||||
columns: crate::VectorSize::Tri,
|
||||
rows: crate::VectorSize::Quad,
|
||||
width: 4,
|
||||
ty: ctx.new_scalar(Scalar::F32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
}))
|
||||
}
|
||||
"mat4x2" => ast::ConstructorType::PartialMatrix {
|
||||
@ -447,7 +462,8 @@ impl Parser {
|
||||
return Ok(Some(ast::ConstructorType::Matrix {
|
||||
columns: crate::VectorSize::Quad,
|
||||
rows: crate::VectorSize::Bi,
|
||||
width: 4,
|
||||
ty: ctx.new_scalar(Scalar::F32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
}))
|
||||
}
|
||||
"mat4x3" => ast::ConstructorType::PartialMatrix {
|
||||
@ -458,7 +474,8 @@ impl Parser {
|
||||
return Ok(Some(ast::ConstructorType::Matrix {
|
||||
columns: crate::VectorSize::Quad,
|
||||
rows: crate::VectorSize::Tri,
|
||||
width: 4,
|
||||
ty: ctx.new_scalar(Scalar::F32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
}))
|
||||
}
|
||||
"mat4x4" => ast::ConstructorType::PartialMatrix {
|
||||
@ -469,7 +486,8 @@ impl Parser {
|
||||
return Ok(Some(ast::ConstructorType::Matrix {
|
||||
columns: crate::VectorSize::Quad,
|
||||
rows: crate::VectorSize::Quad,
|
||||
width: 4,
|
||||
ty: ctx.new_scalar(Scalar::F32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
}))
|
||||
}
|
||||
"array" => ast::ConstructorType::PartialArray,
|
||||
@ -502,19 +520,17 @@ impl Parser {
|
||||
// parse component type if present
|
||||
match (lexer.peek().0, partial) {
|
||||
(Token::Paren('<'), ast::ConstructorType::PartialVector { size }) => {
|
||||
let scalar = lexer.next_scalar_generic()?;
|
||||
Ok(Some(ast::ConstructorType::Vector { size, scalar }))
|
||||
let (ty, ty_span) = self.singular_generic(lexer, ctx)?;
|
||||
Ok(Some(ast::ConstructorType::Vector { size, ty, ty_span }))
|
||||
}
|
||||
(Token::Paren('<'), ast::ConstructorType::PartialMatrix { columns, rows }) => {
|
||||
let (scalar, span) = lexer.next_scalar_generic_with_span()?;
|
||||
match scalar.kind {
|
||||
crate::ScalarKind::Float => Ok(Some(ast::ConstructorType::Matrix {
|
||||
columns,
|
||||
rows,
|
||||
width: scalar.width,
|
||||
})),
|
||||
_ => Err(Error::BadMatrixScalarKind(span, scalar)),
|
||||
}
|
||||
let (ty, ty_span) = self.singular_generic(lexer, ctx)?;
|
||||
Ok(Some(ast::ConstructorType::Matrix {
|
||||
columns,
|
||||
rows,
|
||||
ty,
|
||||
ty_span,
|
||||
}))
|
||||
}
|
||||
(Token::Paren('<'), ast::ConstructorType::PartialArray) => {
|
||||
lexer.expect_generic_paren('<')?;
|
||||
@ -570,11 +586,7 @@ impl Parser {
|
||||
let expr = match name {
|
||||
// bitcast looks like a function call, but it's an operator and must be handled differently.
|
||||
"bitcast" => {
|
||||
lexer.expect_generic_paren('<')?;
|
||||
let start = lexer.start_byte_offset();
|
||||
let to = self.type_decl(lexer, ctx)?;
|
||||
let span = lexer.span_from(start);
|
||||
lexer.expect_generic_paren('>')?;
|
||||
let (to, span) = self.singular_generic(lexer, ctx)?;
|
||||
|
||||
lexer.open_arguments()?;
|
||||
let expr = self.general_expression(lexer, ctx)?;
|
||||
@ -980,8 +992,12 @@ impl Parser {
|
||||
lexer.expect(Token::Paren('>'))?;
|
||||
}
|
||||
let name = lexer.next_ident()?;
|
||||
lexer.expect(Token::Separator(':'))?;
|
||||
let ty = self.type_decl(lexer, ctx)?;
|
||||
|
||||
let ty = if lexer.skip(Token::Separator(':')) {
|
||||
Some(self.type_decl(lexer, ctx)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let init = if lexer.skip(Token::Operation('=')) {
|
||||
let handle = self.general_expression(lexer, ctx)?;
|
||||
@ -1058,21 +1074,34 @@ impl Parser {
|
||||
Ok(members)
|
||||
}
|
||||
|
||||
fn matrix_scalar_type<'a>(
|
||||
/// Parses `<T>`, returning T and span of T
|
||||
fn singular_generic<'a>(
|
||||
&mut self,
|
||||
lexer: &mut Lexer<'a>,
|
||||
ctx: &mut ExpressionContext<'a, '_, '_>,
|
||||
) -> Result<(Handle<ast::Type<'a>>, Span), Error<'a>> {
|
||||
lexer.expect_generic_paren('<')?;
|
||||
let start = lexer.start_byte_offset();
|
||||
let ty = self.type_decl(lexer, ctx)?;
|
||||
let span = lexer.span_from(start);
|
||||
lexer.expect_generic_paren('>')?;
|
||||
Ok((ty, span))
|
||||
}
|
||||
|
||||
fn matrix_with_type<'a>(
|
||||
&mut self,
|
||||
lexer: &mut Lexer<'a>,
|
||||
ctx: &mut ExpressionContext<'a, '_, '_>,
|
||||
columns: crate::VectorSize,
|
||||
rows: crate::VectorSize,
|
||||
) -> Result<ast::Type<'a>, Error<'a>> {
|
||||
let (scalar, span) = lexer.next_scalar_generic_with_span()?;
|
||||
match scalar.kind {
|
||||
crate::ScalarKind::Float => Ok(ast::Type::Matrix {
|
||||
columns,
|
||||
rows,
|
||||
width: scalar.width,
|
||||
}),
|
||||
_ => Err(Error::BadMatrixScalarKind(span, scalar)),
|
||||
}
|
||||
let (ty, ty_span) = self.singular_generic(lexer, ctx)?;
|
||||
Ok(ast::Type::Matrix {
|
||||
columns,
|
||||
rows,
|
||||
ty,
|
||||
ty_span,
|
||||
})
|
||||
}
|
||||
|
||||
fn type_decl_impl<'a>(
|
||||
@ -1087,151 +1116,154 @@ impl Parser {
|
||||
|
||||
Ok(Some(match word {
|
||||
"vec2" => {
|
||||
let scalar = lexer.next_scalar_generic()?;
|
||||
let (ty, ty_span) = self.singular_generic(lexer, ctx)?;
|
||||
ast::Type::Vector {
|
||||
size: crate::VectorSize::Bi,
|
||||
scalar,
|
||||
ty,
|
||||
ty_span,
|
||||
}
|
||||
}
|
||||
"vec2i" => ast::Type::Vector {
|
||||
size: crate::VectorSize::Bi,
|
||||
scalar: Scalar {
|
||||
kind: crate::ScalarKind::Sint,
|
||||
width: 4,
|
||||
},
|
||||
ty: ctx.new_scalar(Scalar::I32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
},
|
||||
"vec2u" => ast::Type::Vector {
|
||||
size: crate::VectorSize::Bi,
|
||||
scalar: Scalar {
|
||||
kind: crate::ScalarKind::Uint,
|
||||
width: 4,
|
||||
},
|
||||
ty: ctx.new_scalar(Scalar::U32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
},
|
||||
"vec2f" => ast::Type::Vector {
|
||||
size: crate::VectorSize::Bi,
|
||||
scalar: Scalar::F32,
|
||||
ty: ctx.new_scalar(Scalar::F32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
},
|
||||
"vec3" => {
|
||||
let scalar = lexer.next_scalar_generic()?;
|
||||
let (ty, ty_span) = self.singular_generic(lexer, ctx)?;
|
||||
ast::Type::Vector {
|
||||
size: crate::VectorSize::Tri,
|
||||
scalar,
|
||||
ty,
|
||||
ty_span,
|
||||
}
|
||||
}
|
||||
"vec3i" => ast::Type::Vector {
|
||||
size: crate::VectorSize::Tri,
|
||||
scalar: Scalar {
|
||||
kind: crate::ScalarKind::Sint,
|
||||
width: 4,
|
||||
},
|
||||
ty: ctx.new_scalar(Scalar::I32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
},
|
||||
"vec3u" => ast::Type::Vector {
|
||||
size: crate::VectorSize::Tri,
|
||||
scalar: Scalar {
|
||||
kind: crate::ScalarKind::Uint,
|
||||
width: 4,
|
||||
},
|
||||
ty: ctx.new_scalar(Scalar::U32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
},
|
||||
"vec3f" => ast::Type::Vector {
|
||||
size: crate::VectorSize::Tri,
|
||||
scalar: Scalar::F32,
|
||||
ty: ctx.new_scalar(Scalar::F32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
},
|
||||
"vec4" => {
|
||||
let scalar = lexer.next_scalar_generic()?;
|
||||
let (ty, ty_span) = self.singular_generic(lexer, ctx)?;
|
||||
ast::Type::Vector {
|
||||
size: crate::VectorSize::Quad,
|
||||
scalar,
|
||||
ty,
|
||||
ty_span,
|
||||
}
|
||||
}
|
||||
"vec4i" => ast::Type::Vector {
|
||||
size: crate::VectorSize::Quad,
|
||||
scalar: Scalar {
|
||||
kind: crate::ScalarKind::Sint,
|
||||
width: 4,
|
||||
},
|
||||
ty: ctx.new_scalar(Scalar::I32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
},
|
||||
"vec4u" => ast::Type::Vector {
|
||||
size: crate::VectorSize::Quad,
|
||||
scalar: Scalar {
|
||||
kind: crate::ScalarKind::Uint,
|
||||
width: 4,
|
||||
},
|
||||
ty: ctx.new_scalar(Scalar::U32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
},
|
||||
"vec4f" => ast::Type::Vector {
|
||||
size: crate::VectorSize::Quad,
|
||||
scalar: Scalar::F32,
|
||||
ty: ctx.new_scalar(Scalar::F32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
},
|
||||
"mat2x2" => {
|
||||
self.matrix_scalar_type(lexer, crate::VectorSize::Bi, crate::VectorSize::Bi)?
|
||||
self.matrix_with_type(lexer, ctx, crate::VectorSize::Bi, crate::VectorSize::Bi)?
|
||||
}
|
||||
"mat2x2f" => ast::Type::Matrix {
|
||||
columns: crate::VectorSize::Bi,
|
||||
rows: crate::VectorSize::Bi,
|
||||
width: 4,
|
||||
ty: ctx.new_scalar(Scalar::F32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
},
|
||||
"mat2x3" => {
|
||||
self.matrix_scalar_type(lexer, crate::VectorSize::Bi, crate::VectorSize::Tri)?
|
||||
self.matrix_with_type(lexer, ctx, crate::VectorSize::Bi, crate::VectorSize::Tri)?
|
||||
}
|
||||
"mat2x3f" => ast::Type::Matrix {
|
||||
columns: crate::VectorSize::Bi,
|
||||
rows: crate::VectorSize::Tri,
|
||||
width: 4,
|
||||
ty: ctx.new_scalar(Scalar::F32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
},
|
||||
"mat2x4" => {
|
||||
self.matrix_scalar_type(lexer, crate::VectorSize::Bi, crate::VectorSize::Quad)?
|
||||
self.matrix_with_type(lexer, ctx, crate::VectorSize::Bi, crate::VectorSize::Quad)?
|
||||
}
|
||||
"mat2x4f" => ast::Type::Matrix {
|
||||
columns: crate::VectorSize::Bi,
|
||||
rows: crate::VectorSize::Quad,
|
||||
width: 4,
|
||||
ty: ctx.new_scalar(Scalar::F32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
},
|
||||
"mat3x2" => {
|
||||
self.matrix_scalar_type(lexer, crate::VectorSize::Tri, crate::VectorSize::Bi)?
|
||||
self.matrix_with_type(lexer, ctx, crate::VectorSize::Tri, crate::VectorSize::Bi)?
|
||||
}
|
||||
"mat3x2f" => ast::Type::Matrix {
|
||||
columns: crate::VectorSize::Tri,
|
||||
rows: crate::VectorSize::Bi,
|
||||
width: 4,
|
||||
ty: ctx.new_scalar(Scalar::F32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
},
|
||||
"mat3x3" => {
|
||||
self.matrix_scalar_type(lexer, crate::VectorSize::Tri, crate::VectorSize::Tri)?
|
||||
self.matrix_with_type(lexer, ctx, crate::VectorSize::Tri, crate::VectorSize::Tri)?
|
||||
}
|
||||
"mat3x3f" => ast::Type::Matrix {
|
||||
columns: crate::VectorSize::Tri,
|
||||
rows: crate::VectorSize::Tri,
|
||||
width: 4,
|
||||
ty: ctx.new_scalar(Scalar::F32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
},
|
||||
"mat3x4" => {
|
||||
self.matrix_scalar_type(lexer, crate::VectorSize::Tri, crate::VectorSize::Quad)?
|
||||
self.matrix_with_type(lexer, ctx, crate::VectorSize::Tri, crate::VectorSize::Quad)?
|
||||
}
|
||||
"mat3x4f" => ast::Type::Matrix {
|
||||
columns: crate::VectorSize::Tri,
|
||||
rows: crate::VectorSize::Quad,
|
||||
width: 4,
|
||||
ty: ctx.new_scalar(Scalar::F32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
},
|
||||
"mat4x2" => {
|
||||
self.matrix_scalar_type(lexer, crate::VectorSize::Quad, crate::VectorSize::Bi)?
|
||||
self.matrix_with_type(lexer, ctx, crate::VectorSize::Quad, crate::VectorSize::Bi)?
|
||||
}
|
||||
"mat4x2f" => ast::Type::Matrix {
|
||||
columns: crate::VectorSize::Quad,
|
||||
rows: crate::VectorSize::Bi,
|
||||
width: 4,
|
||||
ty: ctx.new_scalar(Scalar::F32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
},
|
||||
"mat4x3" => {
|
||||
self.matrix_scalar_type(lexer, crate::VectorSize::Quad, crate::VectorSize::Tri)?
|
||||
self.matrix_with_type(lexer, ctx, crate::VectorSize::Quad, crate::VectorSize::Tri)?
|
||||
}
|
||||
"mat4x3f" => ast::Type::Matrix {
|
||||
columns: crate::VectorSize::Quad,
|
||||
rows: crate::VectorSize::Tri,
|
||||
width: 4,
|
||||
ty: ctx.new_scalar(Scalar::F32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
},
|
||||
"mat4x4" => {
|
||||
self.matrix_scalar_type(lexer, crate::VectorSize::Quad, crate::VectorSize::Quad)?
|
||||
self.matrix_with_type(lexer, ctx, crate::VectorSize::Quad, crate::VectorSize::Quad)?
|
||||
}
|
||||
"mat4x4f" => ast::Type::Matrix {
|
||||
columns: crate::VectorSize::Quad,
|
||||
rows: crate::VectorSize::Quad,
|
||||
width: 4,
|
||||
ty: ctx.new_scalar(Scalar::F32),
|
||||
ty_span: Span::UNDEFINED,
|
||||
},
|
||||
"atomic" => {
|
||||
let scalar = lexer.next_scalar_generic()?;
|
||||
@ -1688,6 +1720,28 @@ impl Parser {
|
||||
handle,
|
||||
}))
|
||||
}
|
||||
"const" => {
|
||||
let _ = lexer.next();
|
||||
let name = lexer.next_ident()?;
|
||||
|
||||
let given_ty = if lexer.skip(Token::Separator(':')) {
|
||||
let ty = self.type_decl(lexer, ctx)?;
|
||||
Some(ty)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
lexer.expect(Token::Operation('='))?;
|
||||
let expr_id = self.general_expression(lexer, ctx)?;
|
||||
lexer.expect(Token::Separator(';'))?;
|
||||
|
||||
let handle = ctx.declare_local(name)?;
|
||||
ast::StatementKind::LocalDecl(ast::LocalDecl::Const(ast::LocalConst {
|
||||
name,
|
||||
ty: given_ty,
|
||||
init: expr_id,
|
||||
handle,
|
||||
}))
|
||||
}
|
||||
"var" => {
|
||||
let _ = lexer.next();
|
||||
|
||||
@ -1963,6 +2017,20 @@ impl Parser {
|
||||
lexer.expect(Token::Separator(';'))?;
|
||||
ast::StatementKind::Kill
|
||||
}
|
||||
// https://www.w3.org/TR/WGSL/#const-assert-statement
|
||||
"const_assert" => {
|
||||
let _ = lexer.next();
|
||||
// parentheses are optional
|
||||
let paren = lexer.skip(Token::Paren('('));
|
||||
|
||||
let condition = self.general_expression(lexer, ctx)?;
|
||||
|
||||
if paren {
|
||||
lexer.expect(Token::Paren(')'))?;
|
||||
}
|
||||
lexer.expect(Token::Separator(';'))?;
|
||||
ast::StatementKind::ConstAssert(condition)
|
||||
}
|
||||
// assignment or a function call
|
||||
_ => {
|
||||
self.function_call_or_assignment_statement(lexer, ctx, block)?;
|
||||
@ -2366,6 +2434,18 @@ impl Parser {
|
||||
..function
|
||||
}))
|
||||
}
|
||||
(Token::Word("const_assert"), _) => {
|
||||
// parentheses are optional
|
||||
let paren = lexer.skip(Token::Paren('('));
|
||||
|
||||
let condition = self.general_expression(lexer, &mut ctx)?;
|
||||
|
||||
if paren {
|
||||
lexer.expect(Token::Paren(')'))?;
|
||||
}
|
||||
lexer.expect(Token::Separator(';'))?;
|
||||
Some(ast::GlobalDeclKind::ConstAssert(condition))
|
||||
}
|
||||
(Token::End, _) => return Ok(()),
|
||||
other => return Err(Error::Unexpected(other.1, ExpectedToken::GlobalItem)),
|
||||
};
|
||||
|
7
third_party/rust/naga/src/lib.rs
vendored
7
third_party/rust/naga/src/lib.rs
vendored
@ -530,6 +530,13 @@ pub enum Sampling {
|
||||
/// Interpolate the value at each sample location. In multisampling, invoke
|
||||
/// the fragment shader once per sample.
|
||||
Sample,
|
||||
|
||||
/// Use the value provided by the first vertex of the current primitive.
|
||||
First,
|
||||
|
||||
/// Use the value provided by the first or last vertex of the current primitive. The exact
|
||||
/// choice is implementation-dependent.
|
||||
Either,
|
||||
}
|
||||
|
||||
/// Member of a user-defined structure.
|
||||
|
120
third_party/rust/naga/src/proc/constant_evaluator.rs
vendored
120
third_party/rust/naga/src/proc/constant_evaluator.rs
vendored
@ -317,7 +317,7 @@ pub struct ConstantEvaluator<'a> {
|
||||
#[derive(Debug)]
|
||||
enum WgslRestrictions<'a> {
|
||||
/// - const-expressions will be evaluated and inserted in the arena
|
||||
Const,
|
||||
Const(Option<FunctionLocalData<'a>>),
|
||||
/// - const-expressions will be evaluated and inserted in the arena
|
||||
/// - override-expressions will be inserted in the arena
|
||||
Override,
|
||||
@ -347,6 +347,8 @@ struct FunctionLocalData<'a> {
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
||||
pub enum ExpressionKind {
|
||||
/// If const is also implemented as const
|
||||
ImplConst,
|
||||
Const,
|
||||
Override,
|
||||
Runtime,
|
||||
@ -372,14 +374,23 @@ impl ExpressionKindTracker {
|
||||
pub fn insert(&mut self, value: Handle<Expression>, expr_type: ExpressionKind) {
|
||||
self.inner.insert(value, expr_type);
|
||||
}
|
||||
|
||||
pub fn is_const(&self, h: Handle<Expression>) -> bool {
|
||||
matches!(self.type_of(h), ExpressionKind::Const)
|
||||
matches!(
|
||||
self.type_of(h),
|
||||
ExpressionKind::Const | ExpressionKind::ImplConst
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns `true` if naga can also evaluate expression as const
|
||||
pub fn is_impl_const(&self, h: Handle<Expression>) -> bool {
|
||||
matches!(self.type_of(h), ExpressionKind::ImplConst)
|
||||
}
|
||||
|
||||
pub fn is_const_or_override(&self, h: Handle<Expression>) -> bool {
|
||||
matches!(
|
||||
self.type_of(h),
|
||||
ExpressionKind::Const | ExpressionKind::Override
|
||||
ExpressionKind::Const | ExpressionKind::Override | ExpressionKind::ImplConst
|
||||
)
|
||||
}
|
||||
|
||||
@ -400,13 +411,14 @@ impl ExpressionKindTracker {
|
||||
}
|
||||
|
||||
fn type_of_with_expr(&self, expr: &Expression) -> ExpressionKind {
|
||||
use crate::MathFunction as Mf;
|
||||
match *expr {
|
||||
Expression::Literal(_) | Expression::ZeroValue(_) | Expression::Constant(_) => {
|
||||
ExpressionKind::Const
|
||||
ExpressionKind::ImplConst
|
||||
}
|
||||
Expression::Override(_) => ExpressionKind::Override,
|
||||
Expression::Compose { ref components, .. } => {
|
||||
let mut expr_type = ExpressionKind::Const;
|
||||
let mut expr_type = ExpressionKind::ImplConst;
|
||||
for component in components {
|
||||
expr_type = expr_type.max(self.type_of(*component))
|
||||
}
|
||||
@ -417,13 +429,16 @@ impl ExpressionKindTracker {
|
||||
Expression::Access { base, index } => self.type_of(base).max(self.type_of(index)),
|
||||
Expression::Swizzle { vector, .. } => self.type_of(vector),
|
||||
Expression::Unary { expr, .. } => self.type_of(expr),
|
||||
Expression::Binary { left, right, .. } => self.type_of(left).max(self.type_of(right)),
|
||||
Expression::Binary { left, right, .. } => self
|
||||
.type_of(left)
|
||||
.max(self.type_of(right))
|
||||
.max(ExpressionKind::Const),
|
||||
Expression::Math {
|
||||
fun,
|
||||
arg,
|
||||
arg1,
|
||||
arg2,
|
||||
arg3,
|
||||
..
|
||||
} => self
|
||||
.type_of(arg)
|
||||
.max(
|
||||
@ -437,8 +452,34 @@ impl ExpressionKindTracker {
|
||||
.max(
|
||||
arg3.map(|arg| self.type_of(arg))
|
||||
.unwrap_or(ExpressionKind::Const),
|
||||
)
|
||||
.max(
|
||||
if matches!(
|
||||
fun,
|
||||
Mf::Dot
|
||||
| Mf::Outer
|
||||
| Mf::Cross
|
||||
| Mf::Distance
|
||||
| Mf::Length
|
||||
| Mf::Normalize
|
||||
| Mf::FaceForward
|
||||
| Mf::Reflect
|
||||
| Mf::Refract
|
||||
| Mf::Ldexp
|
||||
| Mf::Modf
|
||||
| Mf::Mix
|
||||
| Mf::Frexp
|
||||
) {
|
||||
ExpressionKind::Const
|
||||
} else {
|
||||
ExpressionKind::ImplConst
|
||||
},
|
||||
),
|
||||
Expression::As { expr, .. } => self.type_of(expr),
|
||||
Expression::As { convert, expr, .. } => self.type_of(expr).max(if convert.is_some() {
|
||||
ExpressionKind::ImplConst
|
||||
} else {
|
||||
ExpressionKind::Const
|
||||
}),
|
||||
Expression::Select {
|
||||
condition,
|
||||
accept,
|
||||
@ -446,7 +487,8 @@ impl ExpressionKindTracker {
|
||||
} => self
|
||||
.type_of(condition)
|
||||
.max(self.type_of(accept))
|
||||
.max(self.type_of(reject)),
|
||||
.max(self.type_of(reject))
|
||||
.max(ExpressionKind::Const),
|
||||
Expression::Relational { argument, .. } => self.type_of(argument),
|
||||
Expression::ArrayLength(expr) => self.type_of(expr),
|
||||
_ => ExpressionKind::Runtime,
|
||||
@ -556,7 +598,7 @@ impl<'a> ConstantEvaluator<'a> {
|
||||
Behavior::Wgsl(if in_override_ctx {
|
||||
WgslRestrictions::Override
|
||||
} else {
|
||||
WgslRestrictions::Const
|
||||
WgslRestrictions::Const(None)
|
||||
}),
|
||||
module,
|
||||
global_expression_kind_tracker,
|
||||
@ -603,13 +645,19 @@ impl<'a> ConstantEvaluator<'a> {
|
||||
local_expression_kind_tracker: &'a mut ExpressionKindTracker,
|
||||
emitter: &'a mut super::Emitter,
|
||||
block: &'a mut crate::Block,
|
||||
is_const: bool,
|
||||
) -> Self {
|
||||
let local_data = FunctionLocalData {
|
||||
global_expressions: &module.global_expressions,
|
||||
emitter,
|
||||
block,
|
||||
};
|
||||
Self {
|
||||
behavior: Behavior::Wgsl(WgslRestrictions::Runtime(FunctionLocalData {
|
||||
global_expressions: &module.global_expressions,
|
||||
emitter,
|
||||
block,
|
||||
})),
|
||||
behavior: Behavior::Wgsl(if is_const {
|
||||
WgslRestrictions::Const(Some(local_data))
|
||||
} else {
|
||||
WgslRestrictions::Runtime(local_data)
|
||||
}),
|
||||
types: &mut module.types,
|
||||
constants: &module.constants,
|
||||
overrides: &module.overrides,
|
||||
@ -718,6 +766,7 @@ impl<'a> ConstantEvaluator<'a> {
|
||||
span: Span,
|
||||
) -> Result<Handle<Expression>, ConstantEvaluatorError> {
|
||||
match self.expression_kind_tracker.type_of_with_expr(&expr) {
|
||||
ExpressionKind::ImplConst => self.try_eval_and_append_impl(&expr, span),
|
||||
ExpressionKind::Const => {
|
||||
let eval_result = self.try_eval_and_append_impl(&expr, span);
|
||||
// We should be able to evaluate `Const` expressions at this
|
||||
@ -740,7 +789,7 @@ impl<'a> ConstantEvaluator<'a> {
|
||||
Behavior::Wgsl(WgslRestrictions::Override | WgslRestrictions::Runtime(_)) => {
|
||||
Ok(self.append_expr(expr, span, ExpressionKind::Override))
|
||||
}
|
||||
Behavior::Wgsl(WgslRestrictions::Const) => {
|
||||
Behavior::Wgsl(WgslRestrictions::Const(_)) => {
|
||||
Err(ConstantEvaluatorError::OverrideExpr)
|
||||
}
|
||||
Behavior::Glsl(_) => {
|
||||
@ -761,14 +810,17 @@ impl<'a> ConstantEvaluator<'a> {
|
||||
const fn is_global_arena(&self) -> bool {
|
||||
matches!(
|
||||
self.behavior,
|
||||
Behavior::Wgsl(WgslRestrictions::Const | WgslRestrictions::Override)
|
||||
Behavior::Wgsl(WgslRestrictions::Const(None) | WgslRestrictions::Override)
|
||||
| Behavior::Glsl(GlslRestrictions::Const)
|
||||
)
|
||||
}
|
||||
|
||||
const fn function_local_data(&self) -> Option<&FunctionLocalData<'a>> {
|
||||
match self.behavior {
|
||||
Behavior::Wgsl(WgslRestrictions::Runtime(ref function_local_data))
|
||||
Behavior::Wgsl(
|
||||
WgslRestrictions::Runtime(ref function_local_data)
|
||||
| WgslRestrictions::Const(Some(ref function_local_data)),
|
||||
)
|
||||
| Behavior::Glsl(GlslRestrictions::Runtime(ref function_local_data)) => {
|
||||
Some(function_local_data)
|
||||
}
|
||||
@ -1779,9 +1831,13 @@ impl<'a> ConstantEvaluator<'a> {
|
||||
_ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
|
||||
}),
|
||||
(Literal::I32(a), Literal::U32(b)) => Literal::I32(match op {
|
||||
BinaryOperator::ShiftLeft => a
|
||||
.checked_shl(b)
|
||||
.ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?,
|
||||
BinaryOperator::ShiftLeft => {
|
||||
if (if a.is_negative() { !a } else { a }).leading_zeros() <= b {
|
||||
return Err(ConstantEvaluatorError::Overflow("<<".to_string()));
|
||||
}
|
||||
a.checked_shl(b)
|
||||
.ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?
|
||||
}
|
||||
BinaryOperator::ShiftRight => a
|
||||
.checked_shr(b)
|
||||
.ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?,
|
||||
@ -1807,8 +1863,11 @@ impl<'a> ConstantEvaluator<'a> {
|
||||
BinaryOperator::ExclusiveOr => a ^ b,
|
||||
BinaryOperator::InclusiveOr => a | b,
|
||||
BinaryOperator::ShiftLeft => a
|
||||
.checked_shl(b)
|
||||
.ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?,
|
||||
.checked_mul(
|
||||
1u32.checked_shl(b)
|
||||
.ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?,
|
||||
)
|
||||
.ok_or(ConstantEvaluatorError::Overflow("<<".to_string()))?,
|
||||
BinaryOperator::ShiftRight => a
|
||||
.checked_shr(b)
|
||||
.ok_or(ConstantEvaluatorError::ShiftedMoreThan32Bits)?,
|
||||
@ -2057,7 +2116,10 @@ impl<'a> ConstantEvaluator<'a> {
|
||||
expr_type: ExpressionKind,
|
||||
) -> Handle<Expression> {
|
||||
let h = match self.behavior {
|
||||
Behavior::Wgsl(WgslRestrictions::Runtime(ref mut function_local_data))
|
||||
Behavior::Wgsl(
|
||||
WgslRestrictions::Runtime(ref mut function_local_data)
|
||||
| WgslRestrictions::Const(Some(ref mut function_local_data)),
|
||||
)
|
||||
| Behavior::Glsl(GlslRestrictions::Runtime(ref mut function_local_data)) => {
|
||||
let is_running = function_local_data.emitter.is_running();
|
||||
let needs_pre_emit = expr.needs_pre_emit();
|
||||
@ -2480,7 +2542,7 @@ mod tests {
|
||||
|
||||
let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions);
|
||||
let mut solver = ConstantEvaluator {
|
||||
behavior: Behavior::Wgsl(WgslRestrictions::Const),
|
||||
behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
|
||||
types: &mut types,
|
||||
constants: &constants,
|
||||
overrides: &overrides,
|
||||
@ -2566,7 +2628,7 @@ mod tests {
|
||||
|
||||
let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions);
|
||||
let mut solver = ConstantEvaluator {
|
||||
behavior: Behavior::Wgsl(WgslRestrictions::Const),
|
||||
behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
|
||||
types: &mut types,
|
||||
constants: &constants,
|
||||
overrides: &overrides,
|
||||
@ -2684,7 +2746,7 @@ mod tests {
|
||||
|
||||
let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions);
|
||||
let mut solver = ConstantEvaluator {
|
||||
behavior: Behavior::Wgsl(WgslRestrictions::Const),
|
||||
behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
|
||||
types: &mut types,
|
||||
constants: &constants,
|
||||
overrides: &overrides,
|
||||
@ -2777,7 +2839,7 @@ mod tests {
|
||||
|
||||
let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions);
|
||||
let mut solver = ConstantEvaluator {
|
||||
behavior: Behavior::Wgsl(WgslRestrictions::Const),
|
||||
behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
|
||||
types: &mut types,
|
||||
constants: &constants,
|
||||
overrides: &overrides,
|
||||
@ -2859,7 +2921,7 @@ mod tests {
|
||||
|
||||
let expression_kind_tracker = &mut ExpressionKindTracker::from_arena(&global_expressions);
|
||||
let mut solver = ConstantEvaluator {
|
||||
behavior: Behavior::Wgsl(WgslRestrictions::Const),
|
||||
behavior: Behavior::Wgsl(WgslRestrictions::Const(None)),
|
||||
types: &mut types,
|
||||
constants: &constants,
|
||||
overrides: &overrides,
|
||||
|
13
third_party/rust/naga/src/proc/mod.rs
vendored
13
third_party/rust/naga/src/proc/mod.rs
vendored
@ -674,6 +674,19 @@ impl GlobalCtx<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to evaluate the expression in the `arena` using its `handle` and return it as a `bool`.
|
||||
#[allow(dead_code)]
|
||||
pub(super) fn eval_expr_to_bool_from(
|
||||
&self,
|
||||
handle: crate::Handle<crate::Expression>,
|
||||
arena: &crate::Arena<crate::Expression>,
|
||||
) -> Option<bool> {
|
||||
match self.eval_expr_to_literal_from(handle, arena) {
|
||||
Some(crate::Literal::Bool(value)) => Some(value),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn eval_expr_to_literal(
|
||||
&self,
|
||||
|
30
third_party/rust/naga/src/valid/interface.rs
vendored
30
third_party/rust/naga/src/valid/interface.rs
vendored
@ -50,6 +50,11 @@ pub enum VaryingError {
|
||||
NotIOShareableType(Handle<crate::Type>),
|
||||
#[error("Interpolation is not valid")]
|
||||
InvalidInterpolation,
|
||||
#[error("Cannot combine {interpolation:?} interpolation with the {sampling:?} sample type")]
|
||||
InvalidInterpolationSamplingCombination {
|
||||
interpolation: crate::Interpolation,
|
||||
sampling: crate::Sampling,
|
||||
},
|
||||
#[error("Interpolation must be specified on vertex shader outputs and fragment shader inputs")]
|
||||
MissingInterpolation,
|
||||
#[error("Built-in {0:?} is not available at this stage")]
|
||||
@ -339,6 +344,31 @@ impl VaryingContext<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(interpolation) = interpolation {
|
||||
let invalid_sampling = match (interpolation, sampling) {
|
||||
(_, None)
|
||||
| (
|
||||
crate::Interpolation::Perspective | crate::Interpolation::Linear,
|
||||
Some(
|
||||
crate::Sampling::Center
|
||||
| crate::Sampling::Centroid
|
||||
| crate::Sampling::Sample,
|
||||
),
|
||||
)
|
||||
| (
|
||||
crate::Interpolation::Flat,
|
||||
Some(crate::Sampling::First | crate::Sampling::Either),
|
||||
) => None,
|
||||
(_, Some(invalid_sampling)) => Some(invalid_sampling),
|
||||
};
|
||||
if let Some(sampling) = invalid_sampling {
|
||||
return Err(VaryingError::InvalidInterpolationSamplingCombination {
|
||||
interpolation,
|
||||
sampling,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let needs_interpolation = match self.stage {
|
||||
crate::ShaderStage::Vertex => self.output,
|
||||
crate::ShaderStage::Fragment => !self.output,
|
||||
|
File diff suppressed because one or more lines are too long
10
third_party/rust/wgpu-core/src/binding_model.rs
vendored
10
third_party/rust/wgpu-core/src/binding_model.rs
vendored
@ -884,6 +884,16 @@ pub(crate) fn buffer_binding_type_alignment(
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn buffer_binding_type_bounds_check_alignment(
|
||||
alignments: &hal::Alignments,
|
||||
binding_type: wgt::BufferBindingType,
|
||||
) -> wgt::BufferAddress {
|
||||
match binding_type {
|
||||
wgt::BufferBindingType::Uniform => alignments.uniform_bounds_check_alignment.get(),
|
||||
wgt::BufferBindingType::Storage { .. } => wgt::COPY_BUFFER_ALIGNMENT,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BindGroup {
|
||||
pub(crate) raw: Snatchable<Box<dyn hal::DynBindGroup>>,
|
||||
|
@ -82,8 +82,8 @@ pub(crate) enum CommandEncoderStatus {
|
||||
///
|
||||
/// When a `CommandEncoder` is left in this state, we have also
|
||||
/// returned an error result from the function that encountered
|
||||
/// the problem. Future attempts to use the encoder (that is,
|
||||
/// calls to [`CommandBuffer::get_encoder`]) will also return
|
||||
/// the problem. Future attempts to use the encoder (for example,
|
||||
/// calls to [`CommandBuffer::check_recording`]) will also return
|
||||
/// errors.
|
||||
///
|
||||
/// Calling [`Global::command_encoder_finish`] in this state
|
||||
|
@ -3162,7 +3162,7 @@ impl Global {
|
||||
.map_err(|_| RenderPassErrorInner::InvalidBuffer(buffer_id))
|
||||
.map_pass_err(scope)?;
|
||||
let count_buffer = buffers
|
||||
.get_owned(buffer_id)
|
||||
.get_owned(count_buffer_id)
|
||||
.map_err(|_| RenderPassErrorInner::InvalidBuffer(count_buffer_id))
|
||||
.map_pass_err(scope)?;
|
||||
|
||||
@ -3203,7 +3203,7 @@ impl Global {
|
||||
.map_pass_err(scope)?;
|
||||
|
||||
let count_buffer = buffers
|
||||
.get_owned(buffer_id)
|
||||
.get_owned(count_buffer_id)
|
||||
.map_err(|_| RenderPassErrorInner::InvalidBuffer(count_buffer_id))
|
||||
.map_pass_err(scope)?;
|
||||
|
||||
|
25
third_party/rust/wgpu-core/src/device/global.rs
vendored
25
third_party/rust/wgpu-core/src/device/global.rs
vendored
@ -795,14 +795,14 @@ impl Global {
|
||||
Err(..) => break 'error binding_model::CreateBindGroupError::InvalidLayout,
|
||||
};
|
||||
|
||||
fn map_entry<'a>(
|
||||
fn resolve_entry<'a>(
|
||||
e: &BindGroupEntry<'a>,
|
||||
buffer_storage: &Storage<resource::Buffer>,
|
||||
sampler_storage: &Storage<resource::Sampler>,
|
||||
texture_view_storage: &Storage<resource::TextureView>,
|
||||
) -> Result<ResolvedBindGroupEntry<'a>, binding_model::CreateBindGroupError>
|
||||
{
|
||||
let map_buffer = |bb: &BufferBinding| {
|
||||
let resolve_buffer = |bb: &BufferBinding| {
|
||||
buffer_storage
|
||||
.get_owned(bb.buffer_id)
|
||||
.map(|buffer| ResolvedBufferBinding {
|
||||
@ -814,42 +814,45 @@ impl Global {
|
||||
binding_model::CreateBindGroupError::InvalidBufferId(bb.buffer_id)
|
||||
})
|
||||
};
|
||||
let map_sampler = |id: &id::SamplerId| {
|
||||
let resolve_sampler = |id: &id::SamplerId| {
|
||||
sampler_storage
|
||||
.get_owned(*id)
|
||||
.map_err(|_| binding_model::CreateBindGroupError::InvalidSamplerId(*id))
|
||||
};
|
||||
let map_view = |id: &id::TextureViewId| {
|
||||
let resolve_view = |id: &id::TextureViewId| {
|
||||
texture_view_storage
|
||||
.get_owned(*id)
|
||||
.map_err(|_| binding_model::CreateBindGroupError::InvalidTextureViewId(*id))
|
||||
};
|
||||
let resource = match e.resource {
|
||||
BindingResource::Buffer(ref buffer) => {
|
||||
ResolvedBindingResource::Buffer(map_buffer(buffer)?)
|
||||
ResolvedBindingResource::Buffer(resolve_buffer(buffer)?)
|
||||
}
|
||||
BindingResource::BufferArray(ref buffers) => {
|
||||
let buffers = buffers
|
||||
.iter()
|
||||
.map(map_buffer)
|
||||
.map(resolve_buffer)
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
ResolvedBindingResource::BufferArray(Cow::Owned(buffers))
|
||||
}
|
||||
BindingResource::Sampler(ref sampler) => {
|
||||
ResolvedBindingResource::Sampler(map_sampler(sampler)?)
|
||||
ResolvedBindingResource::Sampler(resolve_sampler(sampler)?)
|
||||
}
|
||||
BindingResource::SamplerArray(ref samplers) => {
|
||||
let samplers = samplers
|
||||
.iter()
|
||||
.map(map_sampler)
|
||||
.map(resolve_sampler)
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
ResolvedBindingResource::SamplerArray(Cow::Owned(samplers))
|
||||
}
|
||||
BindingResource::TextureView(ref view) => {
|
||||
ResolvedBindingResource::TextureView(map_view(view)?)
|
||||
ResolvedBindingResource::TextureView(resolve_view(view)?)
|
||||
}
|
||||
BindingResource::TextureViewArray(ref views) => {
|
||||
let views = views.iter().map(map_view).collect::<Result<Vec<_>, _>>()?;
|
||||
let views = views
|
||||
.iter()
|
||||
.map(resolve_view)
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
ResolvedBindingResource::TextureViewArray(Cow::Owned(views))
|
||||
}
|
||||
};
|
||||
@ -865,7 +868,7 @@ impl Global {
|
||||
let sampler_guard = hub.samplers.read();
|
||||
desc.entries
|
||||
.iter()
|
||||
.map(|e| map_entry(e, &buffer_guard, &sampler_guard, &texture_view_guard))
|
||||
.map(|e| resolve_entry(e, &buffer_guard, &sampler_guard, &texture_view_guard))
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
};
|
||||
let entries = match entries {
|
||||
|
44
third_party/rust/wgpu-core/src/device/mod.rs
vendored
44
third_party/rust/wgpu-core/src/device/mod.rs
vendored
@ -336,19 +336,41 @@ fn map_buffer(
|
||||
|
||||
let mapped = unsafe { std::slice::from_raw_parts_mut(mapping.ptr.as_ptr(), size as usize) };
|
||||
|
||||
for uninitialized in buffer
|
||||
.initialization_status
|
||||
.write()
|
||||
.drain(offset..(size + offset))
|
||||
// We can't call flush_mapped_ranges in this case, so we can't drain the uninitialized ranges either
|
||||
if !mapping.is_coherent
|
||||
&& kind == HostMap::Read
|
||||
&& !buffer.usage.contains(wgt::BufferUsages::MAP_WRITE)
|
||||
{
|
||||
// The mapping's pointer is already offset, however we track the
|
||||
// uninitialized range relative to the buffer's start.
|
||||
let fill_range =
|
||||
(uninitialized.start - offset) as usize..(uninitialized.end - offset) as usize;
|
||||
mapped[fill_range].fill(0);
|
||||
for uninitialized in buffer
|
||||
.initialization_status
|
||||
.write()
|
||||
.uninitialized(offset..(size + offset))
|
||||
{
|
||||
// The mapping's pointer is already offset, however we track the
|
||||
// uninitialized range relative to the buffer's start.
|
||||
let fill_range =
|
||||
(uninitialized.start - offset) as usize..(uninitialized.end - offset) as usize;
|
||||
mapped[fill_range].fill(0);
|
||||
}
|
||||
} else {
|
||||
for uninitialized in buffer
|
||||
.initialization_status
|
||||
.write()
|
||||
.drain(offset..(size + offset))
|
||||
{
|
||||
// The mapping's pointer is already offset, however we track the
|
||||
// uninitialized range relative to the buffer's start.
|
||||
let fill_range =
|
||||
(uninitialized.start - offset) as usize..(uninitialized.end - offset) as usize;
|
||||
mapped[fill_range].fill(0);
|
||||
|
||||
if !mapping.is_coherent && kind == HostMap::Read {
|
||||
unsafe { raw.flush_mapped_ranges(raw_buffer, &[uninitialized]) };
|
||||
// NOTE: This is only possible when MAPPABLE_PRIMARY_BUFFERS is enabled.
|
||||
if !mapping.is_coherent
|
||||
&& kind == HostMap::Read
|
||||
&& buffer.usage.contains(wgt::BufferUsages::MAP_WRITE)
|
||||
{
|
||||
unsafe { raw.flush_mapped_ranges(raw_buffer, &[uninitialized]) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,9 @@ use once_cell::sync::OnceCell;
|
||||
|
||||
use smallvec::SmallVec;
|
||||
use thiserror::Error;
|
||||
use wgt::{DeviceLostReason, TextureFormat, TextureSampleType, TextureViewDimension};
|
||||
use wgt::{
|
||||
math::align_to, DeviceLostReason, TextureFormat, TextureSampleType, TextureViewDimension,
|
||||
};
|
||||
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
@ -1629,7 +1631,7 @@ impl Device {
|
||||
|
||||
/// Generate information about late-validated buffer bindings for pipelines.
|
||||
//TODO: should this be combined with `get_introspection_bind_group_layouts` in some way?
|
||||
pub(crate) fn make_late_sized_buffer_groups(
|
||||
fn make_late_sized_buffer_groups(
|
||||
shader_binding_sizes: &FastHashMap<naga::ResourceBinding, wgt::BufferSize>,
|
||||
layout: &binding_model::PipelineLayout,
|
||||
) -> ArrayVec<pipeline::LateSizedBufferGroup, { hal::MAX_BIND_GROUPS }> {
|
||||
@ -1881,8 +1883,8 @@ impl Device {
|
||||
Ok(bgl)
|
||||
}
|
||||
|
||||
pub(crate) fn create_buffer_binding<'a>(
|
||||
self: &Arc<Self>,
|
||||
fn create_buffer_binding<'a>(
|
||||
&self,
|
||||
bb: &'a binding_model::ResolvedBufferBinding,
|
||||
binding: u32,
|
||||
decl: &wgt::BindGroupLayoutEntry,
|
||||
@ -1890,7 +1892,6 @@ impl Device {
|
||||
dynamic_binding_info: &mut Vec<binding_model::BindGroupDynamicBindingData>,
|
||||
late_buffer_binding_sizes: &mut FastHashMap<u32, wgt::BufferSize>,
|
||||
used: &mut BindGroupStates,
|
||||
limits: &wgt::Limits,
|
||||
snatch_guard: &'a SnatchGuard<'a>,
|
||||
) -> Result<hal::BufferBinding<'a, dyn hal::DynBuffer>, binding_model::CreateBindGroupError>
|
||||
{
|
||||
@ -1915,7 +1916,7 @@ impl Device {
|
||||
wgt::BufferBindingType::Uniform => (
|
||||
wgt::BufferUsages::UNIFORM,
|
||||
hal::BufferUses::UNIFORM,
|
||||
limits.max_uniform_buffer_binding_size,
|
||||
self.limits.max_uniform_buffer_binding_size,
|
||||
),
|
||||
wgt::BufferBindingType::Storage { read_only } => (
|
||||
wgt::BufferUsages::STORAGE,
|
||||
@ -1924,12 +1925,12 @@ impl Device {
|
||||
} else {
|
||||
hal::BufferUses::STORAGE_READ_WRITE
|
||||
},
|
||||
limits.max_storage_buffer_binding_size,
|
||||
self.limits.max_storage_buffer_binding_size,
|
||||
),
|
||||
};
|
||||
|
||||
let (align, align_limit_name) =
|
||||
binding_model::buffer_binding_type_alignment(limits, binding_ty);
|
||||
binding_model::buffer_binding_type_alignment(&self.limits, binding_ty);
|
||||
if bb.offset % align as u64 != 0 {
|
||||
return Err(Error::UnalignedBufferOffset(
|
||||
bb.offset,
|
||||
@ -2005,10 +2006,21 @@ impl Device {
|
||||
late_buffer_binding_sizes.insert(binding, late_size);
|
||||
}
|
||||
|
||||
// This was checked against the device's alignment requirements above,
|
||||
// which should always be a multiple of `COPY_BUFFER_ALIGNMENT`.
|
||||
assert_eq!(bb.offset % wgt::COPY_BUFFER_ALIGNMENT, 0);
|
||||
|
||||
// `wgpu_hal` only restricts shader access to bound buffer regions with
|
||||
// a certain resolution. For the sake of lazy initialization, round up
|
||||
// the size of the bound range to reflect how much of the buffer is
|
||||
// actually going to be visible to the shader.
|
||||
let bounds_check_alignment =
|
||||
binding_model::buffer_binding_type_bounds_check_alignment(&self.alignments, binding_ty);
|
||||
let visible_size = align_to(bind_size, bounds_check_alignment);
|
||||
|
||||
used_buffer_ranges.extend(buffer.initialization_status.read().create_action(
|
||||
buffer,
|
||||
bb.offset..bb.offset + bind_size,
|
||||
bb.offset..bb.offset + visible_size,
|
||||
MemoryInitKind::NeedsInitializedMemory,
|
||||
));
|
||||
|
||||
@ -2020,7 +2032,7 @@ impl Device {
|
||||
}
|
||||
|
||||
fn create_sampler_binding<'a>(
|
||||
self: &Arc<Self>,
|
||||
&self,
|
||||
used: &mut BindGroupStates,
|
||||
binding: u32,
|
||||
decl: &wgt::BindGroupLayoutEntry,
|
||||
@ -2068,8 +2080,8 @@ impl Device {
|
||||
Ok(sampler.raw())
|
||||
}
|
||||
|
||||
pub(crate) fn create_texture_binding<'a>(
|
||||
self: &Arc<Self>,
|
||||
fn create_texture_binding<'a>(
|
||||
&self,
|
||||
binding: u32,
|
||||
decl: &wgt::BindGroupLayoutEntry,
|
||||
view: &'a Arc<TextureView>,
|
||||
@ -2167,7 +2179,6 @@ impl Device {
|
||||
&mut dynamic_binding_info,
|
||||
&mut late_buffer_binding_sizes,
|
||||
&mut used,
|
||||
&self.limits,
|
||||
&snatch_guard,
|
||||
)?;
|
||||
|
||||
@ -2189,7 +2200,6 @@ impl Device {
|
||||
&mut dynamic_binding_info,
|
||||
&mut late_buffer_binding_sizes,
|
||||
&mut used,
|
||||
&self.limits,
|
||||
&snatch_guard,
|
||||
)?;
|
||||
hal_buffers.push(bb);
|
||||
@ -2325,7 +2335,7 @@ impl Device {
|
||||
Ok(bind_group)
|
||||
}
|
||||
|
||||
pub(crate) fn check_array_binding(
|
||||
fn check_array_binding(
|
||||
features: wgt::Features,
|
||||
count: Option<NonZeroU32>,
|
||||
num_bindings: usize,
|
||||
@ -2358,8 +2368,8 @@ impl Device {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn texture_use_parameters(
|
||||
self: &Arc<Self>,
|
||||
fn texture_use_parameters(
|
||||
&self,
|
||||
binding: u32,
|
||||
decl: &wgt::BindGroupLayoutEntry,
|
||||
view: &TextureView,
|
||||
@ -3449,10 +3459,7 @@ impl Device {
|
||||
Ok(cache)
|
||||
}
|
||||
|
||||
pub(crate) fn get_texture_format_features(
|
||||
&self,
|
||||
format: TextureFormat,
|
||||
) -> wgt::TextureFormatFeatures {
|
||||
fn get_texture_format_features(&self, format: TextureFormat) -> wgt::TextureFormatFeatures {
|
||||
// Variant of adapter.get_texture_format_features that takes device features into account
|
||||
use wgt::TextureFormatFeatureFlags as tfsc;
|
||||
let mut format_features = self.adapter.get_texture_format_features(format);
|
||||
@ -3466,7 +3473,7 @@ impl Device {
|
||||
format_features
|
||||
}
|
||||
|
||||
pub(crate) fn describe_format_features(
|
||||
fn describe_format_features(
|
||||
&self,
|
||||
format: TextureFormat,
|
||||
) -> Result<wgt::TextureFormatFeatures, MissingFeatures> {
|
||||
|
@ -65,6 +65,35 @@ pub(crate) struct InitTracker<Idx: Ord + Copy + Default> {
|
||||
uninitialized_ranges: UninitializedRangeVec<Idx>,
|
||||
}
|
||||
|
||||
pub(crate) struct UninitializedIter<'a, Idx: fmt::Debug + Ord + Copy> {
|
||||
uninitialized_ranges: &'a UninitializedRangeVec<Idx>,
|
||||
drain_range: Range<Idx>,
|
||||
next_index: usize,
|
||||
}
|
||||
|
||||
impl<'a, Idx> Iterator for UninitializedIter<'a, Idx>
|
||||
where
|
||||
Idx: fmt::Debug + Ord + Copy,
|
||||
{
|
||||
type Item = Range<Idx>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.uninitialized_ranges
|
||||
.get(self.next_index)
|
||||
.and_then(|range| {
|
||||
if range.start < self.drain_range.end {
|
||||
self.next_index += 1;
|
||||
Some(
|
||||
range.start.max(self.drain_range.start)
|
||||
..range.end.min(self.drain_range.end),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct InitTrackerDrain<'a, Idx: fmt::Debug + Ord + Copy> {
|
||||
uninitialized_ranges: &'a mut UninitializedRangeVec<Idx>,
|
||||
drain_range: Range<Idx>,
|
||||
@ -190,6 +219,18 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
// Returns an iterator over the uninitialized ranges in a query range.
|
||||
pub(crate) fn uninitialized(&mut self, drain_range: Range<Idx>) -> UninitializedIter<Idx> {
|
||||
let index = self
|
||||
.uninitialized_ranges
|
||||
.partition_point(|r| r.end <= drain_range.start);
|
||||
UninitializedIter {
|
||||
drain_range,
|
||||
uninitialized_ranges: &self.uninitialized_ranges,
|
||||
next_index: index,
|
||||
}
|
||||
}
|
||||
|
||||
// Drains uninitialized ranges in a query range.
|
||||
pub(crate) fn drain(&mut self, drain_range: Range<Idx>) -> InitTrackerDrain<Idx> {
|
||||
let index = self
|
||||
|
11
third_party/rust/wgpu-core/src/lock/observing.rs
vendored
11
third_party/rust/wgpu-core/src/lock/observing.rs
vendored
@ -369,16 +369,16 @@ impl ObservationLog {
|
||||
self.write_location(new_location);
|
||||
self.write_action(&Action::Acquisition {
|
||||
older_rank: older_lock.rank.bit.number(),
|
||||
older_location: older_lock.location as *const _ as usize,
|
||||
older_location: addr(older_lock.location),
|
||||
newer_rank: new_rank.bit.number(),
|
||||
newer_location: new_location as *const _ as usize,
|
||||
newer_location: addr(new_location),
|
||||
});
|
||||
}
|
||||
|
||||
fn write_location(&mut self, location: &'static Location<'static>) {
|
||||
if self.locations_seen.insert(location) {
|
||||
self.write_action(&Action::Location {
|
||||
address: location as *const _ as usize,
|
||||
address: addr(location),
|
||||
file: location.file(),
|
||||
line: location.line(),
|
||||
column: location.column(),
|
||||
@ -473,3 +473,8 @@ impl LockRankSet {
|
||||
self.bits().trailing_zeros()
|
||||
}
|
||||
}
|
||||
|
||||
/// Convenience for `std::ptr::from_ref(t) as usize`.
|
||||
fn addr<T>(t: &T) -> usize {
|
||||
std::ptr::from_ref(t) as usize
|
||||
}
|
||||
|
4
third_party/rust/wgpu-core/src/resource.rs
vendored
4
third_party/rust/wgpu-core/src/resource.rs
vendored
@ -106,8 +106,8 @@ pub(crate) trait ParentDevice: Labeled {
|
||||
}
|
||||
}
|
||||
|
||||
fn same_device(&self, device: &Arc<Device>) -> Result<(), DeviceError> {
|
||||
if Arc::ptr_eq(self.device(), device) {
|
||||
fn same_device(&self, device: &Device) -> Result<(), DeviceError> {
|
||||
if std::ptr::eq(&**self.device(), device) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(DeviceError::DeviceMismatch(Box::new(DeviceMismatch {
|
||||
|
File diff suppressed because one or more lines are too long
16
third_party/rust/wgpu-hal/Cargo.toml
vendored
16
third_party/rust/wgpu-hal/Cargo.toml
vendored
@ -140,6 +140,7 @@ dx12 = [
|
||||
"gpu-allocator/d3d12",
|
||||
"naga/hlsl-out-if-target-windows",
|
||||
"windows/Win32_Graphics_Direct3D_Fxc",
|
||||
"windows/Win32_Graphics_Direct3D_Dxc",
|
||||
"windows/Win32_Graphics_Direct3D",
|
||||
"windows/Win32_Graphics_Direct3D12",
|
||||
"windows/Win32_Graphics_DirectComposition",
|
||||
@ -151,7 +152,6 @@ dx12 = [
|
||||
"windows/Win32_System_Threading",
|
||||
"windows/Win32_UI_WindowsAndMessaging",
|
||||
]
|
||||
dxc_shader_compiler = ["dep:hassle-rs"]
|
||||
fragile-send-sync-non-atomic-wasm = ["wgt/fragile-send-sync-non-atomic-wasm"]
|
||||
gles = [
|
||||
"naga/glsl-out",
|
||||
@ -213,29 +213,31 @@ version = "0.29.0"
|
||||
[target.'cfg(any(target_os="macos", target_os="ios"))'.dependencies.objc]
|
||||
version = "0.2.5"
|
||||
|
||||
[target.'cfg(not(any(target_arch = "wasm32", windows, target_os = "ios")))'.dev-dependencies.glutin]
|
||||
[target.'cfg(not(any(target_arch = "wasm32", target_os = "ios")))'.dev-dependencies.glutin]
|
||||
version = "0.31"
|
||||
features = [
|
||||
"egl",
|
||||
"wgl",
|
||||
"wayland",
|
||||
"x11",
|
||||
]
|
||||
default-features = false
|
||||
|
||||
[target.'cfg(not(any(target_arch = "wasm32", windows, target_os = "ios")))'.dev-dependencies.glutin-winit]
|
||||
[target.'cfg(not(any(target_arch = "wasm32", target_os = "ios")))'.dev-dependencies.glutin-winit]
|
||||
version = "0.4"
|
||||
features = [
|
||||
"egl",
|
||||
"wgl",
|
||||
"wayland",
|
||||
"x11",
|
||||
]
|
||||
default-features = false
|
||||
|
||||
[target.'cfg(not(any(target_arch = "wasm32", windows, target_os = "ios")))'.dev-dependencies.rwh_05]
|
||||
[target.'cfg(not(any(target_arch = "wasm32", target_os = "ios")))'.dev-dependencies.rwh_05]
|
||||
version = "0.5"
|
||||
package = "raw-window-handle"
|
||||
|
||||
[target.'cfg(not(any(target_arch = "wasm32", windows, target_os = "ios")))'.dev-dependencies.winit]
|
||||
[target.'cfg(not(any(target_arch = "wasm32", target_os = "ios")))'.dev-dependencies.winit]
|
||||
version = "0.29"
|
||||
features = [
|
||||
"android-native-activity",
|
||||
@ -307,10 +309,6 @@ version = "0.27"
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[target."cfg(windows)".dependencies.hassle-rs]
|
||||
version = "0.11.0"
|
||||
optional = true
|
||||
|
||||
[target."cfg(windows)".dependencies.range-alloc]
|
||||
version = "0.1"
|
||||
optional = true
|
||||
|
@ -14,7 +14,9 @@ use winit::{
|
||||
|
||||
use std::{
|
||||
borrow::{Borrow, Cow},
|
||||
iter, mem, ptr,
|
||||
iter,
|
||||
mem::size_of,
|
||||
ptr,
|
||||
time::Instant,
|
||||
};
|
||||
|
||||
@ -193,7 +195,7 @@ impl<A: hal::Api> Example<A> {
|
||||
ty: wgt::BindingType::Buffer {
|
||||
ty: wgt::BufferBindingType::Uniform,
|
||||
has_dynamic_offset: false,
|
||||
min_binding_size: wgt::BufferSize::new(mem::size_of::<Globals>() as _),
|
||||
min_binding_size: wgt::BufferSize::new(size_of::<Globals>() as _),
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
@ -228,7 +230,7 @@ impl<A: hal::Api> Example<A> {
|
||||
ty: wgt::BindingType::Buffer {
|
||||
ty: wgt::BufferBindingType::Uniform,
|
||||
has_dynamic_offset: true,
|
||||
min_binding_size: wgt::BufferSize::new(mem::size_of::<Locals>() as _),
|
||||
min_binding_size: wgt::BufferSize::new(size_of::<Locals>() as _),
|
||||
},
|
||||
count: None,
|
||||
}],
|
||||
@ -394,7 +396,7 @@ impl<A: hal::Api> Example<A> {
|
||||
|
||||
let global_buffer_desc = hal::BufferDescriptor {
|
||||
label: Some("global"),
|
||||
size: mem::size_of::<Globals>() as wgt::BufferAddress,
|
||||
size: size_of::<Globals>() as wgt::BufferAddress,
|
||||
usage: hal::BufferUses::MAP_WRITE | hal::BufferUses::UNIFORM,
|
||||
memory_flags: hal::MemoryFlags::PREFER_COHERENT,
|
||||
};
|
||||
@ -406,7 +408,7 @@ impl<A: hal::Api> Example<A> {
|
||||
ptr::copy_nonoverlapping(
|
||||
&globals as *const Globals as *const u8,
|
||||
mapping.ptr.as_ptr(),
|
||||
mem::size_of::<Globals>(),
|
||||
size_of::<Globals>(),
|
||||
);
|
||||
device.unmap_buffer(&buffer);
|
||||
assert!(mapping.is_coherent);
|
||||
@ -414,7 +416,7 @@ impl<A: hal::Api> Example<A> {
|
||||
};
|
||||
|
||||
let local_alignment = wgt::math::align_to(
|
||||
mem::size_of::<Locals>() as u32,
|
||||
size_of::<Locals>() as u32,
|
||||
capabilities.limits.min_uniform_buffer_offset_alignment,
|
||||
);
|
||||
let local_buffer_desc = hal::BufferDescriptor {
|
||||
@ -476,7 +478,7 @@ impl<A: hal::Api> Example<A> {
|
||||
let local_buffer_binding = hal::BufferBinding {
|
||||
buffer: &local_buffer,
|
||||
offset: 0,
|
||||
size: wgt::BufferSize::new(mem::size_of::<Locals>() as _),
|
||||
size: wgt::BufferSize::new(size_of::<Locals>() as _),
|
||||
};
|
||||
let local_group_desc = hal::BindGroupDescriptor {
|
||||
label: Some("local"),
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
extern crate wgpu_hal as hal;
|
||||
|
||||
#[cfg(not(any(windows, target_arch = "wasm32", target_os = "ios")))]
|
||||
#[cfg(not(any(target_arch = "wasm32", target_os = "ios")))]
|
||||
fn main() {
|
||||
use std::{ffi::CString, num::NonZeroU32};
|
||||
|
||||
@ -255,7 +255,6 @@ fn main() {
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
windows,
|
||||
all(target_arch = "wasm32", not(target_os = "emscripten")),
|
||||
target_os = "ios"
|
||||
))]
|
||||
@ -264,7 +263,6 @@ fn main() {
|
||||
}
|
||||
|
||||
#[cfg(not(any(
|
||||
windows,
|
||||
all(target_arch = "wasm32", not(target_os = "emscripten")),
|
||||
target_os = "ios"
|
||||
)))]
|
||||
|
@ -8,7 +8,9 @@ use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
|
||||
use glam::{Affine3A, Mat4, Vec3};
|
||||
use std::{
|
||||
borrow::{Borrow, Cow},
|
||||
iter, mem, ptr,
|
||||
iter,
|
||||
mem::size_of,
|
||||
ptr,
|
||||
time::Instant,
|
||||
};
|
||||
use winit::window::WindowButtons;
|
||||
@ -304,7 +306,7 @@ impl<A: hal::Api> Example<A> {
|
||||
ty: wgt::BindingType::Buffer {
|
||||
ty: wgt::BufferBindingType::Uniform,
|
||||
has_dynamic_offset: false,
|
||||
min_binding_size: wgt::BufferSize::new(mem::size_of::<Uniforms>() as _),
|
||||
min_binding_size: wgt::BufferSize::new(size_of::<Uniforms>() as _),
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
@ -516,7 +518,7 @@ impl<A: hal::Api> Example<A> {
|
||||
}
|
||||
};
|
||||
|
||||
let uniforms_size = std::mem::size_of::<Uniforms>();
|
||||
let uniforms_size = size_of::<Uniforms>();
|
||||
|
||||
let uniform_buffer = unsafe {
|
||||
let uniform_buffer = device
|
||||
@ -657,8 +659,7 @@ impl<A: hal::Api> Example<A> {
|
||||
),
|
||||
];
|
||||
|
||||
let instances_buffer_size =
|
||||
instances.len() * std::mem::size_of::<AccelerationStructureInstance>();
|
||||
let instances_buffer_size = instances.len() * size_of::<AccelerationStructureInstance>();
|
||||
|
||||
let instances_buffer = unsafe {
|
||||
let instances_buffer = device
|
||||
@ -828,7 +829,7 @@ impl<A: hal::Api> Example<A> {
|
||||
};
|
||||
|
||||
let instances_buffer_size =
|
||||
self.instances.len() * std::mem::size_of::<AccelerationStructureInstance>();
|
||||
self.instances.len() * size_of::<AccelerationStructureInstance>();
|
||||
|
||||
let tlas_flags = hal::AccelerationStructureBuildFlags::PREFER_FAST_TRACE
|
||||
| hal::AccelerationStructureBuildFlags::ALLOW_UPDATE;
|
||||
|
225
third_party/rust/wgpu-hal/src/auxil/dxgi/factory.rs
vendored
225
third_party/rust/wgpu-hal/src/auxil/dxgi/factory.rs
vendored
@ -4,12 +4,7 @@ use windows::{core::Interface as _, Win32::Graphics::Dxgi};
|
||||
|
||||
use crate::dx12::DxgiLib;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum DxgiFactoryType {
|
||||
Factory2,
|
||||
Factory4,
|
||||
Factory6,
|
||||
}
|
||||
// We can rely on the presence of DXGI 1.4 since D3D12 requires WDDM 2.0, Windows 10 (1507), and so does DXGI 1.4.
|
||||
|
||||
fn should_keep_adapter(adapter: &Dxgi::IDXGIAdapter1) -> bool {
|
||||
let desc = unsafe { adapter.GetDesc1() }.unwrap();
|
||||
@ -52,75 +47,27 @@ fn should_keep_adapter(adapter: &Dxgi::IDXGIAdapter1) -> bool {
|
||||
}
|
||||
|
||||
pub enum DxgiAdapter {
|
||||
Adapter1(Dxgi::IDXGIAdapter1),
|
||||
Adapter2(Dxgi::IDXGIAdapter2),
|
||||
/// Provided by DXGI 1.4
|
||||
Adapter3(Dxgi::IDXGIAdapter3),
|
||||
/// Provided by DXGI 1.6
|
||||
Adapter4(Dxgi::IDXGIAdapter4),
|
||||
}
|
||||
|
||||
impl windows::core::Param<Dxgi::IDXGIAdapter> for &DxgiAdapter {
|
||||
unsafe fn param(self) -> windows::core::ParamValue<Dxgi::IDXGIAdapter> {
|
||||
unsafe { self.deref().param() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for DxgiAdapter {
|
||||
type Target = Dxgi::IDXGIAdapter;
|
||||
type Target = Dxgi::IDXGIAdapter3;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
match self {
|
||||
DxgiAdapter::Adapter1(a) => a,
|
||||
DxgiAdapter::Adapter2(a) => a,
|
||||
DxgiAdapter::Adapter3(a) => a,
|
||||
DxgiAdapter::Adapter4(a) => a,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DxgiAdapter {
|
||||
pub fn as_adapter2(&self) -> Option<&Dxgi::IDXGIAdapter2> {
|
||||
match self {
|
||||
Self::Adapter1(_) => None,
|
||||
Self::Adapter2(f) => Some(f),
|
||||
Self::Adapter3(f) => Some(f),
|
||||
Self::Adapter4(f) => Some(f),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unwrap_adapter2(&self) -> &Dxgi::IDXGIAdapter2 {
|
||||
self.as_adapter2().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enumerate_adapters(factory: DxgiFactory) -> Vec<DxgiAdapter> {
|
||||
let mut adapters = Vec::with_capacity(8);
|
||||
|
||||
for cur_index in 0.. {
|
||||
if let DxgiFactory::Factory6(ref factory6) = factory {
|
||||
profiling::scope!("IDXGIFactory6::EnumAdapterByGpuPreference");
|
||||
// We're already at dxgi1.6, we can grab IDXGIAdapter4 directly
|
||||
let adapter4: Dxgi::IDXGIAdapter4 = match unsafe {
|
||||
factory6.EnumAdapterByGpuPreference(
|
||||
cur_index,
|
||||
Dxgi::DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE,
|
||||
)
|
||||
} {
|
||||
Ok(a) => a,
|
||||
Err(e) if e.code() == Dxgi::DXGI_ERROR_NOT_FOUND => break,
|
||||
Err(e) => {
|
||||
log::error!("Failed enumerating adapters: {}", e);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
if !should_keep_adapter(&adapter4) {
|
||||
continue;
|
||||
}
|
||||
|
||||
adapters.push(DxgiAdapter::Adapter4(adapter4));
|
||||
continue;
|
||||
}
|
||||
|
||||
profiling::scope!("IDXGIFactory1::EnumAdapters1");
|
||||
let adapter1: Dxgi::IDXGIAdapter1 = match unsafe { factory.EnumAdapters1(cur_index) } {
|
||||
Ok(a) => a,
|
||||
@ -135,31 +82,12 @@ pub fn enumerate_adapters(factory: DxgiFactory) -> Vec<DxgiAdapter> {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Do the most aggressive casts first, skipping Adapter4 as we definitely don't have dxgi1_6.
|
||||
|
||||
// Adapter1 -> Adapter3
|
||||
match adapter1.cast::<Dxgi::IDXGIAdapter3>() {
|
||||
Ok(adapter3) => {
|
||||
adapters.push(DxgiAdapter::Adapter3(adapter3));
|
||||
continue;
|
||||
}
|
||||
Err(err) => {
|
||||
log::warn!("Failed casting Adapter1 to Adapter3: {}", err);
|
||||
}
|
||||
if let Ok(adapter4) = adapter1.cast::<Dxgi::IDXGIAdapter4>() {
|
||||
adapters.push(DxgiAdapter::Adapter4(adapter4));
|
||||
} else {
|
||||
let adapter3 = adapter1.cast::<Dxgi::IDXGIAdapter3>().unwrap();
|
||||
adapters.push(DxgiAdapter::Adapter3(adapter3));
|
||||
}
|
||||
|
||||
// Adapter1 -> Adapter2
|
||||
match adapter1.cast::<Dxgi::IDXGIAdapter2>() {
|
||||
Ok(adapter2) => {
|
||||
adapters.push(DxgiAdapter::Adapter2(adapter2));
|
||||
continue;
|
||||
}
|
||||
Err(err) => {
|
||||
log::warn!("Failed casting Adapter1 to Adapter2: {}", err);
|
||||
}
|
||||
}
|
||||
|
||||
adapters.push(DxgiAdapter::Adapter1(adapter1));
|
||||
}
|
||||
|
||||
adapters
|
||||
@ -167,52 +95,37 @@ pub fn enumerate_adapters(factory: DxgiFactory) -> Vec<DxgiAdapter> {
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum DxgiFactory {
|
||||
Factory1(Dxgi::IDXGIFactory1),
|
||||
Factory2(Dxgi::IDXGIFactory2),
|
||||
/// Provided by DXGI 1.4
|
||||
Factory4(Dxgi::IDXGIFactory4),
|
||||
/// Provided by DXGI 1.5
|
||||
Factory5(Dxgi::IDXGIFactory5),
|
||||
/// Provided by DXGI 1.6
|
||||
Factory6(Dxgi::IDXGIFactory6),
|
||||
}
|
||||
|
||||
impl Deref for DxgiFactory {
|
||||
type Target = Dxgi::IDXGIFactory1;
|
||||
type Target = Dxgi::IDXGIFactory4;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
match self {
|
||||
DxgiFactory::Factory1(f) => f,
|
||||
DxgiFactory::Factory2(f) => f,
|
||||
DxgiFactory::Factory4(f) => f,
|
||||
DxgiFactory::Factory5(f) => f,
|
||||
DxgiFactory::Factory6(f) => f,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DxgiFactory {
|
||||
pub fn as_factory2(&self) -> Option<&Dxgi::IDXGIFactory2> {
|
||||
match self {
|
||||
Self::Factory1(_) => None,
|
||||
Self::Factory2(f) => Some(f),
|
||||
Self::Factory4(f) => Some(f),
|
||||
Self::Factory6(f) => Some(f),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unwrap_factory2(&self) -> &Dxgi::IDXGIFactory2 {
|
||||
self.as_factory2().unwrap()
|
||||
}
|
||||
|
||||
pub fn as_factory5(&self) -> Option<&Dxgi::IDXGIFactory5> {
|
||||
match self {
|
||||
Self::Factory1(_) | Self::Factory2(_) | Self::Factory4(_) => None,
|
||||
Self::Factory4(_) => None,
|
||||
Self::Factory5(f) => Some(f),
|
||||
Self::Factory6(f) => Some(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Tries to create a [`Dxgi::IDXGIFactory6`], then a [`Dxgi::IDXGIFactory4`], then a [`Dxgi::IDXGIFactory2`], then a [`Dxgi::IDXGIFactory1`],
|
||||
/// returning the one that succeeds, or if the required_factory_type fails to be
|
||||
/// created.
|
||||
pub fn create_factory(
|
||||
required_factory_type: DxgiFactoryType,
|
||||
instance_flags: wgt::InstanceFlags,
|
||||
) -> Result<(DxgiLib, DxgiFactory), crate::InstanceError> {
|
||||
let lib_dxgi = DxgiLib::new().map_err(|e| {
|
||||
@ -225,111 +138,31 @@ pub fn create_factory(
|
||||
// The `DXGI_CREATE_FACTORY_DEBUG` flag is only allowed to be passed to
|
||||
// `CreateDXGIFactory2` if the debug interface is actually available. So
|
||||
// we check for whether it exists first.
|
||||
match lib_dxgi.debug_interface1() {
|
||||
Ok(pair) => match pair {
|
||||
Ok(_debug_controller) => {
|
||||
factory_flags |= Dxgi::DXGI_CREATE_FACTORY_DEBUG;
|
||||
}
|
||||
Err(err) => {
|
||||
log::warn!("Unable to enable DXGI debug interface: {}", err);
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
log::warn!("Debug interface function for DXGI not found: {:?}", err);
|
||||
}
|
||||
if lib_dxgi.debug_interface1().is_ok() {
|
||||
factory_flags |= Dxgi::DXGI_CREATE_FACTORY_DEBUG;
|
||||
}
|
||||
|
||||
// Intercept `OutputDebugString` calls
|
||||
super::exception::register_exception_handler();
|
||||
}
|
||||
|
||||
// Try to create IDXGIFactory4
|
||||
let factory4 = match lib_dxgi.create_factory2(factory_flags) {
|
||||
Ok(pair) => match pair {
|
||||
Ok(factory) => Some(factory),
|
||||
// We hard error here as we _should have_ been able to make a factory4 but couldn't.
|
||||
Err(err) => {
|
||||
// err is a Cow<str>, not an Error implementor
|
||||
return Err(crate::InstanceError::new(format!(
|
||||
"failed to create IDXGIFactory4: {err:?}"
|
||||
)));
|
||||
}
|
||||
},
|
||||
// If we require factory4, hard error.
|
||||
Err(err) if required_factory_type == DxgiFactoryType::Factory4 => {
|
||||
return Err(crate::InstanceError::with_source(
|
||||
String::from("IDXGIFactory1 creation function not found"),
|
||||
err,
|
||||
));
|
||||
}
|
||||
// If we don't print it to warn as all win7 will hit this case.
|
||||
Err(err) => {
|
||||
log::warn!("IDXGIFactory1 creation function not found: {err:?}");
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(factory4) = factory4 {
|
||||
// Try to cast the IDXGIFactory4 into IDXGIFactory6
|
||||
let factory6 = factory4.cast::<Dxgi::IDXGIFactory6>();
|
||||
match factory6 {
|
||||
Ok(factory6) => {
|
||||
return Ok((lib_dxgi, DxgiFactory::Factory6(factory6)));
|
||||
}
|
||||
// If we require factory6, hard error.
|
||||
Err(err) if required_factory_type == DxgiFactoryType::Factory6 => {
|
||||
// err is a Cow<str>, not an Error implementor
|
||||
return Err(crate::InstanceError::new(format!(
|
||||
"failed to cast IDXGIFactory4 to IDXGIFactory6: {err:?}"
|
||||
)));
|
||||
}
|
||||
// If we don't print it to warn.
|
||||
Err(err) => {
|
||||
log::warn!("Failed to cast IDXGIFactory4 to IDXGIFactory6: {:?}", err);
|
||||
return Ok((lib_dxgi, DxgiFactory::Factory4(factory4)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try to create IDXGIFactory1
|
||||
let factory1 = match lib_dxgi.create_factory1() {
|
||||
Ok(pair) => match pair {
|
||||
Ok(factory) => factory,
|
||||
Err(err) => {
|
||||
// err is a Cow<str>, not an Error implementor
|
||||
return Err(crate::InstanceError::new(format!(
|
||||
"failed to create IDXGIFactory1: {err:?}"
|
||||
)));
|
||||
}
|
||||
},
|
||||
// We always require at least factory1, so hard error
|
||||
let factory4 = match lib_dxgi.create_factory4(factory_flags) {
|
||||
Ok(factory) => factory,
|
||||
Err(err) => {
|
||||
return Err(crate::InstanceError::with_source(
|
||||
String::from("IDXGIFactory1 creation function not found"),
|
||||
String::from("IDXGIFactory4 creation failed"),
|
||||
err,
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
// Try to cast the IDXGIFactory1 into IDXGIFactory2
|
||||
let factory2 = factory1.cast::<Dxgi::IDXGIFactory2>();
|
||||
match factory2 {
|
||||
Ok(factory2) => {
|
||||
return Ok((lib_dxgi, DxgiFactory::Factory2(factory2)));
|
||||
}
|
||||
// If we require factory2, hard error.
|
||||
Err(err) if required_factory_type == DxgiFactoryType::Factory2 => {
|
||||
// err is a Cow<str>, not an Error implementor
|
||||
return Err(crate::InstanceError::new(format!(
|
||||
"failed to cast IDXGIFactory1 to IDXGIFactory2: {err:?}"
|
||||
)));
|
||||
}
|
||||
// If we don't print it to warn.
|
||||
Err(err) => {
|
||||
log::warn!("Failed to cast IDXGIFactory1 to IDXGIFactory2: {:?}", err);
|
||||
}
|
||||
if let Ok(factory6) = factory4.cast::<Dxgi::IDXGIFactory6>() {
|
||||
return Ok((lib_dxgi, DxgiFactory::Factory6(factory6)));
|
||||
}
|
||||
|
||||
// We tried to create 4 and 2, but only succeeded with 1.
|
||||
Ok((lib_dxgi, DxgiFactory::Factory1(factory1)))
|
||||
if let Ok(factory5) = factory4.cast::<Dxgi::IDXGIFactory5>() {
|
||||
return Ok((lib_dxgi, DxgiFactory::Factory5(factory5)));
|
||||
}
|
||||
|
||||
Ok((lib_dxgi, DxgiFactory::Factory4(factory4)))
|
||||
}
|
||||
|
@ -1,56 +1,32 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use windows::Win32::{Foundation, Graphics::Dxgi};
|
||||
|
||||
pub(crate) trait HResult<O> {
|
||||
fn into_result(self) -> Result<O, Cow<'static, str>>;
|
||||
fn into_device_result(self, description: &str) -> Result<O, crate::DeviceError>;
|
||||
}
|
||||
impl<T> HResult<T> for windows::core::Result<T> {
|
||||
fn into_result(self) -> Result<T, Cow<'static, str>> {
|
||||
// TODO: use windows-rs built-in error formatting?
|
||||
let description = match self {
|
||||
Ok(t) => return Ok(t),
|
||||
Err(e) if e.code() == Foundation::E_UNEXPECTED => "unexpected",
|
||||
Err(e) if e.code() == Foundation::E_NOTIMPL => "not implemented",
|
||||
Err(e) if e.code() == Foundation::E_OUTOFMEMORY => "out of memory",
|
||||
Err(e) if e.code() == Foundation::E_INVALIDARG => "invalid argument",
|
||||
Err(e) => return Err(Cow::Owned(format!("{e:?}"))),
|
||||
};
|
||||
Err(Cow::Borrowed(description))
|
||||
}
|
||||
fn into_device_result(self, description: &str) -> Result<T, crate::DeviceError> {
|
||||
#![allow(unreachable_code)]
|
||||
|
||||
let err_code = if let Err(err) = &self {
|
||||
Some(err.code())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
self.into_result().map_err(|err| {
|
||||
self.map_err(|err| {
|
||||
log::error!("{} failed: {}", description, err);
|
||||
|
||||
let Some(err_code) = err_code else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
match err_code {
|
||||
match err.code() {
|
||||
Foundation::E_OUTOFMEMORY => {
|
||||
#[cfg(feature = "oom_panic")]
|
||||
panic!("{description} failed: Out of memory");
|
||||
return crate::DeviceError::OutOfMemory;
|
||||
crate::DeviceError::OutOfMemory
|
||||
}
|
||||
Dxgi::DXGI_ERROR_DEVICE_RESET | Dxgi::DXGI_ERROR_DEVICE_REMOVED => {
|
||||
#[cfg(feature = "device_lost_panic")]
|
||||
panic!("{description} failed: Device lost ({err})");
|
||||
crate::DeviceError::Lost
|
||||
}
|
||||
_ => {
|
||||
#[cfg(feature = "internal_error_panic")]
|
||||
panic!("{description} failed: {err}");
|
||||
crate::DeviceError::Unexpected
|
||||
}
|
||||
}
|
||||
|
||||
crate::DeviceError::Lost
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ impl PresentationTimer {
|
||||
let kernelbase =
|
||||
libloading::os::windows::Library::open_already_loaded("kernelbase.dll").unwrap();
|
||||
// No concerns about lifetimes here as kernelbase is always there.
|
||||
let ptr = unsafe { kernelbase.get(b"QueryInterruptTimePrecise").unwrap() };
|
||||
let ptr = unsafe { kernelbase.get(b"QueryInterruptTimePrecise\0").unwrap() };
|
||||
Self::IPresentationManager {
|
||||
fnQueryInterruptTimePrecise: *ptr,
|
||||
}
|
||||
|
54
third_party/rust/wgpu-hal/src/dx12/adapter.rs
vendored
54
third_party/rust/wgpu-hal/src/dx12/adapter.rs
vendored
@ -1,4 +1,9 @@
|
||||
use std::{mem, ptr, sync::Arc, thread};
|
||||
use std::{
|
||||
mem::{size_of, size_of_val},
|
||||
ptr,
|
||||
sync::Arc,
|
||||
thread,
|
||||
};
|
||||
|
||||
use parking_lot::Mutex;
|
||||
use windows::{
|
||||
@ -59,19 +64,9 @@ impl super::Adapter {
|
||||
// Create the device so that we can get the capabilities.
|
||||
let device = {
|
||||
profiling::scope!("ID3D12Device::create_device");
|
||||
match library.create_device(&adapter, Direct3D::D3D_FEATURE_LEVEL_11_0) {
|
||||
Ok(pair) => match pair {
|
||||
Ok(device) => device,
|
||||
Err(err) => {
|
||||
log::warn!("Device creation failed: {}", err);
|
||||
return None;
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
log::warn!("Device creation function is not found: {:?}", err);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
library
|
||||
.create_device(&adapter, Direct3D::D3D_FEATURE_LEVEL_11_0)
|
||||
.ok()?
|
||||
};
|
||||
|
||||
profiling::scope!("feature queries");
|
||||
@ -92,7 +87,7 @@ impl super::Adapter {
|
||||
device.CheckFeatureSupport(
|
||||
Direct3D12::D3D12_FEATURE_FEATURE_LEVELS,
|
||||
<*mut _>::cast(&mut device_levels),
|
||||
mem::size_of_val(&device_levels) as u32,
|
||||
size_of_val(&device_levels) as u32,
|
||||
)
|
||||
}
|
||||
.unwrap();
|
||||
@ -100,7 +95,7 @@ impl super::Adapter {
|
||||
|
||||
// We have found a possible adapter.
|
||||
// Acquire the device information.
|
||||
let desc = unsafe { adapter.unwrap_adapter2().GetDesc2() }.unwrap();
|
||||
let desc = unsafe { adapter.GetDesc2() }.unwrap();
|
||||
|
||||
let device_name = auxil::dxgi::conv::map_adapter_name(desc.Description);
|
||||
|
||||
@ -110,7 +105,7 @@ impl super::Adapter {
|
||||
device.CheckFeatureSupport(
|
||||
Direct3D12::D3D12_FEATURE_ARCHITECTURE,
|
||||
<*mut _>::cast(&mut features_architecture),
|
||||
mem::size_of_val(&features_architecture) as u32,
|
||||
size_of_val(&features_architecture) as u32,
|
||||
)
|
||||
}
|
||||
.unwrap();
|
||||
@ -154,7 +149,7 @@ impl super::Adapter {
|
||||
device.CheckFeatureSupport(
|
||||
Direct3D12::D3D12_FEATURE_D3D12_OPTIONS,
|
||||
<*mut _>::cast(&mut options),
|
||||
mem::size_of_val(&options) as u32,
|
||||
size_of_val(&options) as u32,
|
||||
)
|
||||
}
|
||||
.unwrap();
|
||||
@ -165,7 +160,7 @@ impl super::Adapter {
|
||||
device.CheckFeatureSupport(
|
||||
Direct3D12::D3D12_FEATURE_D3D12_OPTIONS2,
|
||||
<*mut _>::cast(&mut features2),
|
||||
mem::size_of_val(&features2) as u32,
|
||||
size_of_val(&features2) as u32,
|
||||
)
|
||||
}
|
||||
.is_ok()
|
||||
@ -178,7 +173,7 @@ impl super::Adapter {
|
||||
device.CheckFeatureSupport(
|
||||
Direct3D12::D3D12_FEATURE_D3D12_OPTIONS3,
|
||||
<*mut _>::cast(&mut features3),
|
||||
mem::size_of_val(&features3) as u32,
|
||||
size_of_val(&features3) as u32,
|
||||
)
|
||||
}
|
||||
.is_ok()
|
||||
@ -194,7 +189,7 @@ impl super::Adapter {
|
||||
device.CheckFeatureSupport(
|
||||
Direct3D12::D3D12_FEATURE_D3D12_OPTIONS7,
|
||||
<*mut _>::cast(&mut features7),
|
||||
mem::size_of_val(&features7) as u32,
|
||||
size_of_val(&features7) as u32,
|
||||
)
|
||||
}
|
||||
.is_ok()
|
||||
@ -224,7 +219,7 @@ impl super::Adapter {
|
||||
device.CheckFeatureSupport(
|
||||
Direct3D12::D3D12_FEATURE_SHADER_MODEL,
|
||||
<*mut _>::cast(&mut sm),
|
||||
mem::size_of_val(&sm) as u32,
|
||||
size_of_val(&sm) as u32,
|
||||
)
|
||||
}
|
||||
.is_ok()
|
||||
@ -354,7 +349,7 @@ impl super::Adapter {
|
||||
device.CheckFeatureSupport(
|
||||
Direct3D12::D3D12_FEATURE_FORMAT_SUPPORT,
|
||||
<*mut _>::cast(&mut bgra8unorm_info),
|
||||
mem::size_of_val(&bgra8unorm_info) as u32,
|
||||
size_of_val(&bgra8unorm_info) as u32,
|
||||
)
|
||||
};
|
||||
hr.is_ok()
|
||||
@ -372,7 +367,7 @@ impl super::Adapter {
|
||||
device.CheckFeatureSupport(
|
||||
Direct3D12::D3D12_FEATURE_D3D12_OPTIONS1,
|
||||
<*mut _>::cast(&mut features1),
|
||||
mem::size_of_val(&features1) as u32,
|
||||
size_of_val(&features1) as u32,
|
||||
)
|
||||
};
|
||||
|
||||
@ -396,7 +391,7 @@ impl super::Adapter {
|
||||
device.CheckFeatureSupport(
|
||||
Direct3D12::D3D12_FEATURE_D3D12_OPTIONS9,
|
||||
<*mut _>::cast(&mut features9),
|
||||
mem::size_of_val(&features9) as u32,
|
||||
size_of_val(&features9) as u32,
|
||||
)
|
||||
}
|
||||
.is_ok()
|
||||
@ -524,6 +519,9 @@ impl super::Adapter {
|
||||
Direct3D12::D3D12_TEXTURE_DATA_PITCH_ALIGNMENT as u64,
|
||||
)
|
||||
.unwrap(),
|
||||
// Direct3D correctly bounds-checks all array accesses:
|
||||
// https://microsoft.github.io/DirectX-Specs/d3d/archive/D3D11_3_FunctionalSpec.htm#18.6.8.2%20Device%20Memory%20Reads
|
||||
uniform_bounds_check_alignment: wgt::BufferSize::new(1).unwrap(),
|
||||
},
|
||||
downlevel,
|
||||
},
|
||||
@ -604,7 +602,7 @@ impl crate::Adapter for super::Adapter {
|
||||
self.device.CheckFeatureSupport(
|
||||
Direct3D12::D3D12_FEATURE_FORMAT_SUPPORT,
|
||||
<*mut _>::cast(&mut data),
|
||||
mem::size_of_val(&data) as u32,
|
||||
size_of_val(&data) as u32,
|
||||
)
|
||||
}
|
||||
.unwrap();
|
||||
@ -622,7 +620,7 @@ impl crate::Adapter for super::Adapter {
|
||||
self.device.CheckFeatureSupport(
|
||||
Direct3D12::D3D12_FEATURE_FORMAT_SUPPORT,
|
||||
ptr::addr_of_mut!(data_srv_uav).cast(),
|
||||
mem::size_of::<Direct3D12::D3D12_FEATURE_DATA_FORMAT_SUPPORT>() as u32,
|
||||
size_of::<Direct3D12::D3D12_FEATURE_DATA_FORMAT_SUPPORT>() as u32,
|
||||
)
|
||||
}
|
||||
.unwrap();
|
||||
@ -718,7 +716,7 @@ impl crate::Adapter for super::Adapter {
|
||||
self.device.CheckFeatureSupport(
|
||||
Direct3D12::D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS,
|
||||
<*mut _>::cast(&mut ms_levels),
|
||||
mem::size_of_val(&ms_levels) as u32,
|
||||
size_of_val(&ms_levels) as u32,
|
||||
)
|
||||
}
|
||||
.is_ok()
|
||||
|
32
third_party/rust/wgpu-hal/src/dx12/command.rs
vendored
32
third_party/rust/wgpu-hal/src/dx12/command.rs
vendored
@ -53,7 +53,6 @@ impl crate::BufferTextureCopy {
|
||||
|
||||
impl super::Temp {
|
||||
fn prepare_marker(&mut self, marker: &str) -> (&[u16], u32) {
|
||||
// TODO: Store in HSTRING
|
||||
self.marker.clear();
|
||||
self.marker.extend(marker.encode_utf16());
|
||||
self.marker.push(0);
|
||||
@ -153,7 +152,7 @@ impl super::CommandEncoder {
|
||||
self.update_root_elements();
|
||||
}
|
||||
|
||||
//Note: we have to call this lazily before draw calls. Otherwise, D3D complains
|
||||
// Note: we have to call this lazily before draw calls. Otherwise, D3D complains
|
||||
// about the root parameters being incompatible with root signature.
|
||||
fn update_root_elements(&mut self) {
|
||||
use super::{BufferViewKind as Bvk, PassKind as Pk};
|
||||
@ -265,7 +264,8 @@ impl crate::CommandEncoder for super::CommandEncoder {
|
||||
unsafe fn begin_encoding(&mut self, label: crate::Label) -> Result<(), crate::DeviceError> {
|
||||
let list = loop {
|
||||
if let Some(list) = self.free_lists.pop() {
|
||||
let reset_result = unsafe { list.Reset(&self.allocator, None) }.into_result();
|
||||
// TODO: Is an error expected here and should we print it?
|
||||
let reset_result = unsafe { list.Reset(&self.allocator, None) };
|
||||
if reset_result.is_ok() {
|
||||
break Some(list);
|
||||
}
|
||||
@ -314,7 +314,9 @@ impl crate::CommandEncoder for super::CommandEncoder {
|
||||
for cmd_buf in command_buffers {
|
||||
self.free_lists.push(cmd_buf.raw);
|
||||
}
|
||||
let _todo_handle_error = unsafe { self.allocator.Reset() };
|
||||
if let Err(e) = unsafe { self.allocator.Reset() } {
|
||||
log::error!("ID3D12CommandAllocator::Reset() failed with {e}");
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn transition_buffers<'a, T>(&mut self, barriers: T)
|
||||
@ -724,8 +726,7 @@ impl crate::CommandEncoder for super::CommandEncoder {
|
||||
cat.clear_value.b as f32,
|
||||
cat.clear_value.a as f32,
|
||||
];
|
||||
// TODO: Empty slice vs None?
|
||||
unsafe { list.ClearRenderTargetView(*rtv, &value, Some(&[])) };
|
||||
unsafe { list.ClearRenderTargetView(*rtv, &value, None) };
|
||||
}
|
||||
if let Some(ref target) = cat.resolve_target {
|
||||
self.pass.resolves.push(super::PassResolve {
|
||||
@ -754,12 +755,23 @@ impl crate::CommandEncoder for super::CommandEncoder {
|
||||
if let Some(ds_view) = ds_view {
|
||||
if flags != Direct3D12::D3D12_CLEAR_FLAGS::default() {
|
||||
unsafe {
|
||||
list.ClearDepthStencilView(
|
||||
// list.ClearDepthStencilView(
|
||||
// ds_view,
|
||||
// flags,
|
||||
// ds.clear_value.0,
|
||||
// ds.clear_value.1 as u8,
|
||||
// None,
|
||||
// )
|
||||
// TODO: Replace with the above in the next breaking windows-rs release,
|
||||
// when https://github.com/microsoft/win32metadata/pull/1971 is in.
|
||||
(windows_core::Interface::vtable(list).ClearDepthStencilView)(
|
||||
windows_core::Interface::as_raw(list),
|
||||
ds_view,
|
||||
flags,
|
||||
ds.clear_value.0,
|
||||
ds.clear_value.1 as u8,
|
||||
&[],
|
||||
0,
|
||||
std::ptr::null(),
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -796,7 +808,7 @@ impl crate::CommandEncoder for super::CommandEncoder {
|
||||
Type: Direct3D12::D3D12_RESOURCE_BARRIER_TYPE_TRANSITION,
|
||||
Flags: Direct3D12::D3D12_RESOURCE_BARRIER_FLAG_NONE,
|
||||
Anonymous: Direct3D12::D3D12_RESOURCE_BARRIER_0 {
|
||||
//Note: this assumes `D3D12_RESOURCE_STATE_RENDER_TARGET`.
|
||||
// Note: this assumes `D3D12_RESOURCE_STATE_RENDER_TARGET`.
|
||||
// If it's not the case, we can include the `TextureUses` in `PassResove`.
|
||||
Transition: mem::ManuallyDrop::new(
|
||||
Direct3D12::D3D12_RESOURCE_TRANSITION_BARRIER {
|
||||
@ -813,7 +825,7 @@ impl crate::CommandEncoder for super::CommandEncoder {
|
||||
Type: Direct3D12::D3D12_RESOURCE_BARRIER_TYPE_TRANSITION,
|
||||
Flags: Direct3D12::D3D12_RESOURCE_BARRIER_FLAG_NONE,
|
||||
Anonymous: Direct3D12::D3D12_RESOURCE_BARRIER_0 {
|
||||
//Note: this assumes `D3D12_RESOURCE_STATE_RENDER_TARGET`.
|
||||
// Note: this assumes `D3D12_RESOURCE_STATE_RENDER_TARGET`.
|
||||
// If it's not the case, we can include the `TextureUses` in `PassResolve`.
|
||||
Transition: mem::ManuallyDrop::new(
|
||||
Direct3D12::D3D12_RESOURCE_TRANSITION_BARRIER {
|
||||
|
22
third_party/rust/wgpu-hal/src/dx12/descriptor.rs
vendored
22
third_party/rust/wgpu-hal/src/dx12/descriptor.rs
vendored
@ -56,16 +56,18 @@ impl GeneralHeap {
|
||||
.into_device_result("Descriptor heap creation")?
|
||||
};
|
||||
|
||||
let start = DualHandle {
|
||||
cpu: unsafe { raw.GetCPUDescriptorHandleForHeapStart() },
|
||||
gpu: unsafe { raw.GetGPUDescriptorHandleForHeapStart() },
|
||||
count: 0,
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
raw: raw.clone(),
|
||||
raw,
|
||||
ty,
|
||||
handle_size: unsafe { device.GetDescriptorHandleIncrementSize(ty) } as u64,
|
||||
total_handles,
|
||||
start: DualHandle {
|
||||
cpu: unsafe { raw.GetCPUDescriptorHandleForHeapStart() },
|
||||
gpu: unsafe { raw.GetGPUDescriptorHandleForHeapStart() },
|
||||
count: 0,
|
||||
},
|
||||
start,
|
||||
ranges: Mutex::new(RangeAllocator::new(0..total_handles)),
|
||||
})
|
||||
}
|
||||
@ -268,12 +270,14 @@ impl CpuHeap {
|
||||
let raw = unsafe { device.CreateDescriptorHeap::<Direct3D12::ID3D12DescriptorHeap>(&desc) }
|
||||
.into_device_result("CPU descriptor heap creation")?;
|
||||
|
||||
let start = unsafe { raw.GetCPUDescriptorHandleForHeapStart() };
|
||||
|
||||
Ok(Self {
|
||||
inner: Mutex::new(CpuHeapInner {
|
||||
_raw: raw.clone(),
|
||||
_raw: raw,
|
||||
stage: Vec::new(),
|
||||
}),
|
||||
start: unsafe { raw.GetCPUDescriptorHandleForHeapStart() },
|
||||
start,
|
||||
handle_size,
|
||||
total,
|
||||
})
|
||||
@ -297,7 +301,7 @@ impl fmt::Debug for CpuHeap {
|
||||
}
|
||||
|
||||
pub(super) unsafe fn upload(
|
||||
device: Direct3D12::ID3D12Device,
|
||||
device: &Direct3D12::ID3D12Device,
|
||||
src: &CpuHeapInner,
|
||||
dst: &GeneralHeap,
|
||||
dummy_copy_counts: &[u32],
|
||||
|
51
third_party/rust/wgpu-hal/src/dx12/device.rs
vendored
51
third_party/rust/wgpu-hal/src/dx12/device.rs
vendored
@ -1,5 +1,6 @@
|
||||
use std::{
|
||||
ffi, mem,
|
||||
ffi,
|
||||
mem::{self, size_of},
|
||||
num::NonZeroU32,
|
||||
ptr,
|
||||
sync::Arc,
|
||||
@ -84,7 +85,7 @@ impl super::Device {
|
||||
}
|
||||
.into_device_result("Zero buffer creation")?;
|
||||
|
||||
let zero_buffer = zero_buffer.ok_or(crate::DeviceError::ResourceCreationFailed)?;
|
||||
let zero_buffer = zero_buffer.ok_or(crate::DeviceError::Unexpected)?;
|
||||
|
||||
// Note: without `D3D12_HEAP_FLAG_CREATE_NOT_ZEROED`
|
||||
// this resource is zeroed by default.
|
||||
@ -113,7 +114,7 @@ impl super::Device {
|
||||
)
|
||||
}
|
||||
.into_device_result("Command signature creation")?;
|
||||
signature.ok_or(crate::DeviceError::ResourceCreationFailed)
|
||||
signature.ok_or(crate::DeviceError::Unexpected)
|
||||
}
|
||||
|
||||
let shared = super::DeviceShared {
|
||||
@ -121,7 +122,7 @@ impl super::Device {
|
||||
cmd_signatures: super::CommandSignatures {
|
||||
draw: create_command_signature(
|
||||
&raw,
|
||||
mem::size_of::<wgt::DrawIndirectArgs>(),
|
||||
size_of::<wgt::DrawIndirectArgs>(),
|
||||
&[Direct3D12::D3D12_INDIRECT_ARGUMENT_DESC {
|
||||
Type: Direct3D12::D3D12_INDIRECT_ARGUMENT_TYPE_DRAW,
|
||||
..Default::default()
|
||||
@ -130,7 +131,7 @@ impl super::Device {
|
||||
)?,
|
||||
draw_indexed: create_command_signature(
|
||||
&raw,
|
||||
mem::size_of::<wgt::DrawIndexedIndirectArgs>(),
|
||||
size_of::<wgt::DrawIndexedIndirectArgs>(),
|
||||
&[Direct3D12::D3D12_INDIRECT_ARGUMENT_DESC {
|
||||
Type: Direct3D12::D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED,
|
||||
..Default::default()
|
||||
@ -139,7 +140,7 @@ impl super::Device {
|
||||
)?,
|
||||
dispatch: create_command_signature(
|
||||
&raw,
|
||||
mem::size_of::<wgt::DispatchIndirectArgs>(),
|
||||
size_of::<wgt::DispatchIndirectArgs>(),
|
||||
&[Direct3D12::D3D12_INDIRECT_ARGUMENT_DESC {
|
||||
Type: Direct3D12::D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH,
|
||||
..Default::default()
|
||||
@ -287,7 +288,7 @@ impl super::Device {
|
||||
};
|
||||
|
||||
let full_stage = format!(
|
||||
"{}_{}\0",
|
||||
"{}_{}",
|
||||
naga_stage.to_hlsl_str(),
|
||||
naga_options.shader_model.to_str()
|
||||
);
|
||||
@ -305,28 +306,33 @@ impl super::Device {
|
||||
let source_name = stage.module.raw_name.as_deref();
|
||||
|
||||
// Compile with DXC if available, otherwise fall back to FXC
|
||||
let (result, log_level) = if let Some(ref dxc_container) = self.dxc_container {
|
||||
let result = if let Some(ref dxc_container) = self.dxc_container {
|
||||
shader_compilation::compile_dxc(
|
||||
self,
|
||||
&source,
|
||||
source_name,
|
||||
raw_ep,
|
||||
stage_bit,
|
||||
full_stage,
|
||||
&full_stage,
|
||||
dxc_container,
|
||||
)
|
||||
} else {
|
||||
let full_stage = ffi::CStr::from_bytes_with_nul(full_stage.as_bytes()).unwrap();
|
||||
shader_compilation::compile_fxc(
|
||||
self,
|
||||
&source,
|
||||
source_name,
|
||||
&ffi::CString::new(raw_ep.as_str()).unwrap(),
|
||||
raw_ep,
|
||||
stage_bit,
|
||||
full_stage,
|
||||
&full_stage,
|
||||
)
|
||||
};
|
||||
|
||||
let log_level = if result.is_ok() {
|
||||
log::Level::Info
|
||||
} else {
|
||||
log::Level::Error
|
||||
};
|
||||
|
||||
log::log!(
|
||||
log_level,
|
||||
"Naga generated shader for {:?} at {:?}:\n{}",
|
||||
@ -387,7 +393,6 @@ impl crate::Device for super::Device {
|
||||
&self,
|
||||
desc: &crate::BufferDescriptor,
|
||||
) -> Result<super::Buffer, crate::DeviceError> {
|
||||
let mut resource = None;
|
||||
let mut size = desc.size;
|
||||
if desc.usage.contains(crate::BufferUses::UNIFORM) {
|
||||
let align_mask = Direct3D12::D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT as u64 - 1;
|
||||
@ -410,10 +415,8 @@ impl crate::Device for super::Device {
|
||||
Flags: conv::map_buffer_usage_to_resource_flags(desc.usage),
|
||||
};
|
||||
|
||||
let allocation =
|
||||
super::suballocation::create_buffer_resource(self, desc, raw_desc, &mut resource)?;
|
||||
|
||||
let resource = resource.ok_or(crate::DeviceError::ResourceCreationFailed)?;
|
||||
let (resource, allocation) =
|
||||
super::suballocation::create_buffer_resource(self, desc, raw_desc)?;
|
||||
|
||||
if let Some(label) = desc.label {
|
||||
unsafe { resource.SetName(&windows::core::HSTRING::from(label)) }
|
||||
@ -470,10 +473,6 @@ impl crate::Device for super::Device {
|
||||
&self,
|
||||
desc: &crate::TextureDescriptor,
|
||||
) -> Result<super::Texture, crate::DeviceError> {
|
||||
use super::suballocation::create_texture_resource;
|
||||
|
||||
let mut resource = None;
|
||||
|
||||
let raw_desc = Direct3D12::D3D12_RESOURCE_DESC {
|
||||
Dimension: conv::map_texture_dimension(desc.dimension),
|
||||
Alignment: 0,
|
||||
@ -495,9 +494,9 @@ impl crate::Device for super::Device {
|
||||
Flags: conv::map_texture_usage_to_resource_flags(desc.usage),
|
||||
};
|
||||
|
||||
let allocation = create_texture_resource(self, desc, raw_desc, &mut resource)?;
|
||||
let (resource, allocation) =
|
||||
super::suballocation::create_texture_resource(self, desc, raw_desc)?;
|
||||
|
||||
let resource = resource.ok_or(crate::DeviceError::ResourceCreationFailed)?;
|
||||
if let Some(label) = desc.label {
|
||||
unsafe { resource.SetName(&windows::core::HSTRING::from(label)) }
|
||||
.into_device_result("SetName")?;
|
||||
@ -1295,7 +1294,7 @@ impl crate::Device for super::Device {
|
||||
Some(inner) => {
|
||||
let dual = unsafe {
|
||||
descriptor::upload(
|
||||
self.raw.clone(),
|
||||
&self.raw,
|
||||
&inner,
|
||||
&self.shared.heap_views,
|
||||
&desc.layout.copy_counts,
|
||||
@ -1309,7 +1308,7 @@ impl crate::Device for super::Device {
|
||||
Some(inner) => {
|
||||
let dual = unsafe {
|
||||
descriptor::upload(
|
||||
self.raw.clone(),
|
||||
&self.raw,
|
||||
&inner,
|
||||
&self.shared.heap_samplers,
|
||||
&desc.layout.copy_counts,
|
||||
@ -1643,7 +1642,7 @@ impl crate::Device for super::Device {
|
||||
}
|
||||
.into_device_result("Query heap creation")?;
|
||||
|
||||
let raw = raw.ok_or(crate::DeviceError::ResourceCreationFailed)?;
|
||||
let raw = raw.ok_or(crate::DeviceError::Unexpected)?;
|
||||
|
||||
if let Some(label) = desc.label {
|
||||
unsafe { raw.SetName(&windows::core::HSTRING::from(label)) }
|
||||
|
70
third_party/rust/wgpu-hal/src/dx12/instance.rs
vendored
70
third_party/rust/wgpu-hal/src/dx12/instance.rs
vendored
@ -1,4 +1,4 @@
|
||||
use std::sync::Arc;
|
||||
use std::{mem::size_of_val, sync::Arc};
|
||||
|
||||
use parking_lot::RwLock;
|
||||
use windows::{
|
||||
@ -10,10 +10,7 @@ use windows::{
|
||||
};
|
||||
|
||||
use super::SurfaceTarget;
|
||||
use crate::{
|
||||
auxil::{self, dxgi::result::HResult as _},
|
||||
dx12::D3D12Lib,
|
||||
};
|
||||
use crate::{auxil, dx12::D3D12Lib};
|
||||
|
||||
impl Drop for super::Instance {
|
||||
fn drop(&mut self) {
|
||||
@ -37,55 +34,28 @@ impl crate::Instance for super::Instance {
|
||||
.intersects(wgt::InstanceFlags::VALIDATION | wgt::InstanceFlags::GPU_BASED_VALIDATION)
|
||||
{
|
||||
// Enable debug layer
|
||||
match lib_main.debug_interface() {
|
||||
Ok(pair) => match pair {
|
||||
Ok(debug_controller) => {
|
||||
if desc.flags.intersects(wgt::InstanceFlags::VALIDATION) {
|
||||
unsafe { debug_controller.EnableDebugLayer() }
|
||||
}
|
||||
if desc
|
||||
.flags
|
||||
.intersects(wgt::InstanceFlags::GPU_BASED_VALIDATION)
|
||||
{
|
||||
#[allow(clippy::collapsible_if)]
|
||||
if let Ok(debug1) = debug_controller.cast::<Direct3D12::ID3D12Debug1>()
|
||||
{
|
||||
unsafe { debug1.SetEnableGPUBasedValidation(true) }
|
||||
} else {
|
||||
log::warn!("Failed to enable GPU-based validation");
|
||||
}
|
||||
}
|
||||
if let Ok(debug_controller) = lib_main.debug_interface() {
|
||||
if desc.flags.intersects(wgt::InstanceFlags::VALIDATION) {
|
||||
unsafe { debug_controller.EnableDebugLayer() }
|
||||
}
|
||||
if desc
|
||||
.flags
|
||||
.intersects(wgt::InstanceFlags::GPU_BASED_VALIDATION)
|
||||
{
|
||||
#[allow(clippy::collapsible_if)]
|
||||
if let Ok(debug1) = debug_controller.cast::<Direct3D12::ID3D12Debug1>() {
|
||||
unsafe { debug1.SetEnableGPUBasedValidation(true) }
|
||||
} else {
|
||||
log::warn!("Failed to enable GPU-based validation");
|
||||
}
|
||||
Err(err) => {
|
||||
log::warn!("Unable to enable D3D12 debug interface: {}", err);
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
log::warn!("Debug interface function for D3D12 not found: {:?}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create DXGIFactory4
|
||||
let (lib_dxgi, factory) = auxil::dxgi::factory::create_factory(
|
||||
auxil::dxgi::factory::DxgiFactoryType::Factory4,
|
||||
desc.flags,
|
||||
)?;
|
||||
let (lib_dxgi, factory) = auxil::dxgi::factory::create_factory(desc.flags)?;
|
||||
|
||||
// Create IDXGIFactoryMedia
|
||||
let factory_media = match lib_dxgi.create_factory_media() {
|
||||
Ok(pair) => match pair {
|
||||
Ok(factory_media) => Some(factory_media),
|
||||
Err(err) => {
|
||||
log::error!("Failed to create IDXGIFactoryMedia: {}", err);
|
||||
None
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
log::warn!("IDXGIFactory1 creation function not found: {:?}", err);
|
||||
None
|
||||
}
|
||||
};
|
||||
let factory_media = lib_dxgi.create_factory_media().ok();
|
||||
|
||||
let mut supports_allow_tearing = false;
|
||||
if let Some(factory5) = factory.as_factory5() {
|
||||
@ -94,12 +64,12 @@ impl crate::Instance for super::Instance {
|
||||
factory5.CheckFeatureSupport(
|
||||
Dxgi::DXGI_FEATURE_PRESENT_ALLOW_TEARING,
|
||||
<*mut _>::cast(&mut allow_tearing),
|
||||
std::mem::size_of_val(&allow_tearing) as u32,
|
||||
size_of_val(&allow_tearing) as u32,
|
||||
)
|
||||
};
|
||||
|
||||
match hr.into_result() {
|
||||
Err(err) => log::warn!("Unable to check for tearing support: {}", err),
|
||||
match hr {
|
||||
Err(err) => log::warn!("Unable to check for tearing support: {err}"),
|
||||
Ok(()) => supports_allow_tearing = true,
|
||||
}
|
||||
}
|
||||
|
211
third_party/rust/wgpu-hal/src/dx12/mod.rs
vendored
211
third_party/rust/wgpu-hal/src/dx12/mod.rs
vendored
@ -49,14 +49,13 @@ use std::{ffi, fmt, mem, num::NonZeroU32, ops::Deref, sync::Arc};
|
||||
use arrayvec::ArrayVec;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use windows::{
|
||||
core::{Interface, Param as _},
|
||||
core::{Free, Interface},
|
||||
Win32::{
|
||||
Foundation,
|
||||
Graphics::{Direct3D, Direct3D12, DirectComposition, Dxgi},
|
||||
System::Threading,
|
||||
},
|
||||
};
|
||||
use windows_core::Free;
|
||||
|
||||
use crate::auxil::{
|
||||
self,
|
||||
@ -66,21 +65,50 @@ use crate::auxil::{
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct DynLib {
|
||||
inner: libloading::Library,
|
||||
}
|
||||
|
||||
impl DynLib {
|
||||
unsafe fn new<P>(filename: P) -> Result<Self, libloading::Error>
|
||||
where
|
||||
P: AsRef<ffi::OsStr>,
|
||||
{
|
||||
unsafe { libloading::Library::new(filename) }.map(|inner| Self { inner })
|
||||
}
|
||||
|
||||
unsafe fn get<T>(
|
||||
&self,
|
||||
symbol: &[u8],
|
||||
) -> Result<libloading::Symbol<'_, T>, crate::DeviceError> {
|
||||
unsafe { self.inner.get(symbol) }.map_err(|e| match e {
|
||||
libloading::Error::GetProcAddress { .. } | libloading::Error::GetProcAddressUnknown => {
|
||||
crate::DeviceError::Unexpected
|
||||
}
|
||||
libloading::Error::IncompatibleSize
|
||||
| libloading::Error::CreateCString { .. }
|
||||
| libloading::Error::CreateCStringWithTrailing { .. } => crate::hal_internal_error(e),
|
||||
_ => crate::DeviceError::Unexpected, // could be unreachable!() but we prefer to be more robust
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct D3D12Lib {
|
||||
lib: libloading::Library,
|
||||
lib: DynLib,
|
||||
}
|
||||
|
||||
impl D3D12Lib {
|
||||
fn new() -> Result<Self, libloading::Error> {
|
||||
unsafe { libloading::Library::new("d3d12.dll").map(|lib| D3D12Lib { lib }) }
|
||||
unsafe { DynLib::new("d3d12.dll").map(|lib| Self { lib }) }
|
||||
}
|
||||
|
||||
fn create_device(
|
||||
&self,
|
||||
adapter: &DxgiAdapter,
|
||||
feature_level: Direct3D::D3D_FEATURE_LEVEL,
|
||||
) -> Result<windows_core::Result<Direct3D12::ID3D12Device>, libloading::Error> {
|
||||
) -> Result<Direct3D12::ID3D12Device, crate::DeviceError> {
|
||||
// Calls windows::Win32::Graphics::Direct3D12::D3D12CreateDevice on d3d12.dll
|
||||
type Fun = extern "system" fn(
|
||||
padapter: *mut core::ffi::c_void,
|
||||
@ -88,17 +116,21 @@ impl D3D12Lib {
|
||||
riid: *const windows_core::GUID,
|
||||
ppdevice: *mut *mut core::ffi::c_void,
|
||||
) -> windows_core::HRESULT;
|
||||
let func: libloading::Symbol<Fun> = unsafe { self.lib.get(b"D3D12CreateDevice") }?;
|
||||
let func: libloading::Symbol<Fun> = unsafe { self.lib.get(b"D3D12CreateDevice\0") }?;
|
||||
|
||||
let mut result__ = None;
|
||||
Ok((func)(
|
||||
unsafe { adapter.param().abi() },
|
||||
|
||||
(func)(
|
||||
adapter.as_raw(),
|
||||
feature_level,
|
||||
// TODO: Generic?
|
||||
&Direct3D12::ID3D12Device::IID,
|
||||
<*mut _>::cast(&mut result__),
|
||||
)
|
||||
.map(|| result__.expect("D3D12CreateDevice succeeded but result is NULL?")))
|
||||
.ok()
|
||||
.into_device_result("Device creation")?;
|
||||
|
||||
result__.ok_or(crate::DeviceError::Unexpected)
|
||||
}
|
||||
|
||||
fn serialize_root_signature(
|
||||
@ -115,11 +147,8 @@ impl D3D12Lib {
|
||||
ppblob: *mut *mut core::ffi::c_void,
|
||||
pperrorblob: *mut *mut core::ffi::c_void,
|
||||
) -> windows_core::HRESULT;
|
||||
let func: libloading::Symbol<Fun> = unsafe { self.lib.get(b"D3D12SerializeRootSignature") }
|
||||
.map_err(|e| {
|
||||
log::error!("Unable to find serialization function: {:?}", e);
|
||||
crate::DeviceError::Lost
|
||||
})?;
|
||||
let func: libloading::Symbol<Fun> =
|
||||
unsafe { self.lib.get(b"D3D12SerializeRootSignature\0") }?;
|
||||
|
||||
let desc = Direct3D12::D3D12_ROOT_SIGNATURE_DESC {
|
||||
NumParameters: parameters.len() as _,
|
||||
@ -138,8 +167,6 @@ impl D3D12Lib {
|
||||
<*mut _>::cast(&mut error),
|
||||
)
|
||||
.ok()
|
||||
// TODO: If there's a HRESULT, error may still be non-null and
|
||||
// contain info.
|
||||
.into_device_result("Root signature serialization")?;
|
||||
|
||||
if let Some(error) = error {
|
||||
@ -148,104 +175,102 @@ impl D3D12Lib {
|
||||
"Root signature serialization error: {:?}",
|
||||
unsafe { error.as_c_str() }.unwrap().to_str().unwrap()
|
||||
);
|
||||
return Err(crate::DeviceError::Lost);
|
||||
return Err(crate::DeviceError::Unexpected); // could be hal_usage_error or hal_internal_error
|
||||
}
|
||||
|
||||
Ok(D3DBlob(blob.expect(
|
||||
"D3D12SerializeRootSignature succeeded but result is NULL?",
|
||||
)))
|
||||
blob.ok_or(crate::DeviceError::Unexpected)
|
||||
}
|
||||
|
||||
fn debug_interface(
|
||||
&self,
|
||||
) -> Result<windows::core::Result<Direct3D12::ID3D12Debug>, libloading::Error> {
|
||||
fn debug_interface(&self) -> Result<Direct3D12::ID3D12Debug, crate::DeviceError> {
|
||||
// Calls windows::Win32::Graphics::Direct3D12::D3D12GetDebugInterface on d3d12.dll
|
||||
type Fun = extern "system" fn(
|
||||
riid: *const windows_core::GUID,
|
||||
ppvdebug: *mut *mut core::ffi::c_void,
|
||||
) -> windows_core::HRESULT;
|
||||
let func: libloading::Symbol<Fun> = unsafe { self.lib.get(b"D3D12GetDebugInterface") }?;
|
||||
let func: libloading::Symbol<Fun> = unsafe { self.lib.get(b"D3D12GetDebugInterface\0") }?;
|
||||
|
||||
let mut result__ = core::ptr::null_mut();
|
||||
Ok((func)(&Direct3D12::ID3D12Debug::IID, &mut result__)
|
||||
.and_then(|| unsafe { windows_core::Type::from_abi(result__) }))
|
||||
let mut result__ = None;
|
||||
|
||||
(func)(&Direct3D12::ID3D12Debug::IID, <*mut _>::cast(&mut result__))
|
||||
.ok()
|
||||
.into_device_result("GetDebugInterface")?;
|
||||
|
||||
result__.ok_or(crate::DeviceError::Unexpected)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct DxgiLib {
|
||||
lib: libloading::Library,
|
||||
lib: DynLib,
|
||||
}
|
||||
|
||||
impl DxgiLib {
|
||||
pub fn new() -> Result<Self, libloading::Error> {
|
||||
unsafe { libloading::Library::new("dxgi.dll").map(|lib| DxgiLib { lib }) }
|
||||
unsafe { DynLib::new("dxgi.dll").map(|lib| Self { lib }) }
|
||||
}
|
||||
|
||||
pub fn debug_interface1(
|
||||
&self,
|
||||
) -> Result<windows::core::Result<Dxgi::IDXGIInfoQueue>, libloading::Error> {
|
||||
/// Will error with crate::DeviceError::Unexpected if DXGI 1.3 is not available.
|
||||
pub fn debug_interface1(&self) -> Result<Dxgi::IDXGIInfoQueue, crate::DeviceError> {
|
||||
// Calls windows::Win32::Graphics::Dxgi::DXGIGetDebugInterface1 on dxgi.dll
|
||||
type Fun = extern "system" fn(
|
||||
flags: u32,
|
||||
riid: *const windows_core::GUID,
|
||||
pdebug: *mut *mut core::ffi::c_void,
|
||||
) -> windows_core::HRESULT;
|
||||
let func: libloading::Symbol<Fun> = unsafe { self.lib.get(b"DXGIGetDebugInterface1") }?;
|
||||
let func: libloading::Symbol<Fun> = unsafe { self.lib.get(b"DXGIGetDebugInterface1\0") }?;
|
||||
|
||||
let mut result__ = core::ptr::null_mut();
|
||||
Ok((func)(0, &Dxgi::IDXGIInfoQueue::IID, &mut result__)
|
||||
.and_then(|| unsafe { windows_core::Type::from_abi(result__) }))
|
||||
let mut result__ = None;
|
||||
|
||||
(func)(0, &Dxgi::IDXGIInfoQueue::IID, <*mut _>::cast(&mut result__))
|
||||
.ok()
|
||||
.into_device_result("debug_interface1")?;
|
||||
|
||||
result__.ok_or(crate::DeviceError::Unexpected)
|
||||
}
|
||||
|
||||
pub fn create_factory1(
|
||||
&self,
|
||||
) -> Result<windows::core::Result<Dxgi::IDXGIFactory1>, libloading::Error> {
|
||||
// Calls windows::Win32::Graphics::Dxgi::CreateDXGIFactory1 on dxgi.dll
|
||||
type Fun = extern "system" fn(
|
||||
riid: *const windows_core::GUID,
|
||||
ppfactory: *mut *mut core::ffi::c_void,
|
||||
) -> windows_core::HRESULT;
|
||||
let func: libloading::Symbol<Fun> = unsafe { self.lib.get(b"CreateDXGIFactory1") }?;
|
||||
|
||||
let mut result__ = core::ptr::null_mut();
|
||||
Ok((func)(&Dxgi::IDXGIFactory1::IID, &mut result__)
|
||||
.and_then(|| unsafe { windows_core::Type::from_abi(result__) }))
|
||||
}
|
||||
|
||||
pub fn create_factory2(
|
||||
/// Will error with crate::DeviceError::Unexpected if DXGI 1.4 is not available.
|
||||
pub fn create_factory4(
|
||||
&self,
|
||||
factory_flags: Dxgi::DXGI_CREATE_FACTORY_FLAGS,
|
||||
) -> Result<windows::core::Result<Dxgi::IDXGIFactory4>, libloading::Error> {
|
||||
) -> Result<Dxgi::IDXGIFactory4, crate::DeviceError> {
|
||||
// Calls windows::Win32::Graphics::Dxgi::CreateDXGIFactory2 on dxgi.dll
|
||||
type Fun = extern "system" fn(
|
||||
flags: Dxgi::DXGI_CREATE_FACTORY_FLAGS,
|
||||
riid: *const windows_core::GUID,
|
||||
ppfactory: *mut *mut core::ffi::c_void,
|
||||
) -> windows_core::HRESULT;
|
||||
let func: libloading::Symbol<Fun> = unsafe { self.lib.get(b"CreateDXGIFactory2") }?;
|
||||
let func: libloading::Symbol<Fun> = unsafe { self.lib.get(b"CreateDXGIFactory2\0") }?;
|
||||
|
||||
let mut result__ = core::ptr::null_mut();
|
||||
Ok(
|
||||
(func)(factory_flags, &Dxgi::IDXGIFactory4::IID, &mut result__)
|
||||
.and_then(|| unsafe { windows_core::Type::from_abi(result__) }),
|
||||
let mut result__ = None;
|
||||
|
||||
(func)(
|
||||
factory_flags,
|
||||
&Dxgi::IDXGIFactory4::IID,
|
||||
<*mut _>::cast(&mut result__),
|
||||
)
|
||||
.ok()
|
||||
.into_device_result("create_factory4")?;
|
||||
|
||||
result__.ok_or(crate::DeviceError::Unexpected)
|
||||
}
|
||||
|
||||
pub fn create_factory_media(
|
||||
&self,
|
||||
) -> Result<windows::core::Result<Dxgi::IDXGIFactoryMedia>, libloading::Error> {
|
||||
/// Will error with crate::DeviceError::Unexpected if DXGI 1.3 is not available.
|
||||
pub fn create_factory_media(&self) -> Result<Dxgi::IDXGIFactoryMedia, crate::DeviceError> {
|
||||
// Calls windows::Win32::Graphics::Dxgi::CreateDXGIFactory1 on dxgi.dll
|
||||
type Fun = extern "system" fn(
|
||||
riid: *const windows_core::GUID,
|
||||
ppfactory: *mut *mut core::ffi::c_void,
|
||||
) -> windows_core::HRESULT;
|
||||
let func: libloading::Symbol<Fun> = unsafe { self.lib.get(b"CreateDXGIFactory1") }?;
|
||||
let func: libloading::Symbol<Fun> = unsafe { self.lib.get(b"CreateDXGIFactory1\0") }?;
|
||||
|
||||
let mut result__ = None;
|
||||
|
||||
let mut result__ = core::ptr::null_mut();
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/dxgi1_3/nn-dxgi1_3-idxgifactorymedia
|
||||
Ok((func)(&Dxgi::IDXGIFactoryMedia::IID, &mut result__)
|
||||
.and_then(|| unsafe { windows_core::Type::from_abi(result__) }))
|
||||
(func)(&Dxgi::IDXGIFactoryMedia::IID, <*mut _>::cast(&mut result__))
|
||||
.ok()
|
||||
.into_device_result("create_factory_media")?;
|
||||
|
||||
result__.ok_or(crate::DeviceError::Unexpected)
|
||||
}
|
||||
}
|
||||
|
||||
@ -368,7 +393,7 @@ pub struct Instance {
|
||||
}
|
||||
|
||||
impl Instance {
|
||||
pub unsafe fn create_surface_from_visual(&self, visual: *mut std::ffi::c_void) -> Surface {
|
||||
pub unsafe fn create_surface_from_visual(&self, visual: *mut ffi::c_void) -> Surface {
|
||||
let visual = unsafe { DirectComposition::IDCompositionVisual::from_raw_borrowed(&visual) }
|
||||
.expect("COM pointer should not be NULL");
|
||||
Surface {
|
||||
@ -382,7 +407,7 @@ impl Instance {
|
||||
|
||||
pub unsafe fn create_surface_from_surface_handle(
|
||||
&self,
|
||||
surface_handle: *mut std::ffi::c_void,
|
||||
surface_handle: *mut ffi::c_void,
|
||||
) -> Surface {
|
||||
// TODO: We're not given ownership, so we shouldn't call HANDLE::free(). This puts an extra burden on the caller to keep it alive.
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-duplicatehandle could help us, even though DirectComposition is not in the list?
|
||||
@ -399,7 +424,7 @@ impl Instance {
|
||||
|
||||
pub unsafe fn create_surface_from_swap_chain_panel(
|
||||
&self,
|
||||
swap_chain_panel: *mut std::ffi::c_void,
|
||||
swap_chain_panel: *mut ffi::c_void,
|
||||
) -> Surface {
|
||||
let swap_chain_panel =
|
||||
unsafe { types::ISwapChainPanelNative::from_raw_borrowed(&swap_chain_panel) }
|
||||
@ -622,7 +647,7 @@ struct PassState {
|
||||
|
||||
#[test]
|
||||
fn test_dirty_mask() {
|
||||
assert_eq!(MAX_ROOT_ELEMENTS, mem::size_of::<u64>() * 8);
|
||||
assert_eq!(MAX_ROOT_ELEMENTS, u64::BITS as usize);
|
||||
}
|
||||
|
||||
impl PassState {
|
||||
@ -897,8 +922,7 @@ pub struct ShaderModule {
|
||||
impl crate::DynShaderModule for ShaderModule {}
|
||||
|
||||
pub(super) enum CompiledShader {
|
||||
#[allow(unused)]
|
||||
Dxc(Vec<u8>),
|
||||
Dxc(Direct3D::Dxc::IDxcBlob),
|
||||
Fxc(Direct3D::ID3DBlob),
|
||||
}
|
||||
|
||||
@ -906,8 +930,8 @@ impl CompiledShader {
|
||||
fn create_native_shader(&self) -> Direct3D12::D3D12_SHADER_BYTECODE {
|
||||
match self {
|
||||
CompiledShader::Dxc(shader) => Direct3D12::D3D12_SHADER_BYTECODE {
|
||||
pShaderBytecode: shader.as_ptr().cast(),
|
||||
BytecodeLength: shader.len(),
|
||||
pShaderBytecode: unsafe { shader.GetBufferPointer() },
|
||||
BytecodeLength: unsafe { shader.GetBufferSize() },
|
||||
},
|
||||
CompiledShader::Fxc(shader) => Direct3D12::D3D12_SHADER_BYTECODE {
|
||||
pShaderBytecode: unsafe { shader.GetBufferPointer() },
|
||||
@ -1026,8 +1050,8 @@ impl crate::Surface for Surface {
|
||||
flags,
|
||||
)
|
||||
};
|
||||
if let Err(err) = result.into_result() {
|
||||
log::error!("ResizeBuffers failed: {}", err);
|
||||
if let Err(err) = result {
|
||||
log::error!("ResizeBuffers failed: {err}");
|
||||
return Err(crate::SurfaceError::Other("window is in use"));
|
||||
}
|
||||
raw
|
||||
@ -1053,11 +1077,13 @@ impl crate::Surface for Surface {
|
||||
};
|
||||
let swap_chain1 = match self.target {
|
||||
SurfaceTarget::Visual(_) | SurfaceTarget::SwapChainPanel(_) => {
|
||||
profiling::scope!("IDXGIFactory4::CreateSwapChainForComposition");
|
||||
profiling::scope!("IDXGIFactory2::CreateSwapChainForComposition");
|
||||
unsafe {
|
||||
self.factory
|
||||
.unwrap_factory2()
|
||||
.CreateSwapChainForComposition(&device.present_queue, &desc, None)
|
||||
self.factory.CreateSwapChainForComposition(
|
||||
&device.present_queue,
|
||||
&desc,
|
||||
None,
|
||||
)
|
||||
}
|
||||
}
|
||||
SurfaceTarget::SurfaceHandle(handle) => {
|
||||
@ -1077,9 +1103,9 @@ impl crate::Surface for Surface {
|
||||
}
|
||||
}
|
||||
SurfaceTarget::WndHandle(hwnd) => {
|
||||
profiling::scope!("IDXGIFactory4::CreateSwapChainForHwnd");
|
||||
profiling::scope!("IDXGIFactory2::CreateSwapChainForHwnd");
|
||||
unsafe {
|
||||
self.factory.unwrap_factory2().CreateSwapChainForHwnd(
|
||||
self.factory.CreateSwapChainForHwnd(
|
||||
&device.present_queue,
|
||||
hwnd,
|
||||
&desc,
|
||||
@ -1092,24 +1118,22 @@ impl crate::Surface for Surface {
|
||||
|
||||
let swap_chain1 = swap_chain1.map_err(|err| {
|
||||
log::error!("SwapChain creation error: {}", err);
|
||||
crate::SurfaceError::Other("swap chain creation")
|
||||
crate::SurfaceError::Other("swapchain creation")
|
||||
})?;
|
||||
|
||||
match &self.target {
|
||||
SurfaceTarget::WndHandle(_) | SurfaceTarget::SurfaceHandle(_) => {}
|
||||
SurfaceTarget::Visual(visual) => {
|
||||
if let Err(err) = unsafe { visual.SetContent(&swap_chain1) }.into_result() {
|
||||
log::error!("Unable to SetContent: {}", err);
|
||||
if let Err(err) = unsafe { visual.SetContent(&swap_chain1) } {
|
||||
log::error!("Unable to SetContent: {err}");
|
||||
return Err(crate::SurfaceError::Other(
|
||||
"IDCompositionVisual::SetContent",
|
||||
));
|
||||
}
|
||||
}
|
||||
SurfaceTarget::SwapChainPanel(swap_chain_panel) => {
|
||||
if let Err(err) =
|
||||
unsafe { swap_chain_panel.SetSwapChain(&swap_chain1) }.into_result()
|
||||
{
|
||||
log::error!("Unable to SetSwapChain: {}", err);
|
||||
if let Err(err) = unsafe { swap_chain_panel.SetSwapChain(&swap_chain1) } {
|
||||
log::error!("Unable to SetSwapChain: {err}");
|
||||
return Err(crate::SurfaceError::Other(
|
||||
"ISwapChainPanelNative::SetSwapChain",
|
||||
));
|
||||
@ -1117,13 +1141,10 @@ impl crate::Surface for Surface {
|
||||
}
|
||||
}
|
||||
|
||||
match swap_chain1.cast::<Dxgi::IDXGISwapChain3>() {
|
||||
Ok(swap_chain3) => swap_chain3,
|
||||
Err(err) => {
|
||||
log::error!("Unable to cast swap chain: {}", err);
|
||||
return Err(crate::SurfaceError::Other("swap chain cast to 3"));
|
||||
}
|
||||
}
|
||||
swap_chain1.cast::<Dxgi::IDXGISwapChain3>().map_err(|err| {
|
||||
log::error!("Unable to cast swapchain: {err}");
|
||||
crate::SurfaceError::Other("swapchain cast to version 3")
|
||||
})?
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,13 +1,11 @@
|
||||
use std::ffi::CStr;
|
||||
use std::ptr;
|
||||
|
||||
pub(super) use dxc::{compile_dxc, get_dxc_container, DxcContainer};
|
||||
use windows::Win32::Graphics::Direct3D;
|
||||
|
||||
use crate::auxil::dxgi::result::HResult;
|
||||
use std::ffi::CStr;
|
||||
use std::path::PathBuf;
|
||||
use windows::{
|
||||
core::{Interface, PCSTR, PCWSTR},
|
||||
Win32::Graphics::Direct3D::{Dxc, Fxc},
|
||||
};
|
||||
|
||||
// This exists so that users who don't want to use dxc can disable the dxc_shader_compiler feature
|
||||
// and not have to compile hassle_rs.
|
||||
// Currently this will use Dxc if it is chosen as the dx12 compiler at `Instance` creation time, and will
|
||||
// fallback to FXC if the Dxc libraries (dxil.dll and dxcompiler.dll) are not found, or if Fxc is chosen at'
|
||||
// `Instance` creation time.
|
||||
@ -16,40 +14,41 @@ pub(super) fn compile_fxc(
|
||||
device: &super::Device,
|
||||
source: &str,
|
||||
source_name: Option<&CStr>,
|
||||
raw_ep: &CStr,
|
||||
raw_ep: &str,
|
||||
stage_bit: wgt::ShaderStages,
|
||||
full_stage: &CStr,
|
||||
) -> (
|
||||
Result<super::CompiledShader, crate::PipelineError>,
|
||||
log::Level,
|
||||
) {
|
||||
full_stage: &str,
|
||||
) -> Result<super::CompiledShader, crate::PipelineError> {
|
||||
profiling::scope!("compile_fxc");
|
||||
let mut shader_data = None;
|
||||
let mut compile_flags = Direct3D::Fxc::D3DCOMPILE_ENABLE_STRICTNESS;
|
||||
let mut compile_flags = Fxc::D3DCOMPILE_ENABLE_STRICTNESS;
|
||||
if device
|
||||
.private_caps
|
||||
.instance_flags
|
||||
.contains(wgt::InstanceFlags::DEBUG)
|
||||
{
|
||||
compile_flags |=
|
||||
Direct3D::Fxc::D3DCOMPILE_DEBUG | Direct3D::Fxc::D3DCOMPILE_SKIP_OPTIMIZATION;
|
||||
compile_flags |= Fxc::D3DCOMPILE_DEBUG | Fxc::D3DCOMPILE_SKIP_OPTIMIZATION;
|
||||
}
|
||||
|
||||
let raw_ep = std::ffi::CString::new(raw_ep).unwrap();
|
||||
let full_stage = std::ffi::CString::new(full_stage).unwrap();
|
||||
|
||||
// If no name has been set, D3DCompile wants the null pointer.
|
||||
let source_name = source_name.map(|cstr| cstr.as_ptr()).unwrap_or(ptr::null());
|
||||
let source_name = source_name
|
||||
.map(|cstr| cstr.as_ptr().cast())
|
||||
.unwrap_or(core::ptr::null());
|
||||
|
||||
let mut error = None;
|
||||
let hr = unsafe {
|
||||
profiling::scope!("Direct3D::Fxc::D3DCompile");
|
||||
Direct3D::Fxc::D3DCompile(
|
||||
profiling::scope!("Fxc::D3DCompile");
|
||||
Fxc::D3DCompile(
|
||||
// TODO: Update low-level bindings to accept a slice here
|
||||
source.as_ptr().cast(),
|
||||
source.len(),
|
||||
windows::core::PCSTR(source_name.cast()),
|
||||
PCSTR(source_name),
|
||||
None,
|
||||
None,
|
||||
windows::core::PCSTR(raw_ep.as_ptr().cast()),
|
||||
windows::core::PCSTR(full_stage.as_ptr().cast()),
|
||||
PCSTR(raw_ep.as_ptr().cast()),
|
||||
PCSTR(full_stage.as_ptr().cast()),
|
||||
compile_flags,
|
||||
0,
|
||||
&mut shader_data,
|
||||
@ -57,13 +56,10 @@ pub(super) fn compile_fxc(
|
||||
)
|
||||
};
|
||||
|
||||
match hr.into_result() {
|
||||
match hr {
|
||||
Ok(()) => {
|
||||
let shader_data = shader_data.unwrap();
|
||||
(
|
||||
Ok(super::CompiledShader::Fxc(shader_data)),
|
||||
log::Level::Info,
|
||||
)
|
||||
Ok(super::CompiledShader::Fxc(shader_data))
|
||||
}
|
||||
Err(e) => {
|
||||
let mut full_msg = format!("FXC D3DCompile error ({e})");
|
||||
@ -77,234 +73,237 @@ pub(super) fn compile_fxc(
|
||||
};
|
||||
let _ = write!(full_msg, ": {}", String::from_utf8_lossy(message));
|
||||
}
|
||||
(
|
||||
Err(crate::PipelineError::Linkage(stage_bit, full_msg)),
|
||||
log::Level::Warn,
|
||||
)
|
||||
Err(crate::PipelineError::Linkage(stage_bit, full_msg))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The Dxc implementation is behind a feature flag so that users who don't want to use dxc can disable the feature.
|
||||
#[cfg(feature = "dxc_shader_compiler")]
|
||||
mod dxc {
|
||||
use std::ffi::CStr;
|
||||
use std::path::PathBuf;
|
||||
trait DxcObj: Interface {
|
||||
const CLSID: windows::core::GUID;
|
||||
}
|
||||
impl DxcObj for Dxc::IDxcCompiler3 {
|
||||
const CLSID: windows::core::GUID = Dxc::CLSID_DxcCompiler;
|
||||
}
|
||||
impl DxcObj for Dxc::IDxcUtils {
|
||||
const CLSID: windows::core::GUID = Dxc::CLSID_DxcUtils;
|
||||
}
|
||||
impl DxcObj for Dxc::IDxcValidator {
|
||||
const CLSID: windows::core::GUID = Dxc::CLSID_DxcValidator;
|
||||
}
|
||||
|
||||
// Destructor order should be fine since _dxil and _dxc don't rely on each other.
|
||||
pub(crate) struct DxcContainer {
|
||||
compiler: hassle_rs::DxcCompiler,
|
||||
library: hassle_rs::DxcLibrary,
|
||||
validator: hassle_rs::DxcValidator,
|
||||
// Has to be held onto for the lifetime of the device otherwise shaders will fail to compile.
|
||||
_dxc: hassle_rs::Dxc,
|
||||
// Also Has to be held onto for the lifetime of the device otherwise shaders will fail to validate.
|
||||
_dxil: hassle_rs::Dxil,
|
||||
}
|
||||
#[derive(Debug)]
|
||||
struct DxcLib {
|
||||
lib: crate::dx12::DynLib,
|
||||
}
|
||||
|
||||
pub(crate) fn get_dxc_container(
|
||||
dxc_path: Option<PathBuf>,
|
||||
dxil_path: Option<PathBuf>,
|
||||
) -> Result<Option<DxcContainer>, crate::DeviceError> {
|
||||
// Make sure that dxil.dll exists.
|
||||
let dxil = match hassle_rs::Dxil::new(dxil_path) {
|
||||
Ok(dxil) => dxil,
|
||||
Err(e) => {
|
||||
log::warn!("Failed to load dxil.dll. Defaulting to FXC instead: {}", e);
|
||||
return Ok(None);
|
||||
impl DxcLib {
|
||||
fn new(lib_path: Option<PathBuf>, lib_name: &'static str) -> Result<Self, libloading::Error> {
|
||||
let lib_path = if let Some(lib_path) = lib_path {
|
||||
if lib_path.is_file() {
|
||||
lib_path
|
||||
} else {
|
||||
lib_path.join(lib_name)
|
||||
}
|
||||
} else {
|
||||
PathBuf::from(lib_name)
|
||||
};
|
||||
|
||||
// Needed for explicit validation.
|
||||
let validator = dxil.create_validator()?;
|
||||
|
||||
let dxc = match hassle_rs::Dxc::new(dxc_path) {
|
||||
Ok(dxc) => dxc,
|
||||
Err(e) => {
|
||||
log::warn!(
|
||||
"Failed to load dxcompiler.dll. Defaulting to FXC instead: {}",
|
||||
e
|
||||
);
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
let compiler = dxc.create_compiler()?;
|
||||
let library = dxc.create_library()?;
|
||||
|
||||
Ok(Some(DxcContainer {
|
||||
_dxc: dxc,
|
||||
compiler,
|
||||
library,
|
||||
_dxil: dxil,
|
||||
validator,
|
||||
}))
|
||||
unsafe { crate::dx12::DynLib::new(lib_path).map(|lib| Self { lib }) }
|
||||
}
|
||||
|
||||
pub(crate) fn compile_dxc(
|
||||
device: &crate::dx12::Device,
|
||||
source: &str,
|
||||
source_name: Option<&CStr>,
|
||||
raw_ep: &str,
|
||||
stage_bit: wgt::ShaderStages,
|
||||
full_stage: String,
|
||||
dxc_container: &DxcContainer,
|
||||
) -> (
|
||||
Result<crate::dx12::CompiledShader, crate::PipelineError>,
|
||||
log::Level,
|
||||
) {
|
||||
profiling::scope!("compile_dxc");
|
||||
let mut compile_flags = arrayvec::ArrayVec::<&str, 6>::new_const();
|
||||
compile_flags.push("-Ges"); // Direct3D::Fxc::D3DCOMPILE_ENABLE_STRICTNESS
|
||||
compile_flags.push("-Vd"); // Disable implicit validation to work around bugs when dxil.dll isn't in the local directory.
|
||||
compile_flags.push("-HV"); // Use HLSL 2018, Naga doesn't supported 2021 yet.
|
||||
compile_flags.push("2018");
|
||||
pub fn create_instance<T: DxcObj>(&self) -> Result<T, crate::DeviceError> {
|
||||
type Fun = extern "system" fn(
|
||||
rclsid: *const windows_core::GUID,
|
||||
riid: *const windows_core::GUID,
|
||||
ppv: *mut *mut core::ffi::c_void,
|
||||
) -> windows_core::HRESULT;
|
||||
let func: libloading::Symbol<Fun> = unsafe { self.lib.get(b"DxcCreateInstance\0") }?;
|
||||
|
||||
if device
|
||||
.private_caps
|
||||
.instance_flags
|
||||
.contains(wgt::InstanceFlags::DEBUG)
|
||||
{
|
||||
compile_flags.push("-Zi"); // Direct3D::Fxc::D3DCOMPILE_SKIP_OPTIMIZATION
|
||||
compile_flags.push("-Od"); // Direct3D::Fxc::D3DCOMPILE_DEBUG
|
||||
}
|
||||
|
||||
let blob = match dxc_container
|
||||
.library
|
||||
.create_blob_with_encoding_from_str(source)
|
||||
.map_err(|e| crate::PipelineError::Linkage(stage_bit, format!("DXC blob error: {e}")))
|
||||
{
|
||||
Ok(blob) => blob,
|
||||
Err(e) => return (Err(e), log::Level::Error),
|
||||
};
|
||||
|
||||
let source_name = source_name
|
||||
.and_then(|cstr| cstr.to_str().ok())
|
||||
.unwrap_or("");
|
||||
|
||||
let compiled = dxc_container.compiler.compile(
|
||||
&blob,
|
||||
source_name,
|
||||
raw_ep,
|
||||
&full_stage,
|
||||
&compile_flags,
|
||||
None,
|
||||
&[],
|
||||
);
|
||||
|
||||
let (result, log_level) = match compiled {
|
||||
Ok(dxc_result) => match dxc_result.get_result() {
|
||||
Ok(dxc_blob) => {
|
||||
// Validate the shader.
|
||||
match dxc_container.validator.validate(dxc_blob) {
|
||||
Ok(validated_blob) => (
|
||||
Ok(crate::dx12::CompiledShader::Dxc(validated_blob.to_vec())),
|
||||
log::Level::Info,
|
||||
),
|
||||
Err(e) => (
|
||||
Err(crate::PipelineError::Linkage(
|
||||
stage_bit,
|
||||
format!(
|
||||
"DXC validation error: {:?}\n{:?}",
|
||||
get_error_string_from_dxc_result(&dxc_container.library, &e.0)
|
||||
.unwrap_or_default(),
|
||||
e.1
|
||||
),
|
||||
)),
|
||||
log::Level::Error,
|
||||
),
|
||||
}
|
||||
}
|
||||
Err(e) => (
|
||||
Err(crate::PipelineError::Linkage(
|
||||
stage_bit,
|
||||
format!("DXC compile error: {e}"),
|
||||
)),
|
||||
log::Level::Error,
|
||||
),
|
||||
},
|
||||
Err(e) => (
|
||||
Err(crate::PipelineError::Linkage(
|
||||
stage_bit,
|
||||
format!(
|
||||
"DXC compile error: {}",
|
||||
get_error_string_from_dxc_result(&dxc_container.library, &e.0)
|
||||
.unwrap_or_default()
|
||||
),
|
||||
)),
|
||||
log::Level::Error,
|
||||
),
|
||||
};
|
||||
|
||||
(result, log_level)
|
||||
}
|
||||
|
||||
impl From<hassle_rs::HassleError> for crate::DeviceError {
|
||||
fn from(value: hassle_rs::HassleError) -> Self {
|
||||
match value {
|
||||
hassle_rs::HassleError::Win32Error(e) => {
|
||||
// TODO: This returns an HRESULT, should we try and use the associated Windows error message?
|
||||
log::error!("Win32 error: {e:?}");
|
||||
crate::DeviceError::Lost
|
||||
}
|
||||
hassle_rs::HassleError::LoadLibraryError { filename, inner } => {
|
||||
log::error!("Failed to load dxc library {filename:?}. Inner error: {inner:?}");
|
||||
crate::DeviceError::Lost
|
||||
}
|
||||
hassle_rs::HassleError::LibLoadingError(e) => {
|
||||
log::error!("Failed to load dxc library. {e:?}");
|
||||
crate::DeviceError::Lost
|
||||
}
|
||||
hassle_rs::HassleError::WindowsOnly(e) => {
|
||||
log::error!("Signing with dxil.dll is only supported on Windows. {e:?}");
|
||||
crate::DeviceError::Lost
|
||||
}
|
||||
// `ValidationError` and `CompileError` should never happen in a context involving `DeviceError`
|
||||
hassle_rs::HassleError::ValidationError(_e) => unimplemented!(),
|
||||
hassle_rs::HassleError::CompileError(_e) => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_error_string_from_dxc_result(
|
||||
library: &hassle_rs::DxcLibrary,
|
||||
error: &hassle_rs::DxcOperationResult,
|
||||
) -> Result<String, hassle_rs::HassleError> {
|
||||
error
|
||||
.get_error_buffer()
|
||||
.and_then(|error| library.get_blob_as_string(&hassle_rs::DxcBlob::from(error)))
|
||||
let mut result__ = None;
|
||||
(func)(&T::CLSID, &T::IID, <*mut _>::cast(&mut result__))
|
||||
.ok()
|
||||
.into_device_result("DxcCreateInstance")?;
|
||||
result__.ok_or(crate::DeviceError::Unexpected)
|
||||
}
|
||||
}
|
||||
|
||||
// These are stubs for when the `dxc_shader_compiler` feature is disabled.
|
||||
#[cfg(not(feature = "dxc_shader_compiler"))]
|
||||
mod dxc {
|
||||
use std::ffi::CStr;
|
||||
use std::path::PathBuf;
|
||||
// Destructor order should be fine since _dxil and _dxc don't rely on each other.
|
||||
pub(super) struct DxcContainer {
|
||||
compiler: Dxc::IDxcCompiler3,
|
||||
utils: Dxc::IDxcUtils,
|
||||
validator: Dxc::IDxcValidator,
|
||||
// Has to be held onto for the lifetime of the device otherwise shaders will fail to compile.
|
||||
_dxc: DxcLib,
|
||||
// Also Has to be held onto for the lifetime of the device otherwise shaders will fail to validate.
|
||||
_dxil: DxcLib,
|
||||
}
|
||||
|
||||
pub(crate) struct DxcContainer {}
|
||||
pub(super) fn get_dxc_container(
|
||||
dxc_path: Option<PathBuf>,
|
||||
dxil_path: Option<PathBuf>,
|
||||
) -> Result<Option<DxcContainer>, crate::DeviceError> {
|
||||
let dxc = match DxcLib::new(dxc_path, "dxcompiler.dll") {
|
||||
Ok(dxc) => dxc,
|
||||
Err(e) => {
|
||||
log::warn!(
|
||||
"Failed to load dxcompiler.dll. Defaulting to FXC instead: {}",
|
||||
e
|
||||
);
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
|
||||
pub(crate) fn get_dxc_container(
|
||||
_dxc_path: Option<PathBuf>,
|
||||
_dxil_path: Option<PathBuf>,
|
||||
) -> Result<Option<DxcContainer>, crate::DeviceError> {
|
||||
// Falls back to Fxc and logs an error.
|
||||
log::error!("DXC shader compiler was requested on Instance creation, but the DXC feature is disabled. Enable the `dxc_shader_compiler` feature on wgpu_hal to use DXC.");
|
||||
Ok(None)
|
||||
let dxil = match DxcLib::new(dxil_path, "dxil.dll") {
|
||||
Ok(dxil) => dxil,
|
||||
Err(e) => {
|
||||
log::warn!("Failed to load dxil.dll. Defaulting to FXC instead: {}", e);
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
|
||||
let compiler = dxc.create_instance::<Dxc::IDxcCompiler3>()?;
|
||||
let utils = dxc.create_instance::<Dxc::IDxcUtils>()?;
|
||||
let validator = dxil.create_instance::<Dxc::IDxcValidator>()?;
|
||||
|
||||
Ok(Some(DxcContainer {
|
||||
compiler,
|
||||
utils,
|
||||
validator,
|
||||
_dxc: dxc,
|
||||
_dxil: dxil,
|
||||
}))
|
||||
}
|
||||
|
||||
/// Owned PCWSTR
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
struct OPCWSTR {
|
||||
inner: Vec<u16>,
|
||||
}
|
||||
|
||||
impl OPCWSTR {
|
||||
fn new(s: &str) -> Self {
|
||||
let mut inner: Vec<_> = s.encode_utf16().collect();
|
||||
inner.push(0);
|
||||
Self { inner }
|
||||
}
|
||||
|
||||
// It shouldn't be possible that this gets called with the `dxc_shader_compiler` feature disabled.
|
||||
pub(crate) fn compile_dxc(
|
||||
_device: &crate::dx12::Device,
|
||||
_source: &str,
|
||||
_source_name: Option<&CStr>,
|
||||
_raw_ep: &str,
|
||||
_stage_bit: wgt::ShaderStages,
|
||||
_full_stage: String,
|
||||
_dxc_container: &DxcContainer,
|
||||
) -> (
|
||||
Result<crate::dx12::CompiledShader, crate::PipelineError>,
|
||||
log::Level,
|
||||
) {
|
||||
unimplemented!("Something went really wrong, please report this. Attempted to compile shader with DXC, but the DXC feature is disabled. Enable the `dxc_shader_compiler` feature on wgpu_hal to use DXC.");
|
||||
fn ptr(&self) -> PCWSTR {
|
||||
PCWSTR(self.inner.as_ptr())
|
||||
}
|
||||
}
|
||||
|
||||
fn get_output<T: Interface>(
|
||||
res: &Dxc::IDxcResult,
|
||||
kind: Dxc::DXC_OUT_KIND,
|
||||
) -> Result<T, crate::DeviceError> {
|
||||
let mut result__: Option<T> = None;
|
||||
unsafe { res.GetOutput::<T>(kind, &mut None, <*mut _>::cast(&mut result__)) }
|
||||
.into_device_result("GetOutput")?;
|
||||
result__.ok_or(crate::DeviceError::Unexpected)
|
||||
}
|
||||
|
||||
fn as_err_str(blob: &Dxc::IDxcBlobUtf8) -> Result<&str, crate::DeviceError> {
|
||||
let ptr = unsafe { blob.GetStringPointer() };
|
||||
let len = unsafe { blob.GetStringLength() };
|
||||
core::str::from_utf8(unsafe { core::slice::from_raw_parts(ptr.0, len) })
|
||||
.map_err(|_| crate::DeviceError::Unexpected)
|
||||
}
|
||||
|
||||
pub(super) fn compile_dxc(
|
||||
device: &crate::dx12::Device,
|
||||
source: &str,
|
||||
source_name: Option<&CStr>,
|
||||
raw_ep: &str,
|
||||
stage_bit: wgt::ShaderStages,
|
||||
full_stage: &str,
|
||||
dxc_container: &DxcContainer,
|
||||
) -> Result<crate::dx12::CompiledShader, crate::PipelineError> {
|
||||
profiling::scope!("compile_dxc");
|
||||
|
||||
let source_name = source_name.and_then(|cstr| cstr.to_str().ok());
|
||||
|
||||
let source_name = source_name.map(OPCWSTR::new);
|
||||
let raw_ep = OPCWSTR::new(raw_ep);
|
||||
let full_stage = OPCWSTR::new(full_stage);
|
||||
|
||||
let mut compile_args = arrayvec::ArrayVec::<PCWSTR, 12>::new_const();
|
||||
|
||||
if let Some(source_name) = source_name.as_ref() {
|
||||
compile_args.push(source_name.ptr())
|
||||
}
|
||||
|
||||
compile_args.extend([
|
||||
windows::core::w!("-E"),
|
||||
raw_ep.ptr(),
|
||||
windows::core::w!("-T"),
|
||||
full_stage.ptr(),
|
||||
windows::core::w!("-HV"),
|
||||
windows::core::w!("2018"), // Use HLSL 2018, Naga doesn't supported 2021 yet.
|
||||
windows::core::w!("-no-warnings"),
|
||||
Dxc::DXC_ARG_ENABLE_STRICTNESS,
|
||||
Dxc::DXC_ARG_SKIP_VALIDATION, // Disable implicit validation to work around bugs when dxil.dll isn't in the local directory.
|
||||
]);
|
||||
|
||||
if device
|
||||
.private_caps
|
||||
.instance_flags
|
||||
.contains(wgt::InstanceFlags::DEBUG)
|
||||
{
|
||||
compile_args.push(Dxc::DXC_ARG_DEBUG);
|
||||
compile_args.push(Dxc::DXC_ARG_SKIP_OPTIMIZATIONS);
|
||||
}
|
||||
|
||||
let buffer = Dxc::DxcBuffer {
|
||||
Ptr: source.as_ptr().cast(),
|
||||
Size: source.len(),
|
||||
Encoding: Dxc::DXC_CP_UTF8.0,
|
||||
};
|
||||
|
||||
let compile_res: Dxc::IDxcResult = unsafe {
|
||||
dxc_container
|
||||
.compiler
|
||||
.Compile(&buffer, Some(&compile_args), None)
|
||||
}
|
||||
.into_device_result("Compile")?;
|
||||
|
||||
drop(compile_args);
|
||||
drop(source_name);
|
||||
drop(raw_ep);
|
||||
drop(full_stage);
|
||||
|
||||
let err_blob = get_output::<Dxc::IDxcBlobUtf8>(&compile_res, Dxc::DXC_OUT_ERRORS)?;
|
||||
|
||||
let len = unsafe { err_blob.GetStringLength() };
|
||||
if len != 0 {
|
||||
let err = as_err_str(&err_blob)?;
|
||||
return Err(crate::PipelineError::Linkage(
|
||||
stage_bit,
|
||||
format!("DXC compile error: {err}"),
|
||||
));
|
||||
}
|
||||
|
||||
let blob = get_output::<Dxc::IDxcBlob>(&compile_res, Dxc::DXC_OUT_OBJECT)?;
|
||||
|
||||
let err_blob = {
|
||||
let res = unsafe {
|
||||
dxc_container
|
||||
.validator
|
||||
.Validate(&blob, Dxc::DxcValidatorFlags_InPlaceEdit)
|
||||
}
|
||||
.into_device_result("Validate")?;
|
||||
|
||||
unsafe { res.GetErrorBuffer() }.into_device_result("GetErrorBuffer")?
|
||||
};
|
||||
|
||||
let size = unsafe { err_blob.GetBufferSize() };
|
||||
if size != 0 {
|
||||
let err_blob = unsafe { dxc_container.utils.GetBlobAsUtf8(&err_blob) }
|
||||
.into_device_result("GetBlobAsUtf8")?;
|
||||
let err = as_err_str(&err_blob)?;
|
||||
return Err(crate::PipelineError::Linkage(
|
||||
stage_bit,
|
||||
format!("DXC validation error: {err}"),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(crate::dx12::CompiledShader::Dxc(blob))
|
||||
}
|
||||
|
@ -52,14 +52,14 @@ pub(crate) fn create_buffer_resource(
|
||||
device: &crate::dx12::Device,
|
||||
desc: &crate::BufferDescriptor,
|
||||
raw_desc: Direct3D12::D3D12_RESOURCE_DESC,
|
||||
resource: &mut Option<Direct3D12::ID3D12Resource>,
|
||||
) -> Result<Option<AllocationWrapper>, crate::DeviceError> {
|
||||
) -> Result<(Direct3D12::ID3D12Resource, Option<AllocationWrapper>), crate::DeviceError> {
|
||||
let is_cpu_read = desc.usage.contains(crate::BufferUses::MAP_READ);
|
||||
let is_cpu_write = desc.usage.contains(crate::BufferUses::MAP_WRITE);
|
||||
|
||||
// Workaround for Intel Xe drivers
|
||||
if !device.private_caps.suballocation_supported {
|
||||
return create_committed_buffer_resource(device, desc, raw_desc, resource).map(|()| None);
|
||||
return create_committed_buffer_resource(device, desc, raw_desc)
|
||||
.map(|resource| (resource, None));
|
||||
}
|
||||
|
||||
let location = match (is_cpu_read, is_cpu_write) {
|
||||
@ -80,6 +80,7 @@ pub(crate) fn create_buffer_resource(
|
||||
location,
|
||||
);
|
||||
let allocation = allocator.allocator.allocate(&allocation_desc)?;
|
||||
let mut resource = None;
|
||||
|
||||
unsafe {
|
||||
device.raw.CreatePlacedResource(
|
||||
@ -88,32 +89,30 @@ pub(crate) fn create_buffer_resource(
|
||||
&raw_desc,
|
||||
Direct3D12::D3D12_RESOURCE_STATE_COMMON,
|
||||
None,
|
||||
resource,
|
||||
&mut resource,
|
||||
)
|
||||
}
|
||||
.into_device_result("Placed buffer creation")?;
|
||||
|
||||
if resource.is_none() {
|
||||
return Err(crate::DeviceError::ResourceCreationFailed);
|
||||
}
|
||||
let resource = resource.ok_or(crate::DeviceError::Unexpected)?;
|
||||
|
||||
device
|
||||
.counters
|
||||
.buffer_memory
|
||||
.add(allocation.size() as isize);
|
||||
|
||||
Ok(Some(AllocationWrapper { allocation }))
|
||||
Ok((resource, Some(AllocationWrapper { allocation })))
|
||||
}
|
||||
|
||||
pub(crate) fn create_texture_resource(
|
||||
device: &crate::dx12::Device,
|
||||
desc: &crate::TextureDescriptor,
|
||||
raw_desc: Direct3D12::D3D12_RESOURCE_DESC,
|
||||
resource: &mut Option<Direct3D12::ID3D12Resource>,
|
||||
) -> Result<Option<AllocationWrapper>, crate::DeviceError> {
|
||||
) -> Result<(Direct3D12::ID3D12Resource, Option<AllocationWrapper>), crate::DeviceError> {
|
||||
// Workaround for Intel Xe drivers
|
||||
if !device.private_caps.suballocation_supported {
|
||||
return create_committed_texture_resource(device, desc, raw_desc, resource).map(|()| None);
|
||||
return create_committed_texture_resource(device, desc, raw_desc)
|
||||
.map(|resource| (resource, None));
|
||||
}
|
||||
|
||||
let location = MemoryLocation::GpuOnly;
|
||||
@ -128,6 +127,7 @@ pub(crate) fn create_texture_resource(
|
||||
location,
|
||||
);
|
||||
let allocation = allocator.allocator.allocate(&allocation_desc)?;
|
||||
let mut resource = None;
|
||||
|
||||
unsafe {
|
||||
device.raw.CreatePlacedResource(
|
||||
@ -136,21 +136,19 @@ pub(crate) fn create_texture_resource(
|
||||
&raw_desc,
|
||||
Direct3D12::D3D12_RESOURCE_STATE_COMMON,
|
||||
None, // clear value
|
||||
resource,
|
||||
&mut resource,
|
||||
)
|
||||
}
|
||||
.into_device_result("Placed texture creation")?;
|
||||
|
||||
if resource.is_none() {
|
||||
return Err(crate::DeviceError::ResourceCreationFailed);
|
||||
}
|
||||
let resource = resource.ok_or(crate::DeviceError::Unexpected)?;
|
||||
|
||||
device
|
||||
.counters
|
||||
.texture_memory
|
||||
.add(allocation.size() as isize);
|
||||
|
||||
Ok(Some(AllocationWrapper { allocation }))
|
||||
Ok((resource, Some(AllocationWrapper { allocation })))
|
||||
}
|
||||
|
||||
pub(crate) fn free_buffer_allocation(
|
||||
@ -226,8 +224,7 @@ pub(crate) fn create_committed_buffer_resource(
|
||||
device: &crate::dx12::Device,
|
||||
desc: &crate::BufferDescriptor,
|
||||
raw_desc: Direct3D12::D3D12_RESOURCE_DESC,
|
||||
resource: &mut Option<Direct3D12::ID3D12Resource>,
|
||||
) -> Result<(), crate::DeviceError> {
|
||||
) -> Result<Direct3D12::ID3D12Resource, crate::DeviceError> {
|
||||
let is_cpu_read = desc.usage.contains(crate::BufferUses::MAP_READ);
|
||||
let is_cpu_write = desc.usage.contains(crate::BufferUses::MAP_WRITE);
|
||||
|
||||
@ -250,6 +247,8 @@ pub(crate) fn create_committed_buffer_resource(
|
||||
VisibleNodeMask: 0,
|
||||
};
|
||||
|
||||
let mut resource = None;
|
||||
|
||||
unsafe {
|
||||
device.raw.CreateCommittedResource(
|
||||
&heap_properties,
|
||||
@ -261,24 +260,19 @@ pub(crate) fn create_committed_buffer_resource(
|
||||
&raw_desc,
|
||||
Direct3D12::D3D12_RESOURCE_STATE_COMMON,
|
||||
None,
|
||||
resource,
|
||||
&mut resource,
|
||||
)
|
||||
}
|
||||
.into_device_result("Committed buffer creation")?;
|
||||
|
||||
if resource.is_none() {
|
||||
return Err(crate::DeviceError::ResourceCreationFailed);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
resource.ok_or(crate::DeviceError::Unexpected)
|
||||
}
|
||||
|
||||
pub(crate) fn create_committed_texture_resource(
|
||||
device: &crate::dx12::Device,
|
||||
_desc: &crate::TextureDescriptor,
|
||||
raw_desc: Direct3D12::D3D12_RESOURCE_DESC,
|
||||
resource: &mut Option<Direct3D12::ID3D12Resource>,
|
||||
) -> Result<(), crate::DeviceError> {
|
||||
) -> Result<Direct3D12::ID3D12Resource, crate::DeviceError> {
|
||||
let heap_properties = Direct3D12::D3D12_HEAP_PROPERTIES {
|
||||
Type: Direct3D12::D3D12_HEAP_TYPE_CUSTOM,
|
||||
CPUPageProperty: Direct3D12::D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE,
|
||||
@ -290,6 +284,8 @@ pub(crate) fn create_committed_texture_resource(
|
||||
VisibleNodeMask: 0,
|
||||
};
|
||||
|
||||
let mut resource = None;
|
||||
|
||||
unsafe {
|
||||
device.raw.CreateCommittedResource(
|
||||
&heap_properties,
|
||||
@ -301,14 +297,10 @@ pub(crate) fn create_committed_texture_resource(
|
||||
&raw_desc,
|
||||
Direct3D12::D3D12_RESOURCE_STATE_COMMON,
|
||||
None, // clear value
|
||||
resource,
|
||||
&mut resource,
|
||||
)
|
||||
}
|
||||
.into_device_result("Committed texture creation")?;
|
||||
|
||||
if resource.is_none() {
|
||||
return Err(crate::DeviceError::ResourceCreationFailed);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
resource.ok_or(crate::DeviceError::Unexpected)
|
||||
}
|
||||
|
10
third_party/rust/wgpu-hal/src/gles/adapter.rs
vendored
10
third_party/rust/wgpu-hal/src/gles/adapter.rs
vendored
@ -841,6 +841,16 @@ impl super::Adapter {
|
||||
alignments: crate::Alignments {
|
||||
buffer_copy_offset: wgt::BufferSize::new(4).unwrap(),
|
||||
buffer_copy_pitch: wgt::BufferSize::new(4).unwrap(),
|
||||
// #6151: `wgpu_hal::gles` doesn't ask Naga to inject bounds
|
||||
// checks in GLSL, and it doesn't request extensions like
|
||||
// `KHR_robust_buffer_access_behavior` that would provide
|
||||
// them, so we can't really implement the checks promised by
|
||||
// [`crate::BufferBinding`].
|
||||
//
|
||||
// Since this is a pre-existing condition, for the time
|
||||
// being, provide 1 as the value here, to cause as little
|
||||
// trouble as possible.
|
||||
uniform_bounds_check_alignment: wgt::BufferSize::new(1).unwrap(),
|
||||
},
|
||||
},
|
||||
})
|
||||
|
20
third_party/rust/wgpu-hal/src/gles/egl.rs
vendored
20
third_party/rust/wgpu-hal/src/gles/egl.rs
vendored
@ -143,7 +143,7 @@ impl Drop for DisplayOwner {
|
||||
match self.display {
|
||||
DisplayRef::X11(ptr) => unsafe {
|
||||
let func: libloading::Symbol<XCloseDisplayFun> =
|
||||
self.library.get(b"XCloseDisplay").unwrap();
|
||||
self.library.get(b"XCloseDisplay\0").unwrap();
|
||||
func(ptr.as_ptr());
|
||||
},
|
||||
DisplayRef::Wayland => {}
|
||||
@ -155,7 +155,7 @@ fn open_x_display() -> Option<DisplayOwner> {
|
||||
log::debug!("Loading X11 library to get the current display");
|
||||
unsafe {
|
||||
let library = find_library(&["libX11.so.6", "libX11.so"])?;
|
||||
let func: libloading::Symbol<XOpenDisplayFun> = library.get(b"XOpenDisplay").unwrap();
|
||||
let func: libloading::Symbol<XOpenDisplayFun> = library.get(b"XOpenDisplay\0").unwrap();
|
||||
let result = func(ptr::null());
|
||||
ptr::NonNull::new(result).map(|ptr| DisplayOwner {
|
||||
display: DisplayRef::X11(ptr),
|
||||
@ -182,9 +182,9 @@ fn test_wayland_display() -> Option<DisplayOwner> {
|
||||
let library = unsafe {
|
||||
let client_library = find_library(&["libwayland-client.so.0", "libwayland-client.so"])?;
|
||||
let wl_display_connect: libloading::Symbol<WlDisplayConnectFun> =
|
||||
client_library.get(b"wl_display_connect").unwrap();
|
||||
client_library.get(b"wl_display_connect\0").unwrap();
|
||||
let wl_display_disconnect: libloading::Symbol<WlDisplayDisconnectFun> =
|
||||
client_library.get(b"wl_display_disconnect").unwrap();
|
||||
client_library.get(b"wl_display_disconnect\0").unwrap();
|
||||
let display = ptr::NonNull::new(wl_display_connect(ptr::null()))?;
|
||||
wl_display_disconnect(display.as_ptr());
|
||||
find_library(&["libwayland-egl.so.1", "libwayland-egl.so"])?
|
||||
@ -379,7 +379,7 @@ struct EglContextLock<'a> {
|
||||
display: khronos_egl::Display,
|
||||
}
|
||||
|
||||
/// A guard containing a lock to an [`AdapterContext`]
|
||||
/// A guard containing a lock to an [`AdapterContext`], while the GL context is kept current.
|
||||
pub struct AdapterContextLock<'a> {
|
||||
glow: MutexGuard<'a, ManuallyDrop<glow::Context>>,
|
||||
egl: Option<EglContextLock<'a>>,
|
||||
@ -1082,7 +1082,9 @@ impl crate::Instance for Instance {
|
||||
unsafe { gl.debug_message_callback(super::gl_debug_message_callback) };
|
||||
}
|
||||
|
||||
// Avoid accidental drop when the context is not current.
|
||||
// Wrap in ManuallyDrop to make it easier to "current" the GL context before dropping this
|
||||
// GLOW context, which could also happen if a panic occurs after we uncurrent the context
|
||||
// below but before AdapterContext is constructed.
|
||||
let gl = ManuallyDrop::new(gl);
|
||||
inner.egl.unmake_current();
|
||||
|
||||
@ -1294,7 +1296,7 @@ impl crate::Surface for Surface {
|
||||
(WindowKind::Wayland, Rwh::Wayland(handle)) => {
|
||||
let library = &self.wsi.display_owner.as_ref().unwrap().library;
|
||||
let wl_egl_window_create: libloading::Symbol<WlEglWindowCreateFun> =
|
||||
unsafe { library.get(b"wl_egl_window_create") }.unwrap();
|
||||
unsafe { library.get(b"wl_egl_window_create\0") }.unwrap();
|
||||
let window =
|
||||
unsafe { wl_egl_window_create(handle.surface.as_ptr(), 640, 480) }
|
||||
.cast();
|
||||
@ -1403,7 +1405,7 @@ impl crate::Surface for Surface {
|
||||
if let Some(window) = wl_window {
|
||||
let library = &self.wsi.display_owner.as_ref().unwrap().library;
|
||||
let wl_egl_window_resize: libloading::Symbol<WlEglWindowResizeFun> =
|
||||
unsafe { library.get(b"wl_egl_window_resize") }.unwrap();
|
||||
unsafe { library.get(b"wl_egl_window_resize\0") }.unwrap();
|
||||
unsafe {
|
||||
wl_egl_window_resize(
|
||||
window,
|
||||
@ -1475,7 +1477,7 @@ impl crate::Surface for Surface {
|
||||
.expect("unsupported window")
|
||||
.library;
|
||||
let wl_egl_window_destroy: libloading::Symbol<WlEglWindowDestroyFun> =
|
||||
unsafe { library.get(b"wl_egl_window_destroy") }.unwrap();
|
||||
unsafe { library.get(b"wl_egl_window_destroy\0") }.unwrap();
|
||||
unsafe { wl_egl_window_destroy(window) };
|
||||
}
|
||||
}
|
||||
|
109
third_party/rust/wgpu-hal/src/gles/wgl.rs
vendored
109
third_party/rust/wgpu-hal/src/gles/wgl.rs
vendored
@ -1,15 +1,7 @@
|
||||
use glow::HasContext;
|
||||
use glutin_wgl_sys::wgl_extra::{
|
||||
Wgl, CONTEXT_CORE_PROFILE_BIT_ARB, CONTEXT_DEBUG_BIT_ARB, CONTEXT_FLAGS_ARB,
|
||||
CONTEXT_PROFILE_MASK_ARB,
|
||||
};
|
||||
use once_cell::sync::Lazy;
|
||||
use parking_lot::{Mutex, MutexGuard, RwLock};
|
||||
use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
ffi::{c_void, CStr, CString},
|
||||
mem::{self, ManuallyDrop},
|
||||
mem::{self, size_of, size_of_val, ManuallyDrop},
|
||||
os::raw::c_int,
|
||||
ptr,
|
||||
sync::{
|
||||
@ -19,6 +11,15 @@ use std::{
|
||||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use glow::HasContext;
|
||||
use glutin_wgl_sys::wgl_extra::{
|
||||
Wgl, CONTEXT_CORE_PROFILE_BIT_ARB, CONTEXT_DEBUG_BIT_ARB, CONTEXT_FLAGS_ARB,
|
||||
CONTEXT_PROFILE_MASK_ARB,
|
||||
};
|
||||
use once_cell::sync::Lazy;
|
||||
use parking_lot::{Mutex, MutexGuard, RwLock};
|
||||
use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
|
||||
use wgt::InstanceFlags;
|
||||
use windows::{
|
||||
core::{Error, PCSTR},
|
||||
@ -48,7 +49,10 @@ impl AdapterContext {
|
||||
}
|
||||
|
||||
pub fn raw_context(&self) -> *mut c_void {
|
||||
self.inner.lock().context.context.0
|
||||
match self.inner.lock().context {
|
||||
Some(ref wgl) => wgl.context.0,
|
||||
None => ptr::null_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Obtain a lock to the WGL context and get handle to the [`glow::Context`] that can be used to
|
||||
@ -62,7 +66,9 @@ impl AdapterContext {
|
||||
.try_lock_for(Duration::from_secs(CONTEXT_LOCK_TIMEOUT_SECS))
|
||||
.expect("Could not lock adapter context. This is most-likely a deadlock.");
|
||||
|
||||
inner.context.make_current(inner.device.dc).unwrap();
|
||||
if let Some(wgl) = &inner.context {
|
||||
wgl.make_current(inner.device.dc).unwrap()
|
||||
};
|
||||
|
||||
AdapterContextLock { inner }
|
||||
}
|
||||
@ -79,14 +85,15 @@ impl AdapterContext {
|
||||
.try_lock_for(Duration::from_secs(CONTEXT_LOCK_TIMEOUT_SECS))
|
||||
.expect("Could not lock adapter context. This is most-likely a deadlock.");
|
||||
|
||||
inner
|
||||
.context
|
||||
.make_current(device)
|
||||
.map(|()| AdapterContextLock { inner })
|
||||
if let Some(wgl) = &inner.context {
|
||||
wgl.make_current(device)?;
|
||||
}
|
||||
|
||||
Ok(AdapterContextLock { inner })
|
||||
}
|
||||
}
|
||||
|
||||
/// A guard containing a lock to an [`AdapterContext`]
|
||||
/// A guard containing a lock to an [`AdapterContext`], while the GL context is kept current.
|
||||
pub struct AdapterContextLock<'a> {
|
||||
inner: MutexGuard<'a, Inner>,
|
||||
}
|
||||
@ -101,7 +108,9 @@ impl<'a> std::ops::Deref for AdapterContextLock<'a> {
|
||||
|
||||
impl<'a> Drop for AdapterContextLock<'a> {
|
||||
fn drop(&mut self) {
|
||||
self.inner.context.unmake_current().unwrap();
|
||||
if let Some(wgl) = &self.inner.context {
|
||||
wgl.unmake_current().unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,7 +145,7 @@ unsafe impl Sync for WglContext {}
|
||||
struct Inner {
|
||||
gl: ManuallyDrop<glow::Context>,
|
||||
device: InstanceDevice,
|
||||
context: WglContext,
|
||||
context: Option<WglContext>,
|
||||
}
|
||||
|
||||
impl Drop for Inner {
|
||||
@ -150,8 +159,14 @@ impl Drop for Inner {
|
||||
|
||||
// Context must be current when dropped. See safety docs on
|
||||
// `glow::HasContext`.
|
||||
self.context.make_current(self.device.dc).unwrap();
|
||||
let _guard = CurrentGuard(&self.context);
|
||||
//
|
||||
// NOTE: This is only set to `None` by `Adapter::new_external` which
|
||||
// requires the context to be current when anything that may be holding
|
||||
// the `Arc<AdapterShared>` is dropped.
|
||||
let _guard = self.context.as_ref().map(|wgl| {
|
||||
wgl.make_current(self.device.dc).unwrap();
|
||||
CurrentGuard(wgl)
|
||||
});
|
||||
// SAFETY: Field not used after this.
|
||||
unsafe { ManuallyDrop::drop(&mut self.gl) };
|
||||
}
|
||||
@ -196,7 +211,7 @@ unsafe fn setup_pixel_format(dc: Gdi::HDC) -> Result<(), crate::InstanceError> {
|
||||
{
|
||||
let format = OpenGL::PIXELFORMATDESCRIPTOR {
|
||||
nVersion: 1,
|
||||
nSize: mem::size_of::<OpenGL::PIXELFORMATDESCRIPTOR>() as u16,
|
||||
nSize: size_of::<OpenGL::PIXELFORMATDESCRIPTOR>() as u16,
|
||||
dwFlags: OpenGL::PFD_DRAW_TO_WINDOW
|
||||
| OpenGL::PFD_SUPPORT_OPENGL
|
||||
| OpenGL::PFD_DOUBLEBUFFER,
|
||||
@ -232,12 +247,7 @@ unsafe fn setup_pixel_format(dc: Gdi::HDC) -> Result<(), crate::InstanceError> {
|
||||
}
|
||||
let mut format = Default::default();
|
||||
if unsafe {
|
||||
OpenGL::DescribePixelFormat(
|
||||
dc,
|
||||
index,
|
||||
mem::size_of_val(&format) as u32,
|
||||
Some(&mut format),
|
||||
)
|
||||
OpenGL::DescribePixelFormat(dc, index, size_of_val(&format) as u32, Some(&mut format))
|
||||
} == 0
|
||||
{
|
||||
return Err(crate::InstanceError::with_source(
|
||||
@ -280,7 +290,7 @@ fn create_global_window_class() -> Result<CString, crate::InstanceError> {
|
||||
}
|
||||
|
||||
let window_class = WindowsAndMessaging::WNDCLASSEXA {
|
||||
cbSize: mem::size_of::<WindowsAndMessaging::WNDCLASSEXA>() as u32,
|
||||
cbSize: size_of::<WindowsAndMessaging::WNDCLASSEXA>() as u32,
|
||||
style: WindowsAndMessaging::CS_OWNDC,
|
||||
lpfnWndProc: Some(wnd_proc),
|
||||
cbClsExtra: 0,
|
||||
@ -515,7 +525,9 @@ impl crate::Instance for Instance {
|
||||
unsafe { gl.debug_message_callback(super::gl_debug_message_callback) };
|
||||
}
|
||||
|
||||
// Avoid accidental drop when the context is not current.
|
||||
// Wrap in ManuallyDrop to make it easier to "current" the GL context before dropping this
|
||||
// GLOW context, which could also happen if a panic occurs after we uncurrent the context
|
||||
// below but before Inner is constructed.
|
||||
let gl = ManuallyDrop::new(gl);
|
||||
context.unmake_current().map_err(|e| {
|
||||
crate::InstanceError::with_source(
|
||||
@ -528,7 +540,7 @@ impl crate::Instance for Instance {
|
||||
inner: Arc::new(Mutex::new(Inner {
|
||||
device,
|
||||
gl,
|
||||
context,
|
||||
context: Some(context),
|
||||
})),
|
||||
srgb_capable,
|
||||
})
|
||||
@ -570,6 +582,43 @@ impl crate::Instance for Instance {
|
||||
}
|
||||
}
|
||||
|
||||
impl super::Adapter {
|
||||
/// Creates a new external adapter using the specified loader function.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// - The underlying OpenGL ES context must be current.
|
||||
/// - The underlying OpenGL ES context must be current when interfacing with any objects returned by
|
||||
/// wgpu-hal from this adapter.
|
||||
/// - The underlying OpenGL ES context must be current when dropping this adapter and when
|
||||
/// dropping any objects returned from this adapter.
|
||||
pub unsafe fn new_external(
|
||||
fun: impl FnMut(&str) -> *const c_void,
|
||||
) -> Option<crate::ExposedAdapter<super::Api>> {
|
||||
let context = unsafe { glow::Context::from_loader_function(fun) };
|
||||
unsafe {
|
||||
Self::expose(AdapterContext {
|
||||
inner: Arc::new(Mutex::new(Inner {
|
||||
gl: ManuallyDrop::new(context),
|
||||
device: create_instance_device().ok()?,
|
||||
context: None,
|
||||
})),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn adapter_context(&self) -> &AdapterContext {
|
||||
&self.shared.context
|
||||
}
|
||||
}
|
||||
|
||||
impl super::Device {
|
||||
/// Returns the underlying WGL context.
|
||||
pub fn context(&self) -> &AdapterContext {
|
||||
&self.shared.context
|
||||
}
|
||||
}
|
||||
|
||||
struct DeviceContextHandle {
|
||||
device: Gdi::HDC,
|
||||
window: Foundation::HWND,
|
||||
|
192
third_party/rust/wgpu-hal/src/lib.rs
vendored
192
third_party/rust/wgpu-hal/src/lib.rs
vendored
@ -51,8 +51,8 @@
|
||||
//! must use [`CommandEncoder::transition_buffers`] between those two
|
||||
//! operations.
|
||||
//!
|
||||
//! - Pipeline layouts are *explicitly specified* when setting bind
|
||||
//! group. Incompatible layouts disturb groups bound at higher indices.
|
||||
//! - Pipeline layouts are *explicitly specified* when setting bind groups.
|
||||
//! Incompatible layouts disturb groups bound at higher indices.
|
||||
//!
|
||||
//! - The API *accepts collections as iterators*, to avoid forcing the user to
|
||||
//! store data in particular containers. The implementation doesn't guarantee
|
||||
@ -327,7 +327,7 @@ impl Drop for DropGuard {
|
||||
}
|
||||
|
||||
#[cfg(any(gles, vulkan))]
|
||||
impl std::fmt::Debug for DropGuard {
|
||||
impl fmt::Debug for DropGuard {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("DropGuard").finish()
|
||||
}
|
||||
@ -345,6 +345,18 @@ pub enum DeviceError {
|
||||
Unexpected,
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // may be unused on some platforms
|
||||
#[cold]
|
||||
fn hal_usage_error<T: fmt::Display>(txt: T) -> ! {
|
||||
panic!("wgpu-hal invariant was violated (usage error): {txt}")
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // may be unused on some platforms
|
||||
#[cold]
|
||||
fn hal_internal_error<T: fmt::Display>(txt: T) -> ! {
|
||||
panic!("wgpu-hal ran into a preventable internal error: {txt}")
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Error)]
|
||||
pub enum ShaderError {
|
||||
#[error("Compilation failed: {0:?}")]
|
||||
@ -1230,8 +1242,40 @@ pub trait CommandEncoder: WasmNotSendSync + fmt::Debug {
|
||||
|
||||
// pass common
|
||||
|
||||
/// Sets the bind group at `index` to `group`, assuming the layout
|
||||
/// of all the preceding groups to be taken from `layout`.
|
||||
/// Sets the bind group at `index` to `group`.
|
||||
///
|
||||
/// If this is not the first call to `set_bind_group` within the current
|
||||
/// render or compute pass:
|
||||
///
|
||||
/// - If `layout` contains `n` bind group layouts, then any previously set
|
||||
/// bind groups at indices `n` or higher are cleared.
|
||||
///
|
||||
/// - If the first `m` bind group layouts of `layout` are equal to those of
|
||||
/// the previously passed layout, but no more, then any previously set
|
||||
/// bind groups at indices `m` or higher are cleared.
|
||||
///
|
||||
/// It follows from the above that passing the same layout as before doesn't
|
||||
/// clear any bind groups.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// - This [`CommandEncoder`] must be within a render or compute pass.
|
||||
///
|
||||
/// - `index` must be the valid index of some bind group layout in `layout`.
|
||||
/// Call this the "relevant bind group layout".
|
||||
///
|
||||
/// - The layout of `group` must be equal to the relevant bind group layout.
|
||||
///
|
||||
/// - The length of `dynamic_offsets` must match the number of buffer
|
||||
/// bindings [with dynamic offsets][hdo] in the relevant bind group
|
||||
/// layout.
|
||||
///
|
||||
/// - If those buffer bindings are ordered by increasing [`binding` number]
|
||||
/// and paired with elements from `dynamic_offsets`, then each offset must
|
||||
/// be a valid offset for the binding's corresponding buffer in `group`.
|
||||
///
|
||||
/// [hdo]: wgt::BindingType::Buffer::has_dynamic_offset
|
||||
/// [`binding` number]: wgt::BindGroupLayoutEntry::binding
|
||||
unsafe fn set_bind_group(
|
||||
&mut self,
|
||||
layout: &<Self::A as Api>::PipelineLayout,
|
||||
@ -1283,11 +1327,43 @@ pub trait CommandEncoder: WasmNotSendSync + fmt::Debug {
|
||||
|
||||
// render passes
|
||||
|
||||
// Begins a render pass, clears all active bindings.
|
||||
/// Begin a new render pass, clearing all active bindings.
|
||||
///
|
||||
/// This clears any bindings established by the following calls:
|
||||
///
|
||||
/// - [`set_bind_group`](CommandEncoder::set_bind_group)
|
||||
/// - [`set_push_constants`](CommandEncoder::set_push_constants)
|
||||
/// - [`begin_query`](CommandEncoder::begin_query)
|
||||
/// - [`set_render_pipeline`](CommandEncoder::set_render_pipeline)
|
||||
/// - [`set_index_buffer`](CommandEncoder::set_index_buffer)
|
||||
/// - [`set_vertex_buffer`](CommandEncoder::set_vertex_buffer)
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// - All prior calls to [`begin_render_pass`] on this [`CommandEncoder`] must have been followed
|
||||
/// by a call to [`end_render_pass`].
|
||||
///
|
||||
/// - All prior calls to [`begin_compute_pass`] on this [`CommandEncoder`] must have been followed
|
||||
/// by a call to [`end_compute_pass`].
|
||||
///
|
||||
/// [`begin_render_pass`]: CommandEncoder::begin_render_pass
|
||||
/// [`begin_compute_pass`]: CommandEncoder::begin_compute_pass
|
||||
/// [`end_render_pass`]: CommandEncoder::end_render_pass
|
||||
/// [`end_compute_pass`]: CommandEncoder::end_compute_pass
|
||||
unsafe fn begin_render_pass(
|
||||
&mut self,
|
||||
desc: &RenderPassDescriptor<<Self::A as Api>::QuerySet, <Self::A as Api>::TextureView>,
|
||||
);
|
||||
|
||||
/// End the current render pass.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// - There must have been a prior call to [`begin_render_pass`] on this [`CommandEncoder`]
|
||||
/// that has not been followed by a call to [`end_render_pass`].
|
||||
///
|
||||
/// [`begin_render_pass`]: CommandEncoder::begin_render_pass
|
||||
/// [`end_render_pass`]: CommandEncoder::end_render_pass
|
||||
unsafe fn end_render_pass(&mut self);
|
||||
|
||||
unsafe fn set_render_pipeline(&mut self, pipeline: &<Self::A as Api>::RenderPipeline);
|
||||
@ -1353,11 +1429,41 @@ pub trait CommandEncoder: WasmNotSendSync + fmt::Debug {
|
||||
|
||||
// compute passes
|
||||
|
||||
// Begins a compute pass, clears all active bindings.
|
||||
/// Begin a new compute pass, clearing all active bindings.
|
||||
///
|
||||
/// This clears any bindings established by the following calls:
|
||||
///
|
||||
/// - [`set_bind_group`](CommandEncoder::set_bind_group)
|
||||
/// - [`set_push_constants`](CommandEncoder::set_push_constants)
|
||||
/// - [`begin_query`](CommandEncoder::begin_query)
|
||||
/// - [`set_compute_pipeline`](CommandEncoder::set_compute_pipeline)
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// - All prior calls to [`begin_render_pass`] on this [`CommandEncoder`] must have been followed
|
||||
/// by a call to [`end_render_pass`].
|
||||
///
|
||||
/// - All prior calls to [`begin_compute_pass`] on this [`CommandEncoder`] must have been followed
|
||||
/// by a call to [`end_compute_pass`].
|
||||
///
|
||||
/// [`begin_render_pass`]: CommandEncoder::begin_render_pass
|
||||
/// [`begin_compute_pass`]: CommandEncoder::begin_compute_pass
|
||||
/// [`end_render_pass`]: CommandEncoder::end_render_pass
|
||||
/// [`end_compute_pass`]: CommandEncoder::end_compute_pass
|
||||
unsafe fn begin_compute_pass(
|
||||
&mut self,
|
||||
desc: &ComputePassDescriptor<<Self::A as Api>::QuerySet>,
|
||||
);
|
||||
|
||||
/// End the current compute pass.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// - There must have been a prior call to [`begin_compute_pass`] on this [`CommandEncoder`]
|
||||
/// that has not been followed by a call to [`end_compute_pass`].
|
||||
///
|
||||
/// [`begin_compute_pass`]: CommandEncoder::begin_compute_pass
|
||||
/// [`end_compute_pass`]: CommandEncoder::end_compute_pass
|
||||
unsafe fn end_compute_pass(&mut self);
|
||||
|
||||
unsafe fn set_compute_pipeline(&mut self, pipeline: &<Self::A as Api>::ComputePipeline);
|
||||
@ -1635,9 +1741,27 @@ pub struct InstanceDescriptor<'a> {
|
||||
pub struct Alignments {
|
||||
/// The alignment of the start of the buffer used as a GPU copy source.
|
||||
pub buffer_copy_offset: wgt::BufferSize,
|
||||
|
||||
/// The alignment of the row pitch of the texture data stored in a buffer that is
|
||||
/// used in a GPU copy operation.
|
||||
pub buffer_copy_pitch: wgt::BufferSize,
|
||||
|
||||
/// The finest alignment of bound range checking for uniform buffers.
|
||||
///
|
||||
/// When `wgpu_hal` restricts shader references to the [accessible
|
||||
/// region][ar] of a [`Uniform`] buffer, the size of the accessible region
|
||||
/// is the bind group binding's stated [size], rounded up to the next
|
||||
/// multiple of this value.
|
||||
///
|
||||
/// We don't need an analogous field for storage buffer bindings, because
|
||||
/// all our backends promise to enforce the size at least to a four-byte
|
||||
/// alignment, and `wgpu_hal` requires bound range lengths to be a multiple
|
||||
/// of four anyway.
|
||||
///
|
||||
/// [ar]: struct.BufferBinding.html#accessible-region
|
||||
/// [`Uniform`]: wgt::BufferBindingType::Uniform
|
||||
/// [size]: BufferBinding::size
|
||||
pub uniform_bounds_check_alignment: wgt::BufferSize,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@ -1807,6 +1931,40 @@ pub struct PipelineLayoutDescriptor<'a, B: DynBindGroupLayout + ?Sized> {
|
||||
pub push_constant_ranges: &'a [wgt::PushConstantRange],
|
||||
}
|
||||
|
||||
/// A region of a buffer made visible to shaders via a [`BindGroup`].
|
||||
///
|
||||
/// [`BindGroup`]: Api::BindGroup
|
||||
///
|
||||
/// ## Accessible region
|
||||
///
|
||||
/// `wgpu_hal` guarantees that shaders compiled with
|
||||
/// [`ShaderModuleDescriptor::runtime_checks`] set to `true` cannot read or
|
||||
/// write data via this binding outside the *accessible region* of [`buffer`]:
|
||||
///
|
||||
/// - The accessible region starts at [`offset`].
|
||||
///
|
||||
/// - For [`Storage`] bindings, the size of the accessible region is [`size`],
|
||||
/// which must be a multiple of 4.
|
||||
///
|
||||
/// - For [`Uniform`] bindings, the size of the accessible region is [`size`]
|
||||
/// rounded up to the next multiple of
|
||||
/// [`Alignments::uniform_bounds_check_alignment`].
|
||||
///
|
||||
/// Note that this guarantee is stricter than WGSL's requirements for
|
||||
/// [out-of-bounds accesses][woob], as WGSL allows them to return values from
|
||||
/// elsewhere in the buffer. But this guarantee is necessary anyway, to permit
|
||||
/// `wgpu-core` to avoid clearing uninitialized regions of buffers that will
|
||||
/// never be read by the application before they are overwritten. This
|
||||
/// optimization consults bind group buffer binding regions to determine which
|
||||
/// parts of which buffers shaders might observe. This optimization is only
|
||||
/// sound if shader access is bounds-checked.
|
||||
///
|
||||
/// [`buffer`]: BufferBinding::buffer
|
||||
/// [`offset`]: BufferBinding::offset
|
||||
/// [`size`]: BufferBinding::size
|
||||
/// [`Storage`]: wgt::BufferBindingType::Storage
|
||||
/// [`Uniform`]: wgt::BufferBindingType::Uniform
|
||||
/// [woob]: https://gpuweb.github.io/gpuweb/wgsl/#out-of-bounds-access-sec
|
||||
#[derive(Debug)]
|
||||
pub struct BufferBinding<'a, B: DynBuffer + ?Sized> {
|
||||
/// The buffer being bound.
|
||||
@ -1925,6 +2083,26 @@ pub enum ShaderInput<'a> {
|
||||
|
||||
pub struct ShaderModuleDescriptor<'a> {
|
||||
pub label: Label<'a>,
|
||||
|
||||
/// Enforce bounds checks in shaders, even if the underlying driver doesn't
|
||||
/// support doing so natively.
|
||||
///
|
||||
/// When this is `true`, `wgpu_hal` promises that shaders can only read or
|
||||
/// write the [accessible region][ar] of a bindgroup's buffer bindings. If
|
||||
/// the underlying graphics platform cannot implement these bounds checks
|
||||
/// itself, `wgpu_hal` will inject bounds checks before presenting the
|
||||
/// shader to the platform.
|
||||
///
|
||||
/// When this is `false`, `wgpu_hal` only enforces such bounds checks if the
|
||||
/// underlying platform provides a way to do so itself. `wgpu_hal` does not
|
||||
/// itself add any bounds checks to generated shader code.
|
||||
///
|
||||
/// Note that `wgpu_hal` users may try to initialize only those portions of
|
||||
/// buffers that they anticipate might be read from. Passing `false` here
|
||||
/// may allow shaders to see wider regions of the buffers than expected,
|
||||
/// making such deferred initialization visible to the application.
|
||||
///
|
||||
/// [ar]: struct.BufferBinding.html#accessible-region
|
||||
pub runtime_checks: bool,
|
||||
}
|
||||
|
||||
|
@ -997,6 +997,10 @@ impl super::PrivateCapabilities {
|
||||
alignments: crate::Alignments {
|
||||
buffer_copy_offset: wgt::BufferSize::new(self.buffer_alignment).unwrap(),
|
||||
buffer_copy_pitch: wgt::BufferSize::new(4).unwrap(),
|
||||
// This backend has Naga incorporate bounds checks into the
|
||||
// Metal Shading Language it generates, so from `wgpu_hal`'s
|
||||
// users' point of view, references are tightly checked.
|
||||
uniform_bounds_check_alignment: wgt::BufferSize::new(1).unwrap(),
|
||||
},
|
||||
downlevel,
|
||||
}
|
||||
|
49
third_party/rust/wgpu-hal/src/vulkan/adapter.rs
vendored
49
third_party/rust/wgpu-hal/src/vulkan/adapter.rs
vendored
@ -342,9 +342,6 @@ impl PhysicalDeviceFeatures {
|
||||
None
|
||||
},
|
||||
robustness2: if enabled_extensions.contains(&ext::robustness2::NAME) {
|
||||
// Note: enabling `robust_buffer_access2` isn't requires, strictly speaking
|
||||
// since we can enable `robust_buffer_access` all the time. But it improves
|
||||
// program portability, so we opt into it if they are supported.
|
||||
Some(
|
||||
vk::PhysicalDeviceRobustness2FeaturesEXT::default()
|
||||
.robust_buffer_access2(private_caps.robust_buffer_access2)
|
||||
@ -842,6 +839,10 @@ pub struct PhysicalDeviceProperties {
|
||||
/// `VK_EXT_subgroup_size_control` extension, promoted to Vulkan 1.3.
|
||||
subgroup_size_control: Option<vk::PhysicalDeviceSubgroupSizeControlProperties<'static>>,
|
||||
|
||||
/// Additional `vk::PhysicalDevice` properties from the
|
||||
/// `VK_EXT_robustness2` extension.
|
||||
robustness2: Option<vk::PhysicalDeviceRobustness2PropertiesEXT<'static>>,
|
||||
|
||||
/// The device API version.
|
||||
///
|
||||
/// Which is the version of Vulkan supported for device-level functionality.
|
||||
@ -1097,13 +1098,38 @@ impl PhysicalDeviceProperties {
|
||||
}
|
||||
}
|
||||
|
||||
fn to_hal_alignments(&self) -> crate::Alignments {
|
||||
/// Return a `wgpu_hal::Alignments` structure describing this adapter.
|
||||
///
|
||||
/// The `using_robustness2` argument says how this adapter will implement
|
||||
/// `wgpu_hal`'s guarantee that shaders can only read the [accessible
|
||||
/// region][ar] of bindgroup's buffer bindings:
|
||||
///
|
||||
/// - If this adapter will depend on `VK_EXT_robustness2`'s
|
||||
/// `robustBufferAccess2` feature to apply bounds checks to shader buffer
|
||||
/// access, `using_robustness2` must be `true`.
|
||||
///
|
||||
/// - Otherwise, this adapter must use Naga to inject bounds checks on
|
||||
/// buffer accesses, and `using_robustness2` must be `false`.
|
||||
///
|
||||
/// [ar]: ../../struct.BufferBinding.html#accessible-region
|
||||
fn to_hal_alignments(&self, using_robustness2: bool) -> crate::Alignments {
|
||||
let limits = &self.properties.limits;
|
||||
crate::Alignments {
|
||||
buffer_copy_offset: wgt::BufferSize::new(limits.optimal_buffer_copy_offset_alignment)
|
||||
.unwrap(),
|
||||
buffer_copy_pitch: wgt::BufferSize::new(limits.optimal_buffer_copy_row_pitch_alignment)
|
||||
.unwrap(),
|
||||
uniform_bounds_check_alignment: {
|
||||
let alignment = if using_robustness2 {
|
||||
self.robustness2
|
||||
.unwrap() // if we're using it, we should have its properties
|
||||
.robust_uniform_buffer_access_size_alignment
|
||||
} else {
|
||||
// If the `robustness2` properties are unavailable, then `robustness2` is not available either Naga-injected bounds checks are precise.
|
||||
1
|
||||
};
|
||||
wgt::BufferSize::new(alignment).unwrap()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1133,6 +1159,7 @@ impl super::InstanceShared {
|
||||
let supports_subgroup_size_control = capabilities.device_api_version
|
||||
>= vk::API_VERSION_1_3
|
||||
|| capabilities.supports_extension(ext::subgroup_size_control::NAME);
|
||||
let supports_robustness2 = capabilities.supports_extension(ext::robustness2::NAME);
|
||||
|
||||
let supports_acceleration_structure =
|
||||
capabilities.supports_extension(khr::acceleration_structure::NAME);
|
||||
@ -1180,6 +1207,13 @@ impl super::InstanceShared {
|
||||
properties2 = properties2.push_next(next);
|
||||
}
|
||||
|
||||
if supports_robustness2 {
|
||||
let next = capabilities
|
||||
.robustness2
|
||||
.insert(vk::PhysicalDeviceRobustness2PropertiesEXT::default());
|
||||
properties2 = properties2.push_next(next);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
get_device_properties.get_physical_device_properties2(phd, &mut properties2)
|
||||
};
|
||||
@ -1191,6 +1225,7 @@ impl super::InstanceShared {
|
||||
capabilities
|
||||
.supported_extensions
|
||||
.retain(|&x| x.extension_name_as_c_str() != Ok(ext::robustness2::NAME));
|
||||
capabilities.robustness2 = None;
|
||||
}
|
||||
};
|
||||
capabilities
|
||||
@ -1507,7 +1542,7 @@ impl super::Instance {
|
||||
};
|
||||
let capabilities = crate::Capabilities {
|
||||
limits: phd_capabilities.to_wgpu_limits(),
|
||||
alignments: phd_capabilities.to_hal_alignments(),
|
||||
alignments: phd_capabilities.to_hal_alignments(private_caps.robust_buffer_access2),
|
||||
downlevel: wgt::DownlevelCapabilities {
|
||||
flags: downlevel_flags,
|
||||
limits: wgt::DownlevelLimits {},
|
||||
@ -1779,7 +1814,7 @@ impl super::Adapter {
|
||||
capabilities: Some(capabilities.iter().cloned().collect()),
|
||||
bounds_check_policies: naga::proc::BoundsCheckPolicies {
|
||||
index: naga::proc::BoundsCheckPolicy::Restrict,
|
||||
buffer: if self.private_caps.robust_buffer_access {
|
||||
buffer: if self.private_caps.robust_buffer_access2 {
|
||||
naga::proc::BoundsCheckPolicy::Unchecked
|
||||
} else {
|
||||
naga::proc::BoundsCheckPolicy::Restrict
|
||||
@ -2010,7 +2045,7 @@ impl crate::Adapter for super::Adapter {
|
||||
vk::Result::ERROR_TOO_MANY_OBJECTS => crate::DeviceError::OutOfMemory,
|
||||
vk::Result::ERROR_INITIALIZATION_FAILED => crate::DeviceError::Lost,
|
||||
vk::Result::ERROR_EXTENSION_NOT_PRESENT | vk::Result::ERROR_FEATURE_NOT_PRESENT => {
|
||||
super::hal_usage_error(err)
|
||||
crate::hal_usage_error(err)
|
||||
}
|
||||
other => super::map_host_device_oom_and_lost_err(other),
|
||||
}
|
||||
|
10
third_party/rust/wgpu-hal/src/vulkan/device.rs
vendored
10
third_party/rust/wgpu-hal/src/vulkan/device.rs
vendored
@ -970,14 +970,14 @@ impl crate::Device for super::Device {
|
||||
.contains(gpu_alloc::MemoryPropertyFlags::HOST_COHERENT);
|
||||
Ok(crate::BufferMapping { ptr, is_coherent })
|
||||
} else {
|
||||
super::hal_usage_error("tried to map external buffer")
|
||||
crate::hal_usage_error("tried to map external buffer")
|
||||
}
|
||||
}
|
||||
unsafe fn unmap_buffer(&self, buffer: &super::Buffer) {
|
||||
if let Some(ref block) = buffer.block {
|
||||
unsafe { block.lock().unmap(&*self.shared) };
|
||||
} else {
|
||||
super::hal_usage_error("tried to unmap external buffer")
|
||||
crate::hal_usage_error("tried to unmap external buffer")
|
||||
}
|
||||
}
|
||||
|
||||
@ -2520,7 +2520,7 @@ impl super::DeviceShared {
|
||||
}
|
||||
}
|
||||
None => {
|
||||
super::hal_usage_error(format!(
|
||||
crate::hal_usage_error(format!(
|
||||
"no signals reached value {}",
|
||||
wait_value
|
||||
));
|
||||
@ -2537,7 +2537,7 @@ impl From<gpu_alloc::AllocationError> for crate::DeviceError {
|
||||
use gpu_alloc::AllocationError as Ae;
|
||||
match error {
|
||||
Ae::OutOfDeviceMemory | Ae::OutOfHostMemory | Ae::TooManyObjects => Self::OutOfMemory,
|
||||
Ae::NoCompatibleMemoryTypes => super::hal_usage_error(error),
|
||||
Ae::NoCompatibleMemoryTypes => crate::hal_usage_error(error),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2546,7 +2546,7 @@ impl From<gpu_alloc::MapError> for crate::DeviceError {
|
||||
use gpu_alloc::MapError as Me;
|
||||
match error {
|
||||
Me::OutOfDeviceMemory | Me::OutOfHostMemory | Me::MapFailed => Self::OutOfMemory,
|
||||
Me::NonHostVisible | Me::AlreadyMapped => super::hal_usage_error(error),
|
||||
Me::NonHostVisible | Me::AlreadyMapped => crate::hal_usage_error(error),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
32
third_party/rust/wgpu-hal/src/vulkan/mod.rs
vendored
32
third_party/rust/wgpu-hal/src/vulkan/mod.rs
vendored
@ -493,9 +493,36 @@ struct PrivateCapabilities {
|
||||
/// Ability to present contents to any screen. Only needed to work around broken platform configurations.
|
||||
can_present: bool,
|
||||
non_coherent_map_mask: wgt::BufferAddress,
|
||||
|
||||
/// True if this adapter advertises the [`robustBufferAccess`][vrba] feature.
|
||||
///
|
||||
/// Note that Vulkan's `robustBufferAccess` is not sufficient to implement
|
||||
/// `wgpu_hal`'s guarantee that shaders will not access buffer contents via
|
||||
/// a given bindgroup binding outside that binding's [accessible
|
||||
/// region][ar]. Enabling `robustBufferAccess` does ensure that
|
||||
/// out-of-bounds reads and writes are not undefined behavior (that's good),
|
||||
/// but still permits out-of-bounds reads to return data from anywhere
|
||||
/// within the buffer, not just the accessible region.
|
||||
///
|
||||
/// [ar]: ../struct.BufferBinding.html#accessible-region
|
||||
/// [vrba]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#features-robustBufferAccess
|
||||
robust_buffer_access: bool,
|
||||
|
||||
robust_image_access: bool,
|
||||
|
||||
/// True if this adapter supports the [`VK_EXT_robustness2`] extension's
|
||||
/// [`robustBufferAccess2`] feature.
|
||||
///
|
||||
/// This is sufficient to implement `wgpu_hal`'s [required bounds-checking][ar] of
|
||||
/// shader accesses to buffer contents. If this feature is not available,
|
||||
/// this backend must have Naga inject bounds checks in the generated
|
||||
/// SPIR-V.
|
||||
///
|
||||
/// [`VK_EXT_robustness2`]: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_robustness2.html
|
||||
/// [`robustBufferAccess2`]: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRobustness2FeaturesEXT.html#features-robustBufferAccess2
|
||||
/// [ar]: ../struct.BufferBinding.html#accessible-region
|
||||
robust_buffer_access2: bool,
|
||||
|
||||
robust_image_access2: bool,
|
||||
zero_initialize_workgroup_memory: bool,
|
||||
image_format_list: bool,
|
||||
@ -1360,8 +1387,3 @@ fn get_lost_err() -> crate::DeviceError {
|
||||
#[allow(unreachable_code)]
|
||||
crate::DeviceError::Lost
|
||||
}
|
||||
|
||||
#[cold]
|
||||
fn hal_usage_error<T: fmt::Display>(txt: T) -> ! {
|
||||
panic!("wgpu-hal invariant was violated (usage error): {txt}")
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
{"files":{"Cargo.toml":"e23d8d5f33e2bc96270c9c839e3e8038095ce1ffd5cca66129766c2879a7e350","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","src/assertions.rs":"d22aa7ddb95d3ae129ff9848fd45913bab41bd354b6f1c1f6c38a86f9d1abbc6","src/counters.rs":"599e9c033c4f8fcc95113bf730191d80f51b3276b3ee8fd03bbc1c27d24bf76d","src/lib.rs":"f3434598049500d0bc2c1d1e047de091c6d8728d5d0ecae22651f97889f5cce0","src/math.rs":"4d03039736dd6926feb139bc68734cb59df34ede310427bbf059e5c925e0af3b"},"package":null}
|
||||
{"files":{"Cargo.toml":"388f76262a9fe7ce13791695fc1cea6352ca8b1d367bdf1810c2a1eb80180d13","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","src/assertions.rs":"d22aa7ddb95d3ae129ff9848fd45913bab41bd354b6f1c1f6c38a86f9d1abbc6","src/counters.rs":"599e9c033c4f8fcc95113bf730191d80f51b3276b3ee8fd03bbc1c27d24bf76d","src/lib.rs":"aaaa6cc499533277abdb8c9b1fc45c333f5db2cbe012a9fcbabbe43a4936af34","src/math.rs":"4d03039736dd6926feb139bc68734cb59df34ede310427bbf059e5c925e0af3b"},"package":null}
|
2
third_party/rust/wgpu-types/Cargo.toml
vendored
2
third_party/rust/wgpu-types/Cargo.toml
vendored
@ -62,7 +62,7 @@ version = "1"
|
||||
features = ["derive"]
|
||||
|
||||
[dev-dependencies.serde_json]
|
||||
version = "1.0.125"
|
||||
version = "1.0.127"
|
||||
|
||||
[features]
|
||||
counters = []
|
||||
|
26
third_party/rust/wgpu-types/src/lib.rs
vendored
26
third_party/rust/wgpu-types/src/lib.rs
vendored
@ -13,6 +13,7 @@ use serde::Deserialize;
|
||||
#[cfg(any(feature = "serde", test))]
|
||||
use serde::Serialize;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::mem::size_of;
|
||||
use std::path::PathBuf;
|
||||
use std::{num::NonZeroU32, ops::Range};
|
||||
|
||||
@ -7228,7 +7229,7 @@ impl DrawIndirectArgs {
|
||||
unsafe {
|
||||
std::mem::transmute(std::slice::from_raw_parts(
|
||||
std::ptr::from_ref(self).cast::<u8>(),
|
||||
std::mem::size_of::<Self>(),
|
||||
size_of::<Self>(),
|
||||
))
|
||||
}
|
||||
}
|
||||
@ -7259,7 +7260,7 @@ impl DrawIndexedIndirectArgs {
|
||||
unsafe {
|
||||
std::mem::transmute(std::slice::from_raw_parts(
|
||||
std::ptr::from_ref(self).cast::<u8>(),
|
||||
std::mem::size_of::<Self>(),
|
||||
size_of::<Self>(),
|
||||
))
|
||||
}
|
||||
}
|
||||
@ -7284,7 +7285,7 @@ impl DispatchIndirectArgs {
|
||||
unsafe {
|
||||
std::mem::transmute(std::slice::from_raw_parts(
|
||||
std::ptr::from_ref(self).cast::<u8>(),
|
||||
std::mem::size_of::<Self>(),
|
||||
size_of::<Self>(),
|
||||
))
|
||||
}
|
||||
}
|
||||
@ -7309,8 +7310,15 @@ impl ShaderBoundChecks {
|
||||
/// Creates a new configuration where the shader isn't bound checked.
|
||||
///
|
||||
/// # Safety
|
||||
/// The caller MUST ensure that all shaders built with this configuration don't perform any
|
||||
/// out of bounds reads or writes.
|
||||
///
|
||||
/// The caller MUST ensure that all shaders built with this configuration
|
||||
/// don't perform any out of bounds reads or writes.
|
||||
///
|
||||
/// Note that `wgpu_core`, in particular, initializes only those portions of
|
||||
/// buffers that it expects might be read, and it does not expect contents
|
||||
/// outside the ranges bound in bindgroups to be accessible, so using this
|
||||
/// configuration with ill-behaved shaders could expose uninitialized GPU
|
||||
/// memory contents to the application.
|
||||
#[must_use]
|
||||
pub unsafe fn unchecked() -> Self {
|
||||
ShaderBoundChecks {
|
||||
@ -7333,10 +7341,6 @@ impl Default for ShaderBoundChecks {
|
||||
|
||||
/// Selects which DX12 shader compiler to use.
|
||||
///
|
||||
/// If the `wgpu-hal/dx12-shader-compiler` feature isn't enabled then this will fall back
|
||||
/// to the Fxc compiler at runtime and log an error.
|
||||
/// This feature is always enabled when using `wgpu`.
|
||||
///
|
||||
/// If the `Dxc` option is selected, but `dxcompiler.dll` and `dxil.dll` files aren't found,
|
||||
/// then this will fall back to the Fxc compiler at runtime and log an error.
|
||||
///
|
||||
@ -7353,6 +7357,10 @@ pub enum Dx12Compiler {
|
||||
///
|
||||
/// However, it requires both `dxcompiler.dll` and `dxil.dll` to be shipped with the application.
|
||||
/// These files can be downloaded from <https://github.com/microsoft/DirectXShaderCompiler/releases>.
|
||||
///
|
||||
/// Minimum supported version: [v1.5.2010](https://github.com/microsoft/DirectXShaderCompiler/releases/tag/v1.5.2010)
|
||||
///
|
||||
/// It also requires WDDM 2.1 (Windows 10 version 1607).
|
||||
Dxc {
|
||||
/// Path to the `dxil.dll` file, or path to the directory containing `dxil.dll` file. Passing `None` will use standard platform specific dll loading rules.
|
||||
dxil_path: Option<PathBuf>,
|
||||
|
Loading…
Reference in New Issue
Block a user