зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1857243 - Update `wgpu` to revision 1495e159faf721cbf87a0634157682f454a963fb. r=webgpu-reviewers,supply-chain-reviewers,ErichDonGubler
Differential Revision: https://phabricator.services.mozilla.com/D190208
This commit is contained in:
Родитель
c04c99325f
Коммит
faf195158d
|
@ -30,14 +30,14 @@ git = "https://github.com/gfx-rs/metal-rs/"
|
|||
rev = "d24f1a4"
|
||||
replace-with = "vendored-sources"
|
||||
|
||||
[source."git+https://github.com/gfx-rs/naga?rev=df8107b7"]
|
||||
[source."git+https://github.com/gfx-rs/naga?rev=6668d0694cc51ee66c71c2ca3a1ab1081956299b"]
|
||||
git = "https://github.com/gfx-rs/naga"
|
||||
rev = "df8107b7"
|
||||
rev = "6668d0694cc51ee66c71c2ca3a1ab1081956299b"
|
||||
replace-with = "vendored-sources"
|
||||
|
||||
[source."git+https://github.com/gfx-rs/wgpu?rev=9a76c483da4891fb7046c579e36d7c54bdb0b251"]
|
||||
[source."git+https://github.com/gfx-rs/wgpu?rev=1495e159faf721cbf87a0634157682f454a963fb"]
|
||||
git = "https://github.com/gfx-rs/wgpu"
|
||||
rev = "9a76c483da4891fb7046c579e36d7c54bdb0b251"
|
||||
rev = "1495e159faf721cbf87a0634157682f454a963fb"
|
||||
replace-with = "vendored-sources"
|
||||
|
||||
[source."git+https://github.com/glandium/prost?rev=95964e9d33df3c2a9c3f14285e262867cab6f96b"]
|
||||
|
|
|
@ -3755,7 +3755,7 @@ checksum = "a2983372caf4480544083767bf2d27defafe32af49ab4df3a0b7fc90793a3664"
|
|||
[[package]]
|
||||
name = "naga"
|
||||
version = "0.13.0"
|
||||
source = "git+https://github.com/gfx-rs/naga?rev=df8107b7#df8107b78812cc2b1e3d5de35279cedc1f0da3fb"
|
||||
source = "git+https://github.com/gfx-rs/naga?rev=6668d0694cc51ee66c71c2ca3a1ab1081956299b#6668d0694cc51ee66c71c2ca3a1ab1081956299b"
|
||||
dependencies = [
|
||||
"bit-set",
|
||||
"bitflags 2.4.0",
|
||||
|
@ -6339,7 +6339,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "wgpu-core"
|
||||
version = "0.17.0"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=9a76c483da4891fb7046c579e36d7c54bdb0b251#9a76c483da4891fb7046c579e36d7c54bdb0b251"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=1495e159faf721cbf87a0634157682f454a963fb#1495e159faf721cbf87a0634157682f454a963fb"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bit-vec",
|
||||
|
@ -6362,7 +6362,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "wgpu-hal"
|
||||
version = "0.17.0"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=9a76c483da4891fb7046c579e36d7c54bdb0b251#9a76c483da4891fb7046c579e36d7c54bdb0b251"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=1495e159faf721cbf87a0634157682f454a963fb#1495e159faf721cbf87a0634157682f454a963fb"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"arrayvec",
|
||||
|
@ -6398,7 +6398,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "wgpu-types"
|
||||
version = "0.17.0"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=9a76c483da4891fb7046c579e36d7c54bdb0b251#9a76c483da4891fb7046c579e36d7c54bdb0b251"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=1495e159faf721cbf87a0634157682f454a963fb#1495e159faf721cbf87a0634157682f454a963fb"
|
||||
dependencies = [
|
||||
"bitflags 2.4.0",
|
||||
"js-sys",
|
||||
|
|
|
@ -17,7 +17,7 @@ default = []
|
|||
[dependencies.wgc]
|
||||
package = "wgpu-core"
|
||||
git = "https://github.com/gfx-rs/wgpu"
|
||||
rev = "9a76c483da4891fb7046c579e36d7c54bdb0b251"
|
||||
rev = "1495e159faf721cbf87a0634157682f454a963fb"
|
||||
#Note: "replay" shouldn't ideally be needed,
|
||||
# but it allows us to serialize everything across IPC.
|
||||
features = ["replay", "trace", "serial-pass", "strict_asserts", "wgsl"]
|
||||
|
@ -27,32 +27,32 @@ features = ["replay", "trace", "serial-pass", "strict_asserts", "wgsl"]
|
|||
[target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies.wgc]
|
||||
package = "wgpu-core"
|
||||
git = "https://github.com/gfx-rs/wgpu"
|
||||
rev = "9a76c483da4891fb7046c579e36d7c54bdb0b251"
|
||||
rev = "1495e159faf721cbf87a0634157682f454a963fb"
|
||||
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 = "9a76c483da4891fb7046c579e36d7c54bdb0b251"
|
||||
rev = "1495e159faf721cbf87a0634157682f454a963fb"
|
||||
features = ["dx11", "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 = "9a76c483da4891fb7046c579e36d7c54bdb0b251"
|
||||
rev = "1495e159faf721cbf87a0634157682f454a963fb"
|
||||
features = ["vulkan"]
|
||||
|
||||
[dependencies.wgt]
|
||||
package = "wgpu-types"
|
||||
git = "https://github.com/gfx-rs/wgpu"
|
||||
rev = "9a76c483da4891fb7046c579e36d7c54bdb0b251"
|
||||
rev = "1495e159faf721cbf87a0634157682f454a963fb"
|
||||
|
||||
[dependencies.wgh]
|
||||
package = "wgpu-hal"
|
||||
git = "https://github.com/gfx-rs/wgpu"
|
||||
rev = "9a76c483da4891fb7046c579e36d7c54bdb0b251"
|
||||
rev = "1495e159faf721cbf87a0634157682f454a963fb"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
d3d12 = "0.7.0"
|
||||
|
|
|
@ -20,11 +20,11 @@ origin:
|
|||
|
||||
# Human-readable identifier for this version/release
|
||||
# Generally "version NNN", "tag SSS", "bookmark SSS"
|
||||
release: commit 9a76c483da4891fb7046c579e36d7c54bdb0b251
|
||||
release: commit 1495e159faf721cbf87a0634157682f454a963fb
|
||||
|
||||
# Revision to pull in
|
||||
# Must be a long or short commit SHA (long preferred)
|
||||
revision: 9a76c483da4891fb7046c579e36d7c54bdb0b251
|
||||
revision: 1495e159faf721cbf87a0634157682f454a963fb
|
||||
|
||||
license: ['MIT', 'Apache-2.0']
|
||||
|
||||
|
|
|
@ -436,7 +436,7 @@ mod foreign {
|
|||
impl HasErrorBufferType for DeviceError {
|
||||
fn error_type(&self) -> ErrorBufferType {
|
||||
match self {
|
||||
DeviceError::Invalid => ErrorBufferType::Validation,
|
||||
DeviceError::Invalid | DeviceError::WrongDevice => ErrorBufferType::Validation,
|
||||
DeviceError::Lost => ErrorBufferType::None,
|
||||
DeviceError::OutOfMemory => ErrorBufferType::OutOfMemory,
|
||||
DeviceError::ResourceCreationFailed => ErrorBufferType::Internal,
|
||||
|
|
|
@ -2344,6 +2344,11 @@ who = "Nicolas Silva <nical@fastmail.com>"
|
|||
criteria = "safe-to-deploy"
|
||||
delta = "0.13.0@git:cc87b8f9eb30bb55d0735b89d3df3e099e1a6e7c -> 0.13.0@git:df8107b78812cc2b1e3d5de35279cedc1f0da3fb"
|
||||
|
||||
[[audits.naga]]
|
||||
who = "Nicolas Silva <nical@fastmail.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
delta = "0.13.0@git:df8107b78812cc2b1e3d5de35279cedc1f0da3fb -> 0.13.0@git:6668d0694cc51ee66c71c2ca3a1ab1081956299b"
|
||||
|
||||
[[audits.net2]]
|
||||
who = "Mike Hommey <mh+mozilla@glandium.org>"
|
||||
criteria = "safe-to-run"
|
||||
|
@ -4073,6 +4078,11 @@ who = "Nicolas Silva <nical@fastmail.com>"
|
|||
criteria = "safe-to-deploy"
|
||||
delta = "0.17.0@git:7fea9e934efd8d5dc03b9aa3e06b775c1ac4a23e -> 0.17.0@git:7e0d6c971f900f6a8f01a9de9c41f7894164a82c"
|
||||
|
||||
[[audits.wgpu-core]]
|
||||
who = "Nicolas Silva <nical@fastmail.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
delta = "0.17.0@git:9a76c483da4891fb7046c579e36d7c54bdb0b251 -> 0.17.0@git:1495e159faf721cbf87a0634157682f454a963fb"
|
||||
|
||||
[[audits.wgpu-hal]]
|
||||
who = "Dzmitry Malyshau <kvark@fastmail.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
|
@ -4196,6 +4206,11 @@ who = "Nicolas Silva <nical@fastmail.com>"
|
|||
criteria = "safe-to-deploy"
|
||||
delta = "0.17.0@git:7fea9e934efd8d5dc03b9aa3e06b775c1ac4a23e -> 0.17.0@git:7e0d6c971f900f6a8f01a9de9c41f7894164a82c"
|
||||
|
||||
[[audits.wgpu-hal]]
|
||||
who = "Nicolas Silva <nical@fastmail.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
delta = "0.17.0@git:9a76c483da4891fb7046c579e36d7c54bdb0b251 -> 0.17.0@git:1495e159faf721cbf87a0634157682f454a963fb"
|
||||
|
||||
[[audits.wgpu-types]]
|
||||
who = "Dzmitry Malyshau <kvark@fastmail.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
|
@ -4319,6 +4334,11 @@ who = "Nicolas Silva <nical@fastmail.com>"
|
|||
criteria = "safe-to-deploy"
|
||||
delta = "0.17.0@git:7fea9e934efd8d5dc03b9aa3e06b775c1ac4a23e -> 0.17.0@git:7e0d6c971f900f6a8f01a9de9c41f7894164a82c"
|
||||
|
||||
[[audits.wgpu-types]]
|
||||
who = "Nicolas Silva <nical@fastmail.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
delta = "0.17.0@git:9a76c483da4891fb7046c579e36d7c54bdb0b251 -> 0.17.0@git:1495e159faf721cbf87a0634157682f454a963fb"
|
||||
|
||||
[[audits.whatsys]]
|
||||
who = "Bobby Holley <bobbyholley@gmail.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -130,6 +130,7 @@ arbitrary = [
|
|||
"indexmap/arbitrary",
|
||||
]
|
||||
clone = []
|
||||
compact = []
|
||||
default = []
|
||||
deserialize = [
|
||||
"serde",
|
||||
|
|
|
@ -5,8 +5,7 @@ use std::{cmp::Ordering, fmt, hash, marker::PhantomData, num::NonZeroU32, ops};
|
|||
/// the same size and representation as `Handle<T>`.
|
||||
type Index = NonZeroU32;
|
||||
|
||||
use crate::Span;
|
||||
use indexmap::set::IndexSet;
|
||||
use crate::{FastIndexSet, Span};
|
||||
|
||||
#[derive(Clone, Copy, Debug, thiserror::Error, PartialEq)]
|
||||
#[error("Handle {index} of {kind} is either not present, or inaccessible yet")]
|
||||
|
@ -192,12 +191,31 @@ impl<T> Iterator for Range<T> {
|
|||
}
|
||||
|
||||
impl<T> Range<T> {
|
||||
/// Return a range enclosing handles `first` through `last`, inclusive.
|
||||
pub fn new_from_bounds(first: Handle<T>, last: Handle<T>) -> Self {
|
||||
Self {
|
||||
inner: (first.index() as u32)..(last.index() as u32 + 1),
|
||||
marker: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the first and last handles included in `self`.
|
||||
///
|
||||
/// If `self` is an empty range, there are no handles included, so
|
||||
/// return `None`.
|
||||
pub fn first_and_last(&self) -> Option<(Handle<T>, Handle<T>)> {
|
||||
if self.inner.start < self.inner.end {
|
||||
Some((
|
||||
// `Range::new_from_bounds` expects a 1-based, start- and
|
||||
// end-inclusive range, but `self.inner` is a zero-based,
|
||||
// end-exclusive range.
|
||||
Handle::new(Index::new(self.inner.start + 1).unwrap()),
|
||||
Handle::new(Index::new(self.inner.end).unwrap()),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An arena holding some kind of component (e.g., type, constant,
|
||||
|
@ -382,6 +400,19 @@ impl<T> Arena<T> {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "compact")]
|
||||
pub(crate) fn retain_mut<P>(&mut self, mut predicate: P)
|
||||
where
|
||||
P: FnMut(Handle<T>, &mut T) -> bool,
|
||||
{
|
||||
let mut index = 0;
|
||||
self.data.retain_mut(|elt| {
|
||||
index += 1;
|
||||
let handle = Handle::new(Index::new(index).unwrap());
|
||||
predicate(handle, elt)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "deserialize")]
|
||||
|
@ -484,11 +515,11 @@ mod tests {
|
|||
/// `UniqueArena` is `HashSet`-like.
|
||||
#[cfg_attr(feature = "clone", derive(Clone))]
|
||||
pub struct UniqueArena<T> {
|
||||
set: IndexSet<T>,
|
||||
set: FastIndexSet<T>,
|
||||
|
||||
/// Spans for the elements, indexed by handle.
|
||||
///
|
||||
/// The length of this vector is always equal to `set.len()`. `IndexSet`
|
||||
/// The length of this vector is always equal to `set.len()`. `FastIndexSet`
|
||||
/// promises that its elements "are indexed in a compact range, without
|
||||
/// holes in the range 0..set.len()", so we can always use the indices
|
||||
/// returned by insertion as indices into this vector.
|
||||
|
@ -500,7 +531,7 @@ impl<T> UniqueArena<T> {
|
|||
/// Create a new arena with no initial capacity allocated.
|
||||
pub fn new() -> Self {
|
||||
UniqueArena {
|
||||
set: IndexSet::new(),
|
||||
set: FastIndexSet::default(),
|
||||
#[cfg(feature = "span")]
|
||||
span_info: Vec::new(),
|
||||
}
|
||||
|
@ -544,6 +575,44 @@ impl<T> UniqueArena<T> {
|
|||
Span::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "compact")]
|
||||
pub(crate) fn drain_all(&mut self) -> UniqueArenaDrain<T> {
|
||||
UniqueArenaDrain {
|
||||
inner_elts: self.set.drain(..),
|
||||
#[cfg(feature = "span")]
|
||||
inner_spans: self.span_info.drain(..),
|
||||
index: Index::new(1).unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "compact")]
|
||||
pub(crate) struct UniqueArenaDrain<'a, T> {
|
||||
inner_elts: indexmap::set::Drain<'a, T>,
|
||||
#[cfg(feature = "span")]
|
||||
inner_spans: std::vec::Drain<'a, Span>,
|
||||
index: Index,
|
||||
}
|
||||
|
||||
#[cfg(feature = "compact")]
|
||||
impl<'a, T> Iterator for UniqueArenaDrain<'a, T> {
|
||||
type Item = (Handle<T>, T, Span);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self.inner_elts.next() {
|
||||
Some(elt) => {
|
||||
let handle = Handle::new(self.index);
|
||||
self.index = self.index.checked_add(1).unwrap();
|
||||
#[cfg(feature = "span")]
|
||||
let span = self.inner_spans.next().unwrap();
|
||||
#[cfg(not(feature = "span"))]
|
||||
let span = Span::default();
|
||||
Some((handle, elt, span))
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Eq + hash::Hash> UniqueArena<T> {
|
||||
|
@ -671,7 +740,7 @@ where
|
|||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let set = IndexSet::deserialize(deserializer)?;
|
||||
let set = FastIndexSet::deserialize(deserializer)?;
|
||||
#[cfg(feature = "span")]
|
||||
let span_info = std::iter::repeat(Span::default()).take(set.len()).collect();
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ use std::{
|
|||
};
|
||||
|
||||
/// Configuration options for the dot backend
|
||||
#[derive(Default)]
|
||||
#[derive(Clone, Default)]
|
||||
pub struct Options {
|
||||
/// Only emit function bodies
|
||||
pub cfg_only: bool,
|
||||
|
|
|
@ -209,11 +209,6 @@ impl FeaturesManager {
|
|||
writeln!(out, "#extension GL_OES_sample_variables : require")?;
|
||||
}
|
||||
|
||||
if self.0.contains(Features::SAMPLE_VARIABLES) && version.is_es() {
|
||||
// https://www.khronos.org/registry/OpenGL/extensions/OES/OES_sample_variables.txt
|
||||
writeln!(out, "#extension GL_OES_sample_variables : require")?;
|
||||
}
|
||||
|
||||
if self.0.contains(Features::MULTI_VIEW) {
|
||||
if let Version::Embedded { is_webgl: true, .. } = version {
|
||||
// https://www.khronos.org/registry/OpenGL/extensions/OVR/OVR_multiview2.txt
|
||||
|
@ -362,6 +357,7 @@ impl<'a, W> Writer<'a, W> {
|
|||
| StorageFormat::Rg16Uint
|
||||
| StorageFormat::Rg16Sint
|
||||
| StorageFormat::Rg16Float
|
||||
| StorageFormat::Rgb10a2Uint
|
||||
| StorageFormat::Rgb10a2Unorm
|
||||
| StorageFormat::Rg11b10Float
|
||||
| StorageFormat::Rg32Uint
|
||||
|
|
|
@ -189,6 +189,10 @@ impl Version {
|
|||
*self >= Version::Desktop(400) || *self >= Version::new_gles(310)
|
||||
}
|
||||
|
||||
fn supports_frexp_function(&self) -> bool {
|
||||
*self >= Version::Desktop(400) || *self >= Version::new_gles(310)
|
||||
}
|
||||
|
||||
fn supports_derivative_control(&self) -> bool {
|
||||
*self >= Version::Desktop(450)
|
||||
}
|
||||
|
@ -667,15 +671,27 @@ impl<'a, W: Write> Writer<'a, W> {
|
|||
let struct_name = &self.names[&NameKey::Type(*struct_ty)];
|
||||
|
||||
writeln!(self.out)?;
|
||||
writeln!(
|
||||
self.out,
|
||||
"{} {defined_func_name}({arg_type_name} arg) {{
|
||||
if !self.options.version.supports_frexp_function()
|
||||
&& matches!(type_key, &crate::PredeclaredType::FrexpResult { .. })
|
||||
{
|
||||
writeln!(
|
||||
self.out,
|
||||
"{struct_name} {defined_func_name}({arg_type_name} arg) {{
|
||||
{other_type_name} other = arg == {arg_type_name}(0) ? {other_type_name}(0) : {other_type_name}({arg_type_name}(1) + log2(arg));
|
||||
{arg_type_name} fract = arg * exp2({arg_type_name}(-other));
|
||||
return {struct_name}(fract, other);
|
||||
}}",
|
||||
)?;
|
||||
} else {
|
||||
writeln!(
|
||||
self.out,
|
||||
"{struct_name} {defined_func_name}({arg_type_name} arg) {{
|
||||
{other_type_name} other;
|
||||
{arg_type_name} fract = {called_func_name}(arg, other);
|
||||
return {}(fract, other);
|
||||
return {struct_name}(fract, other);
|
||||
}}",
|
||||
struct_name, struct_name
|
||||
)?;
|
||||
)?;
|
||||
}
|
||||
}
|
||||
&crate::PredeclaredType::AtomicCompareExchangeWeakResult { .. } => {}
|
||||
}
|
||||
|
@ -1113,7 +1129,8 @@ impl<'a, W: Write> Writer<'a, W> {
|
|||
let ty_name = &self.names[&NameKey::Type(global.ty)];
|
||||
let block_name = format!(
|
||||
"{}_block_{}{:?}",
|
||||
ty_name,
|
||||
// avoid double underscores as they are reserved in GLSL
|
||||
ty_name.trim_end_matches('_'),
|
||||
self.block_id.generate(),
|
||||
self.entry_point.stage,
|
||||
);
|
||||
|
@ -4221,7 +4238,8 @@ const fn glsl_storage_format(format: crate::StorageFormat) -> &'static str {
|
|||
Sf::Rgba8Snorm => "rgba8_snorm",
|
||||
Sf::Rgba8Uint => "rgba8ui",
|
||||
Sf::Rgba8Sint => "rgba8i",
|
||||
Sf::Rgb10a2Unorm => "rgb10_a2ui",
|
||||
Sf::Rgb10a2Uint => "rgb10_a2ui",
|
||||
Sf::Rgb10a2Unorm => "rgb10_a2",
|
||||
Sf::Rg11b10Float => "r11f_g11f_b10f",
|
||||
Sf::Rg32Uint => "rg32ui",
|
||||
Sf::Rg32Sint => "rg32i",
|
||||
|
|
|
@ -129,7 +129,8 @@ impl crate::StorageFormat {
|
|||
| Self::Rgba16Uint
|
||||
| Self::R32Uint
|
||||
| Self::Rg32Uint
|
||||
| Self::Rgba32Uint => "uint4",
|
||||
| Self::Rgba32Uint
|
||||
| Self::Rgb10a2Uint => "uint4",
|
||||
Self::Rgba8Sint
|
||||
| Self::Rgba16Sint
|
||||
| Self::R32Sint
|
||||
|
|
|
@ -2352,12 +2352,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
|
|||
}
|
||||
}
|
||||
Expression::FunctionArgument(pos) => {
|
||||
let key = match func_ctx.ty {
|
||||
back::FunctionType::Function(handle) => NameKey::FunctionArgument(handle, pos),
|
||||
back::FunctionType::EntryPoint(index) => {
|
||||
NameKey::EntryPointArgument(index, pos)
|
||||
}
|
||||
};
|
||||
let key = func_ctx.argument_key(pos);
|
||||
let name = &self.names[&key];
|
||||
write!(self.out, "{name}")?;
|
||||
}
|
||||
|
|
|
@ -37,13 +37,28 @@ impl std::fmt::Display for Level {
|
|||
}
|
||||
}
|
||||
|
||||
/// Stores the current function type (either a regular function or an entry point)
|
||||
/// Whether we're generating an entry point or a regular function.
|
||||
///
|
||||
/// Also stores data needed to identify it (handle for a regular function or index for an entry point)
|
||||
/// Backend languages often require different code for a [`Function`]
|
||||
/// depending on whether it represents an [`EntryPoint`] or not.
|
||||
/// Backends can pass common code one of these values to select the
|
||||
/// right behavior.
|
||||
///
|
||||
/// These values also carry enough information to find the `Function`
|
||||
/// in the [`Module`]: the `Handle` for a regular function, or the
|
||||
/// index into [`Module::entry_points`] for an entry point.
|
||||
///
|
||||
/// [`Function`]: crate::Function
|
||||
/// [`EntryPoint`]: crate::EntryPoint
|
||||
/// [`Module`]: crate::Module
|
||||
/// [`Module::entry_points`]: crate::Module::entry_points
|
||||
enum FunctionType {
|
||||
/// A regular function and it's handle
|
||||
/// A regular function.
|
||||
Function(crate::Handle<crate::Function>),
|
||||
/// A entry point and it's index
|
||||
/// An [`EntryPoint`], and its index in [`Module::entry_points`].
|
||||
///
|
||||
/// [`EntryPoint`]: crate::EntryPoint
|
||||
/// [`Module::entry_points`]: crate::Module::entry_points
|
||||
EntryPoint(crate::proc::EntryPointIndex),
|
||||
}
|
||||
|
||||
|
|
|
@ -3689,6 +3689,15 @@ impl<W: Write> Writer<W> {
|
|||
}
|
||||
};
|
||||
|
||||
// Since `Namer.reset` wasn't expecting struct members to be
|
||||
// suddenly injected into another namespace like this,
|
||||
// `self.names` doesn't keep them distinct from other variables.
|
||||
// Generate fresh names for these arguments, and remember the
|
||||
// mapping.
|
||||
let mut flattened_member_names = FastHashMap::default();
|
||||
// Varyings' members get their own namespace
|
||||
let mut varyings_namer = crate::proc::Namer::default();
|
||||
|
||||
// List all the Naga `EntryPoint`'s `Function`'s arguments,
|
||||
// flattening structs into their members. In Metal, we will pass
|
||||
// each of these values to the entry point as a separate argument—
|
||||
|
@ -3704,6 +3713,14 @@ impl<W: Write> Writer<W> {
|
|||
member.ty,
|
||||
member.binding.as_ref(),
|
||||
));
|
||||
let name_key = NameKey::StructMember(arg.ty, member_index);
|
||||
let name = match member.binding {
|
||||
Some(crate::Binding::Location { .. }) => {
|
||||
varyings_namer.call(&self.names[&name_key])
|
||||
}
|
||||
_ => self.namer.call(&self.names[&name_key]),
|
||||
};
|
||||
flattened_member_names.insert(name_key, name);
|
||||
}
|
||||
}
|
||||
_ => flattened_arguments.push((
|
||||
|
@ -3727,7 +3744,10 @@ impl<W: Write> Writer<W> {
|
|||
_ => continue,
|
||||
};
|
||||
has_varyings = true;
|
||||
let name = &self.names[name_key];
|
||||
let name = match *name_key {
|
||||
NameKey::StructMember(..) => &flattened_member_names[name_key],
|
||||
_ => &self.names[name_key],
|
||||
};
|
||||
let ty_name = TypeContext {
|
||||
handle: ty,
|
||||
gctx: module.to_ctx(),
|
||||
|
@ -3840,27 +3860,14 @@ impl<W: Write> Writer<W> {
|
|||
|
||||
// Then pass the remaining arguments not included in the varyings
|
||||
// struct.
|
||||
//
|
||||
// Since `Namer.reset` wasn't expecting struct members to be
|
||||
// suddenly injected into the normal namespace like this,
|
||||
// `self.names` doesn't keep them distinct from other variables.
|
||||
// Generate fresh names for these arguments, and remember the
|
||||
// mapping.
|
||||
let mut flattened_member_names = FastHashMap::default();
|
||||
for &(ref name_key, ty, binding) in flattened_arguments.iter() {
|
||||
let binding = match binding {
|
||||
Some(binding @ &crate::Binding::BuiltIn { .. }) => binding,
|
||||
_ => continue,
|
||||
};
|
||||
let name = if let NameKey::StructMember(ty, index) = *name_key {
|
||||
// We should always insert a fresh entry here, but use
|
||||
// `or_insert` to get a reference to the `String` we just
|
||||
// inserted.
|
||||
flattened_member_names
|
||||
.entry(NameKey::StructMember(ty, index))
|
||||
.or_insert_with(|| self.namer.call(&self.names[name_key]))
|
||||
} else {
|
||||
&self.names[name_key]
|
||||
let name = match *name_key {
|
||||
NameKey::StructMember(..) => &flattened_member_names[name_key],
|
||||
_ => &self.names[name_key],
|
||||
};
|
||||
|
||||
if binding == &crate::Binding::BuiltIn(crate::BuiltIn::LocalInvocationId) {
|
||||
|
@ -4057,15 +4064,7 @@ impl<W: Write> Writer<W> {
|
|||
)?;
|
||||
for (member_index, member) in members.iter().enumerate() {
|
||||
let key = NameKey::StructMember(arg.ty, member_index as u32);
|
||||
// If it's not in the varying struct, then we should
|
||||
// have passed it as its own argument and assigned
|
||||
// it a new name.
|
||||
let name = match member.binding {
|
||||
Some(crate::Binding::BuiltIn { .. }) => {
|
||||
&flattened_member_names[&key]
|
||||
}
|
||||
_ => &self.names[&key],
|
||||
};
|
||||
let name = &flattened_member_names[&key];
|
||||
if member_index != 0 {
|
||||
write!(self.out, ", ")?;
|
||||
}
|
||||
|
|
|
@ -1064,7 +1064,8 @@ impl From<crate::StorageFormat> for spirv::ImageFormat {
|
|||
Sf::Rgba8Snorm => Self::Rgba8Snorm,
|
||||
Sf::Rgba8Uint => Self::Rgba8ui,
|
||||
Sf::Rgba8Sint => Self::Rgba8i,
|
||||
Sf::Rgb10a2Unorm => Self::Rgb10a2ui,
|
||||
Sf::Rgb10a2Uint => Self::Rgb10a2ui,
|
||||
Sf::Rgb10a2Unorm => Self::Rgb10A2,
|
||||
Sf::Rg11b10Float => Self::R11fG11fB10f,
|
||||
Sf::Rg32Uint => Self::Rg32ui,
|
||||
Sf::Rg32Sint => Self::Rg32i,
|
||||
|
|
|
@ -85,7 +85,7 @@ impl IdGenerator {
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct DebugInfo<'a> {
|
||||
pub source_code: &'a str,
|
||||
pub file_name: &'a str,
|
||||
pub file_name: &'a std::path::Path,
|
||||
}
|
||||
|
||||
/// A SPIR-V block to which we are still adding instructions.
|
||||
|
|
|
@ -1514,8 +1514,20 @@ impl Writer {
|
|||
// vertex
|
||||
Bi::BaseInstance => BuiltIn::BaseInstance,
|
||||
Bi::BaseVertex => BuiltIn::BaseVertex,
|
||||
Bi::ClipDistance => BuiltIn::ClipDistance,
|
||||
Bi::CullDistance => BuiltIn::CullDistance,
|
||||
Bi::ClipDistance => {
|
||||
self.require_any(
|
||||
"`clip_distance` built-in",
|
||||
&[spirv::Capability::ClipDistance],
|
||||
)?;
|
||||
BuiltIn::ClipDistance
|
||||
}
|
||||
Bi::CullDistance => {
|
||||
self.require_any(
|
||||
"`cull_distance` built-in",
|
||||
&[spirv::Capability::CullDistance],
|
||||
)?;
|
||||
BuiltIn::CullDistance
|
||||
}
|
||||
Bi::InstanceIndex => BuiltIn::InstanceIndex,
|
||||
Bi::PointSize => BuiltIn::PointSize,
|
||||
Bi::VertexIndex => BuiltIn::VertexIndex,
|
||||
|
@ -1840,8 +1852,10 @@ impl Writer {
|
|||
if self.flags.contains(WriterFlags::DEBUG) {
|
||||
if let Some(debug_info) = debug_info.as_ref() {
|
||||
let source_file_id = self.id_gen.next();
|
||||
self.debugs
|
||||
.push(Instruction::string(debug_info.file_name, source_file_id));
|
||||
self.debugs.push(Instruction::string(
|
||||
&debug_info.file_name.display().to_string(),
|
||||
source_file_id,
|
||||
));
|
||||
|
||||
debug_info_inner = Some(DebugInfoInner {
|
||||
source_code: debug_info.source_code,
|
||||
|
|
|
@ -247,14 +247,7 @@ impl<W: Write> Writer<W> {
|
|||
self.write_attributes(&map_binding_to_attribute(binding))?;
|
||||
}
|
||||
// Write argument name
|
||||
let argument_name = match func_ctx.ty {
|
||||
back::FunctionType::Function(handle) => {
|
||||
&self.names[&NameKey::FunctionArgument(handle, index as u32)]
|
||||
}
|
||||
back::FunctionType::EntryPoint(ep_index) => {
|
||||
&self.names[&NameKey::EntryPointArgument(ep_index, index as u32)]
|
||||
}
|
||||
};
|
||||
let argument_name = &self.names[&func_ctx.argument_key(index as u32)];
|
||||
|
||||
write!(self.out, "{argument_name}: ")?;
|
||||
// Write argument type
|
||||
|
@ -1837,6 +1830,7 @@ const fn storage_format_str(format: crate::StorageFormat) -> &'static str {
|
|||
Sf::Rgba8Snorm => "rgba8snorm",
|
||||
Sf::Rgba8Uint => "rgba8uint",
|
||||
Sf::Rgba8Sint => "rgba8sint",
|
||||
Sf::Rgb10a2Uint => "rgb10a2uint",
|
||||
Sf::Rgb10a2Unorm => "rgb10a2unorm",
|
||||
Sf::Rg11b10Float => "rg11b10float",
|
||||
Sf::Rg32Uint => "rg32uint",
|
||||
|
|
|
@ -0,0 +1,395 @@
|
|||
use super::{HandleMap, HandleSet, ModuleMap};
|
||||
use crate::arena::{Arena, Handle, UniqueArena};
|
||||
|
||||
pub struct ExpressionTracer<'tracer> {
|
||||
pub types: &'tracer UniqueArena<crate::Type>,
|
||||
pub constants: &'tracer Arena<crate::Constant>,
|
||||
|
||||
/// The arena in which we are currently tracing expressions.
|
||||
pub expressions: &'tracer Arena<crate::Expression>,
|
||||
|
||||
/// The used map for `types`.
|
||||
pub types_used: &'tracer mut HandleSet<crate::Type>,
|
||||
|
||||
/// The used map for `constants`.
|
||||
pub constants_used: &'tracer mut HandleSet<crate::Constant>,
|
||||
|
||||
/// The used set for `arena`.
|
||||
///
|
||||
/// This points to whatever arena holds the expressions we are
|
||||
/// currently tracing: either a function's expression arena, or
|
||||
/// the module's constant expression arena.
|
||||
pub expressions_used: &'tracer mut HandleSet<crate::Expression>,
|
||||
|
||||
/// The constant expression arena and its used map, if we haven't
|
||||
/// switched to tracing constant expressions yet.
|
||||
pub const_expressions: Option<(
|
||||
&'tracer Arena<crate::Expression>,
|
||||
&'tracer mut HandleSet<crate::Expression>,
|
||||
)>,
|
||||
}
|
||||
|
||||
impl<'tracer> ExpressionTracer<'tracer> {
|
||||
pub fn trace_expression(&mut self, expr: Handle<crate::Expression>) {
|
||||
log::trace!(
|
||||
"entering trace_expression of {}",
|
||||
if self.const_expressions.is_some() {
|
||||
"function expressions"
|
||||
} else {
|
||||
"const expressions"
|
||||
}
|
||||
);
|
||||
let mut work_list = vec![expr];
|
||||
while let Some(expr) = work_list.pop() {
|
||||
// If we've already seen this expression, no need to trace further.
|
||||
if !self.expressions_used.insert(expr) {
|
||||
continue;
|
||||
}
|
||||
log::trace!("tracing new expression {:?}", expr);
|
||||
|
||||
use crate::Expression as Ex;
|
||||
match self.expressions[expr] {
|
||||
// Expressions that do not contain handles that need to be traced.
|
||||
Ex::Literal(_)
|
||||
| Ex::FunctionArgument(_)
|
||||
| Ex::GlobalVariable(_)
|
||||
| Ex::LocalVariable(_)
|
||||
| Ex::CallResult(_)
|
||||
| Ex::RayQueryProceedResult => {}
|
||||
|
||||
Ex::Constant(handle) => {
|
||||
self.constants_used.insert(handle);
|
||||
let constant = &self.constants[handle];
|
||||
self.trace_type(constant.ty);
|
||||
self.trace_const_expression(constant.init);
|
||||
}
|
||||
Ex::ZeroValue(ty) => self.trace_type(ty),
|
||||
Ex::Compose { ty, ref components } => {
|
||||
self.trace_type(ty);
|
||||
work_list.extend(components);
|
||||
}
|
||||
Ex::Access { base, index } => work_list.extend([base, index]),
|
||||
Ex::AccessIndex { base, index: _ } => work_list.push(base),
|
||||
Ex::Splat { size: _, value } => work_list.push(value),
|
||||
Ex::Swizzle {
|
||||
size: _,
|
||||
vector,
|
||||
pattern: _,
|
||||
} => work_list.push(vector),
|
||||
Ex::Load { pointer } => work_list.push(pointer),
|
||||
Ex::ImageSample {
|
||||
image,
|
||||
sampler,
|
||||
gather: _,
|
||||
coordinate,
|
||||
array_index,
|
||||
offset,
|
||||
ref level,
|
||||
depth_ref,
|
||||
} => {
|
||||
work_list.push(image);
|
||||
work_list.push(sampler);
|
||||
work_list.push(coordinate);
|
||||
work_list.extend(array_index);
|
||||
if let Some(offset) = offset {
|
||||
self.trace_const_expression(offset);
|
||||
}
|
||||
use crate::SampleLevel as Sl;
|
||||
match *level {
|
||||
Sl::Auto | Sl::Zero => {}
|
||||
Sl::Exact(expr) | Sl::Bias(expr) => work_list.push(expr),
|
||||
Sl::Gradient { x, y } => work_list.extend([x, y]),
|
||||
}
|
||||
work_list.extend(depth_ref);
|
||||
}
|
||||
Ex::ImageLoad {
|
||||
image,
|
||||
coordinate,
|
||||
array_index,
|
||||
sample,
|
||||
level,
|
||||
} => {
|
||||
work_list.push(image);
|
||||
work_list.push(coordinate);
|
||||
work_list.extend(array_index);
|
||||
work_list.extend(sample);
|
||||
work_list.extend(level);
|
||||
}
|
||||
Ex::ImageQuery { image, ref query } => {
|
||||
work_list.push(image);
|
||||
use crate::ImageQuery as Iq;
|
||||
match *query {
|
||||
Iq::Size { level } => work_list.extend(level),
|
||||
Iq::NumLevels | Iq::NumLayers | Iq::NumSamples => {}
|
||||
}
|
||||
}
|
||||
Ex::Unary { op: _, expr } => work_list.push(expr),
|
||||
Ex::Binary { op: _, left, right } => work_list.extend([left, right]),
|
||||
Ex::Select {
|
||||
condition,
|
||||
accept,
|
||||
reject,
|
||||
} => work_list.extend([condition, accept, reject]),
|
||||
Ex::Derivative {
|
||||
axis: _,
|
||||
ctrl: _,
|
||||
expr,
|
||||
} => work_list.push(expr),
|
||||
Ex::Relational { fun: _, argument } => work_list.push(argument),
|
||||
Ex::Math {
|
||||
fun: _,
|
||||
arg,
|
||||
arg1,
|
||||
arg2,
|
||||
arg3,
|
||||
} => {
|
||||
work_list.push(arg);
|
||||
work_list.extend(arg1);
|
||||
work_list.extend(arg2);
|
||||
work_list.extend(arg3);
|
||||
}
|
||||
Ex::As {
|
||||
expr,
|
||||
kind: _,
|
||||
convert: _,
|
||||
} => work_list.push(expr),
|
||||
Ex::AtomicResult { ty, comparison: _ } => self.trace_type(ty),
|
||||
Ex::WorkGroupUniformLoadResult { ty } => self.trace_type(ty),
|
||||
Ex::ArrayLength(expr) => work_list.push(expr),
|
||||
Ex::RayQueryGetIntersection {
|
||||
query,
|
||||
committed: _,
|
||||
} => work_list.push(query),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn trace_type(&mut self, ty: Handle<crate::Type>) {
|
||||
let mut types_used = super::types::TypeTracer {
|
||||
types: self.types,
|
||||
types_used: self.types_used,
|
||||
};
|
||||
types_used.trace_type(ty);
|
||||
}
|
||||
|
||||
pub fn as_const_expression(&mut self) -> ExpressionTracer {
|
||||
match self.const_expressions {
|
||||
Some((ref mut exprs, ref mut exprs_used)) => ExpressionTracer {
|
||||
expressions: exprs,
|
||||
expressions_used: exprs_used,
|
||||
types: self.types,
|
||||
constants: self.constants,
|
||||
types_used: self.types_used,
|
||||
constants_used: self.constants_used,
|
||||
const_expressions: None,
|
||||
},
|
||||
None => ExpressionTracer {
|
||||
types: self.types,
|
||||
constants: self.constants,
|
||||
expressions: self.expressions,
|
||||
types_used: self.types_used,
|
||||
constants_used: self.constants_used,
|
||||
expressions_used: self.expressions_used,
|
||||
const_expressions: None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn trace_const_expression(&mut self, const_expr: Handle<crate::Expression>) {
|
||||
self.as_const_expression().trace_expression(const_expr);
|
||||
}
|
||||
}
|
||||
|
||||
impl ModuleMap {
|
||||
/// Fix up all handles in `expr`.
|
||||
///
|
||||
/// Use the expression handle remappings in `operand_map`, and all
|
||||
/// other mappings from `self`.
|
||||
pub fn adjust_expression(
|
||||
&self,
|
||||
expr: &mut crate::Expression,
|
||||
operand_map: &HandleMap<crate::Expression>,
|
||||
) {
|
||||
let adjust = |expr: &mut Handle<crate::Expression>| {
|
||||
operand_map.adjust(expr);
|
||||
};
|
||||
|
||||
use crate::Expression as Ex;
|
||||
match *expr {
|
||||
// Expressions that do not contain handles that need to be adjusted.
|
||||
Ex::Literal(_)
|
||||
| Ex::FunctionArgument(_)
|
||||
| Ex::GlobalVariable(_)
|
||||
| Ex::LocalVariable(_)
|
||||
| Ex::CallResult(_)
|
||||
| Ex::RayQueryProceedResult => {}
|
||||
|
||||
// Expressions that contain handles that need to be adjusted.
|
||||
Ex::Constant(ref mut constant) => self.constants.adjust(constant),
|
||||
Ex::ZeroValue(ref mut ty) => self.types.adjust(ty),
|
||||
Ex::Compose {
|
||||
ref mut ty,
|
||||
ref mut components,
|
||||
} => {
|
||||
self.types.adjust(ty);
|
||||
for component in components {
|
||||
adjust(component);
|
||||
}
|
||||
}
|
||||
Ex::Access {
|
||||
ref mut base,
|
||||
ref mut index,
|
||||
} => {
|
||||
adjust(base);
|
||||
adjust(index);
|
||||
}
|
||||
Ex::AccessIndex {
|
||||
ref mut base,
|
||||
index: _,
|
||||
} => adjust(base),
|
||||
Ex::Splat {
|
||||
size: _,
|
||||
ref mut value,
|
||||
} => adjust(value),
|
||||
Ex::Swizzle {
|
||||
size: _,
|
||||
ref mut vector,
|
||||
pattern: _,
|
||||
} => adjust(vector),
|
||||
Ex::Load { ref mut pointer } => adjust(pointer),
|
||||
Ex::ImageSample {
|
||||
ref mut image,
|
||||
ref mut sampler,
|
||||
gather: _,
|
||||
ref mut coordinate,
|
||||
ref mut array_index,
|
||||
ref mut offset,
|
||||
ref mut level,
|
||||
ref mut depth_ref,
|
||||
} => {
|
||||
adjust(image);
|
||||
adjust(sampler);
|
||||
adjust(coordinate);
|
||||
operand_map.adjust_option(array_index);
|
||||
// TEST: try adjusting this with plain operand_map
|
||||
if let Some(ref mut offset) = *offset {
|
||||
self.const_expressions.adjust(offset);
|
||||
}
|
||||
self.adjust_sample_level(level, operand_map);
|
||||
operand_map.adjust_option(depth_ref);
|
||||
}
|
||||
Ex::ImageLoad {
|
||||
ref mut image,
|
||||
ref mut coordinate,
|
||||
ref mut array_index,
|
||||
ref mut sample,
|
||||
ref mut level,
|
||||
} => {
|
||||
adjust(image);
|
||||
adjust(coordinate);
|
||||
operand_map.adjust_option(array_index);
|
||||
operand_map.adjust_option(sample);
|
||||
operand_map.adjust_option(level);
|
||||
}
|
||||
Ex::ImageQuery {
|
||||
ref mut image,
|
||||
ref mut query,
|
||||
} => {
|
||||
adjust(image);
|
||||
self.adjust_image_query(query, operand_map);
|
||||
}
|
||||
Ex::Unary {
|
||||
op: _,
|
||||
ref mut expr,
|
||||
} => adjust(expr),
|
||||
Ex::Binary {
|
||||
op: _,
|
||||
ref mut left,
|
||||
ref mut right,
|
||||
} => {
|
||||
adjust(left);
|
||||
adjust(right);
|
||||
}
|
||||
Ex::Select {
|
||||
ref mut condition,
|
||||
ref mut accept,
|
||||
ref mut reject,
|
||||
} => {
|
||||
adjust(condition);
|
||||
adjust(accept);
|
||||
adjust(reject);
|
||||
}
|
||||
Ex::Derivative {
|
||||
axis: _,
|
||||
ctrl: _,
|
||||
ref mut expr,
|
||||
} => adjust(expr),
|
||||
Ex::Relational {
|
||||
fun: _,
|
||||
ref mut argument,
|
||||
} => adjust(argument),
|
||||
Ex::Math {
|
||||
fun: _,
|
||||
ref mut arg,
|
||||
ref mut arg1,
|
||||
ref mut arg2,
|
||||
ref mut arg3,
|
||||
} => {
|
||||
adjust(arg);
|
||||
operand_map.adjust_option(arg1);
|
||||
operand_map.adjust_option(arg2);
|
||||
operand_map.adjust_option(arg3);
|
||||
}
|
||||
Ex::As {
|
||||
ref mut expr,
|
||||
kind: _,
|
||||
convert: _,
|
||||
} => adjust(expr),
|
||||
Ex::AtomicResult {
|
||||
ref mut ty,
|
||||
comparison: _,
|
||||
} => self.types.adjust(ty),
|
||||
Ex::WorkGroupUniformLoadResult { ref mut ty } => self.types.adjust(ty),
|
||||
Ex::ArrayLength(ref mut expr) => adjust(expr),
|
||||
Ex::RayQueryGetIntersection {
|
||||
ref mut query,
|
||||
committed: _,
|
||||
} => adjust(query),
|
||||
}
|
||||
}
|
||||
|
||||
fn adjust_sample_level(
|
||||
&self,
|
||||
level: &mut crate::SampleLevel,
|
||||
operand_map: &HandleMap<crate::Expression>,
|
||||
) {
|
||||
let adjust = |expr: &mut Handle<crate::Expression>| operand_map.adjust(expr);
|
||||
|
||||
use crate::SampleLevel as Sl;
|
||||
match *level {
|
||||
Sl::Auto | Sl::Zero => {}
|
||||
Sl::Exact(ref mut expr) => adjust(expr),
|
||||
Sl::Bias(ref mut expr) => adjust(expr),
|
||||
Sl::Gradient {
|
||||
ref mut x,
|
||||
ref mut y,
|
||||
} => {
|
||||
adjust(x);
|
||||
adjust(y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn adjust_image_query(
|
||||
&self,
|
||||
query: &mut crate::ImageQuery,
|
||||
operand_map: &HandleMap<crate::Expression>,
|
||||
) {
|
||||
use crate::ImageQuery as Iq;
|
||||
|
||||
match *query {
|
||||
Iq::Size { ref mut level } => operand_map.adjust_option(level),
|
||||
Iq::NumLevels | Iq::NumLayers | Iq::NumSamples => {}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
use super::handle_set_map::HandleSet;
|
||||
use super::{FunctionMap, ModuleMap};
|
||||
use crate::arena::Handle;
|
||||
|
||||
pub(super) struct FunctionTracer<'a> {
|
||||
pub(super) module: &'a crate::Module,
|
||||
pub(super) function: &'a crate::Function,
|
||||
|
||||
pub(super) types_used: &'a mut HandleSet<crate::Type>,
|
||||
pub(super) constants_used: &'a mut HandleSet<crate::Constant>,
|
||||
pub(super) const_expressions_used: &'a mut HandleSet<crate::Expression>,
|
||||
|
||||
/// Function-local expressions used.
|
||||
pub(super) expressions_used: HandleSet<crate::Expression>,
|
||||
}
|
||||
|
||||
impl<'a> FunctionTracer<'a> {
|
||||
pub fn trace(&mut self) {
|
||||
for argument in self.function.arguments.iter() {
|
||||
self.trace_type(argument.ty);
|
||||
}
|
||||
|
||||
if let Some(ref result) = self.function.result {
|
||||
self.trace_type(result.ty);
|
||||
}
|
||||
|
||||
for (_, local) in self.function.local_variables.iter() {
|
||||
self.trace_type(local.ty);
|
||||
if let Some(init) = local.init {
|
||||
// TEST: try changing this to trace_expression
|
||||
self.trace_const_expression(init);
|
||||
}
|
||||
}
|
||||
|
||||
// Treat named expressions as alive, for the sake of our test suite,
|
||||
// which uses `let blah = expr;` to exercise lots of things.
|
||||
for (value, _name) in &self.function.named_expressions {
|
||||
self.trace_expression(*value);
|
||||
}
|
||||
|
||||
self.trace_block(&self.function.body);
|
||||
}
|
||||
|
||||
pub fn trace_type(&mut self, ty: Handle<crate::Type>) {
|
||||
self.as_type().trace_type(ty)
|
||||
}
|
||||
|
||||
pub fn trace_expression(&mut self, expr: Handle<crate::Expression>) {
|
||||
self.as_expression().trace_expression(expr);
|
||||
}
|
||||
|
||||
pub fn trace_const_expression(&mut self, expr: Handle<crate::Expression>) {
|
||||
self.as_expression()
|
||||
.as_const_expression()
|
||||
.trace_expression(expr);
|
||||
}
|
||||
|
||||
/*
|
||||
pub fn trace_const_expression(&mut self, const_expr: Handle<crate::Expression>) {
|
||||
self.as_expression().as_const_expression().trace_expression(const_expr);
|
||||
}
|
||||
*/
|
||||
|
||||
fn as_type(&mut self) -> super::types::TypeTracer {
|
||||
super::types::TypeTracer {
|
||||
types: &self.module.types,
|
||||
types_used: self.types_used,
|
||||
}
|
||||
}
|
||||
|
||||
fn as_expression(&mut self) -> super::expressions::ExpressionTracer {
|
||||
super::expressions::ExpressionTracer {
|
||||
types: &self.module.types,
|
||||
constants: &self.module.constants,
|
||||
expressions: &self.function.expressions,
|
||||
|
||||
types_used: self.types_used,
|
||||
constants_used: self.constants_used,
|
||||
expressions_used: &mut self.expressions_used,
|
||||
const_expressions: Some((
|
||||
&self.module.const_expressions,
|
||||
&mut self.const_expressions_used,
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FunctionMap {
|
||||
pub fn compact(
|
||||
&self,
|
||||
function: &mut crate::Function,
|
||||
module_map: &ModuleMap,
|
||||
reuse: &mut crate::NamedExpressions,
|
||||
) {
|
||||
assert!(reuse.is_empty());
|
||||
|
||||
for argument in function.arguments.iter_mut() {
|
||||
module_map.types.adjust(&mut argument.ty);
|
||||
}
|
||||
|
||||
if let Some(ref mut result) = function.result {
|
||||
module_map.types.adjust(&mut result.ty);
|
||||
}
|
||||
|
||||
for (_, local) in function.local_variables.iter_mut() {
|
||||
log::trace!("adjusting local variable {:?}", local.name);
|
||||
module_map.types.adjust(&mut local.ty);
|
||||
if let Some(ref mut init) = local.init {
|
||||
module_map.const_expressions.adjust(init);
|
||||
}
|
||||
}
|
||||
|
||||
// Drop unused expressions, reusing existing storage.
|
||||
function.expressions.retain_mut(|handle, expr| {
|
||||
if self.expressions.used(handle) {
|
||||
module_map.adjust_expression(expr, &self.expressions);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
});
|
||||
|
||||
// Adjust named expressions.
|
||||
for (mut handle, name) in function.named_expressions.drain(..) {
|
||||
self.expressions.adjust(&mut handle);
|
||||
reuse.insert(handle, name);
|
||||
}
|
||||
std::mem::swap(&mut function.named_expressions, reuse);
|
||||
assert!(reuse.is_empty());
|
||||
|
||||
// Adjust statements.
|
||||
self.adjust_block(&mut function.body);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
use crate::arena::{Arena, Handle, UniqueArena};
|
||||
|
||||
type Index = std::num::NonZeroU32;
|
||||
|
||||
/// A set of `Handle<T>` values.
|
||||
pub struct HandleSet<T> {
|
||||
/// Bound on zero-based indexes of handles stored in this set.
|
||||
len: usize,
|
||||
|
||||
/// `members[i]` is true if the handle with zero-based index `i`
|
||||
/// is a member.
|
||||
members: bit_set::BitSet,
|
||||
|
||||
/// This type is indexed by values of type `T`.
|
||||
as_keys: std::marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> HandleSet<T> {
|
||||
pub fn for_arena(arena: &impl ArenaType<T>) -> Self {
|
||||
let len = arena.len();
|
||||
Self {
|
||||
len,
|
||||
members: bit_set::BitSet::with_capacity(len),
|
||||
as_keys: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Add `handle` to the set.
|
||||
///
|
||||
/// Return `true` if the handle was not already in the set. In
|
||||
/// other words, return true if it was newly inserted.
|
||||
pub fn insert(&mut self, handle: Handle<T>) -> bool {
|
||||
// Note that, oddly, `Handle::index` does not return a 1-based
|
||||
// `Index`, but rather a zero-based `usize`.
|
||||
self.members.insert(handle.index())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ArenaType<T> {
|
||||
fn len(&self) -> usize;
|
||||
}
|
||||
|
||||
impl<T> ArenaType<T> for Arena<T> {
|
||||
fn len(&self) -> usize {
|
||||
self.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: std::hash::Hash + Eq> ArenaType<T> for UniqueArena<T> {
|
||||
fn len(&self) -> usize {
|
||||
self.len()
|
||||
}
|
||||
}
|
||||
|
||||
/// A map from old handle indices to new, compressed handle indices.
|
||||
pub struct HandleMap<T> {
|
||||
/// The indices assigned to handles in the compacted module.
|
||||
///
|
||||
/// If `new_index[i]` is `Some(n)`, then `n` is the 1-based
|
||||
/// `Index` of the compacted `Handle` corresponding to the
|
||||
/// pre-compacted `Handle` whose zero-based index is `i`. ("Clear
|
||||
/// as mud.")
|
||||
new_index: Vec<Option<Index>>,
|
||||
|
||||
/// This type is indexed by values of type `T`.
|
||||
as_keys: std::marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: 'static> HandleMap<T> {
|
||||
pub fn from_set(set: HandleSet<T>) -> Self {
|
||||
let mut next_index = Index::new(1).unwrap();
|
||||
Self {
|
||||
new_index: (0..set.len)
|
||||
.map(|zero_based_index| {
|
||||
if set.members.contains(zero_based_index) {
|
||||
// This handle will be retained in the compacted version,
|
||||
// so assign it a new index.
|
||||
let this = next_index;
|
||||
next_index = next_index.checked_add(1).unwrap();
|
||||
Some(this)
|
||||
} else {
|
||||
// This handle will be omitted in the compacted version.
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
as_keys: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return true if `old` is used in the compacted module.
|
||||
pub fn used(&self, old: Handle<T>) -> bool {
|
||||
self.new_index[old.index()].is_some()
|
||||
}
|
||||
|
||||
/// Return the counterpart to `old` in the compacted module.
|
||||
///
|
||||
/// If we thought `old` wouldn't be used in the compacted module, return
|
||||
/// `None`.
|
||||
pub fn try_adjust(&self, old: Handle<T>) -> Option<Handle<T>> {
|
||||
log::trace!(
|
||||
"adjusting {} handle [{}] -> [{:?}]",
|
||||
std::any::type_name::<T>(),
|
||||
old.index() + 1,
|
||||
self.new_index[old.index()]
|
||||
);
|
||||
// Note that `Handle::index` returns a zero-based index,
|
||||
// but `Handle::new` accepts a 1-based `Index`.
|
||||
self.new_index[old.index()].map(Handle::new)
|
||||
}
|
||||
|
||||
/// Return the counterpart to `old` in the compacted module.
|
||||
///
|
||||
/// If we thought `old` wouldn't be used in the compacted module, panic.
|
||||
pub fn adjust(&self, handle: &mut Handle<T>) {
|
||||
*handle = self.try_adjust(*handle).unwrap();
|
||||
}
|
||||
|
||||
/// Like `adjust`, but for optional handles.
|
||||
pub fn adjust_option(&self, handle: &mut Option<Handle<T>>) {
|
||||
if let Some(ref mut handle) = *handle {
|
||||
self.adjust(handle);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,286 @@
|
|||
mod expressions;
|
||||
mod functions;
|
||||
mod handle_set_map;
|
||||
mod statements;
|
||||
mod types;
|
||||
|
||||
use crate::{arena, compact::functions::FunctionTracer};
|
||||
use handle_set_map::{HandleMap, HandleSet};
|
||||
|
||||
/// Remove unused types, expressions, and constants from `module`.
|
||||
///
|
||||
/// Assuming that all globals, named constants, special types,
|
||||
/// functions and entry points in `module` are used, determine which
|
||||
/// types, constants, and expressions (both function-local and global
|
||||
/// constant expressions) are actually used, and remove the rest,
|
||||
/// adjusting all handles as necessary. The result should be a module
|
||||
/// functionally identical to the original.
|
||||
///
|
||||
/// This may be useful to apply to modules generated in the snapshot
|
||||
/// tests. Our backends often generate temporary names based on handle
|
||||
/// indices, which means that adding or removing unused arena entries
|
||||
/// can affect the output even though they have no semantic effect.
|
||||
/// Such meaningless changes add noise to snapshot diffs, making
|
||||
/// accurate patch review difficult. Compacting the modules before
|
||||
/// generating snapshots makes the output independent of unused arena
|
||||
/// entries.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If `module` has not passed validation, this may panic.
|
||||
pub fn compact(module: &mut crate::Module) {
|
||||
let mut module_tracer = ModuleTracer::new(module);
|
||||
|
||||
// We treat all globals as used by definition.
|
||||
log::trace!("tracing global variables");
|
||||
{
|
||||
for (_, global) in module.global_variables.iter() {
|
||||
log::trace!("tracing global {:?}", global.name);
|
||||
module_tracer.as_type().trace_type(global.ty);
|
||||
if let Some(init) = global.init {
|
||||
module_tracer.as_const_expression().trace_expression(init);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We treat all special types as used by definition.
|
||||
module_tracer.trace_special_types(&module.special_types);
|
||||
|
||||
// We treat all named constants as used by definition.
|
||||
for (handle, constant) in module.constants.iter() {
|
||||
if constant.name.is_some() {
|
||||
module_tracer.constants_used.insert(handle);
|
||||
module_tracer.as_type().trace_type(constant.ty);
|
||||
module_tracer
|
||||
.as_const_expression()
|
||||
.trace_expression(constant.init);
|
||||
}
|
||||
}
|
||||
|
||||
// We assume that all functions are used.
|
||||
//
|
||||
// Observe which types, constant expressions, constants, and
|
||||
// expressions each function uses, and produce maps from
|
||||
// pre-compaction to post-compaction handles.
|
||||
log::trace!("tracing functions");
|
||||
let function_maps: Vec<FunctionMap> = module
|
||||
.functions
|
||||
.iter()
|
||||
.map(|(_, f)| {
|
||||
log::trace!("tracing function {:?}", f.name);
|
||||
let mut function_tracer = module_tracer.enter_function(f);
|
||||
function_tracer.trace();
|
||||
FunctionMap::from(function_tracer)
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Similiarly, observe what each entry point actually uses.
|
||||
log::trace!("tracing entry points");
|
||||
let entry_point_maps: Vec<FunctionMap> = module
|
||||
.entry_points
|
||||
.iter()
|
||||
.map(|e| {
|
||||
log::trace!("tracing entry point {:?}", e.function.name);
|
||||
let mut used = module_tracer.enter_function(&e.function);
|
||||
used.trace();
|
||||
FunctionMap::from(used)
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Now that we know what is used and what is never touched,
|
||||
// produce maps from the `Handle`s that appear in `module` now to
|
||||
// the corresponding `Handle`s that will refer to the same items
|
||||
// in the compacted module.
|
||||
let module_map = ModuleMap::from(module_tracer);
|
||||
|
||||
// Drop unused types from the type arena.
|
||||
//
|
||||
// `FastIndexSet`s don't have an underlying Vec<T> that we can
|
||||
// steal, compact in place, and then rebuild the `FastIndexSet`
|
||||
// from. So we have to rebuild the type arena from scratch.
|
||||
log::trace!("compacting types");
|
||||
let mut new_types = arena::UniqueArena::new();
|
||||
for (old_handle, mut ty, span) in module.types.drain_all() {
|
||||
if let Some(expected_new_handle) = module_map.types.try_adjust(old_handle) {
|
||||
module_map.adjust_type(&mut ty);
|
||||
let actual_new_handle = new_types.insert(ty, span);
|
||||
assert_eq!(actual_new_handle, expected_new_handle);
|
||||
}
|
||||
}
|
||||
module.types = new_types;
|
||||
log::trace!("adjusting special types");
|
||||
module_map.adjust_special_types(&mut module.special_types);
|
||||
|
||||
// Drop unused constant expressions, reusing existing storage.
|
||||
log::trace!("adjusting constant expressions");
|
||||
module.const_expressions.retain_mut(|handle, expr| {
|
||||
if module_map.const_expressions.used(handle) {
|
||||
module_map.adjust_expression(expr, &module_map.const_expressions);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
});
|
||||
|
||||
// Drop unused constants in place, reusing existing storage.
|
||||
log::trace!("adjusting constants");
|
||||
module.constants.retain_mut(|handle, constant| {
|
||||
if module_map.constants.used(handle) {
|
||||
module_map.types.adjust(&mut constant.ty);
|
||||
module_map.const_expressions.adjust(&mut constant.init);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
});
|
||||
|
||||
// Adjust global variables' types and initializers.
|
||||
log::trace!("adjusting global variables");
|
||||
for (_, global) in module.global_variables.iter_mut() {
|
||||
log::trace!("adjusting global {:?}", global.name);
|
||||
module_map.types.adjust(&mut global.ty);
|
||||
if let Some(ref mut init) = global.init {
|
||||
module_map.const_expressions.adjust(init);
|
||||
}
|
||||
}
|
||||
|
||||
// Temporary storage to help us reuse allocations of existing
|
||||
// named expression tables.
|
||||
let mut reused_named_expressions = crate::NamedExpressions::default();
|
||||
|
||||
// Compact each function.
|
||||
for ((_, function), map) in module.functions.iter_mut().zip(function_maps.iter()) {
|
||||
log::trace!("compacting function {:?}", function.name);
|
||||
map.compact(function, &module_map, &mut reused_named_expressions);
|
||||
}
|
||||
|
||||
// Compact each entry point.
|
||||
for (entry, map) in module.entry_points.iter_mut().zip(entry_point_maps.iter()) {
|
||||
log::trace!("compacting entry point {:?}", entry.function.name);
|
||||
map.compact(
|
||||
&mut entry.function,
|
||||
&module_map,
|
||||
&mut reused_named_expressions,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
struct ModuleTracer<'module> {
|
||||
module: &'module crate::Module,
|
||||
types_used: HandleSet<crate::Type>,
|
||||
constants_used: HandleSet<crate::Constant>,
|
||||
const_expressions_used: HandleSet<crate::Expression>,
|
||||
}
|
||||
|
||||
impl<'module> ModuleTracer<'module> {
|
||||
fn new(module: &'module crate::Module) -> Self {
|
||||
Self {
|
||||
module,
|
||||
types_used: HandleSet::for_arena(&module.types),
|
||||
constants_used: HandleSet::for_arena(&module.constants),
|
||||
const_expressions_used: HandleSet::for_arena(&module.const_expressions),
|
||||
}
|
||||
}
|
||||
|
||||
fn trace_special_types(&mut self, special_types: &crate::SpecialTypes) {
|
||||
let crate::SpecialTypes {
|
||||
ref ray_desc,
|
||||
ref ray_intersection,
|
||||
ref predeclared_types,
|
||||
} = *special_types;
|
||||
|
||||
let mut type_tracer = self.as_type();
|
||||
if let Some(ray_desc) = *ray_desc {
|
||||
type_tracer.trace_type(ray_desc);
|
||||
}
|
||||
if let Some(ray_intersection) = *ray_intersection {
|
||||
type_tracer.trace_type(ray_intersection);
|
||||
}
|
||||
for (_, &handle) in predeclared_types {
|
||||
type_tracer.trace_type(handle);
|
||||
}
|
||||
}
|
||||
|
||||
fn as_type(&mut self) -> types::TypeTracer {
|
||||
types::TypeTracer {
|
||||
types: &self.module.types,
|
||||
types_used: &mut self.types_used,
|
||||
}
|
||||
}
|
||||
|
||||
fn as_const_expression(&mut self) -> expressions::ExpressionTracer {
|
||||
expressions::ExpressionTracer {
|
||||
types: &self.module.types,
|
||||
constants: &self.module.constants,
|
||||
expressions: &self.module.const_expressions,
|
||||
types_used: &mut self.types_used,
|
||||
constants_used: &mut self.constants_used,
|
||||
expressions_used: &mut self.const_expressions_used,
|
||||
const_expressions: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enter_function<'tracer>(
|
||||
&'tracer mut self,
|
||||
function: &'tracer crate::Function,
|
||||
) -> FunctionTracer<'tracer> {
|
||||
FunctionTracer {
|
||||
module: self.module,
|
||||
function,
|
||||
|
||||
types_used: &mut self.types_used,
|
||||
constants_used: &mut self.constants_used,
|
||||
const_expressions_used: &mut self.const_expressions_used,
|
||||
expressions_used: HandleSet::for_arena(&function.expressions),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ModuleMap {
|
||||
types: HandleMap<crate::Type>,
|
||||
constants: HandleMap<crate::Constant>,
|
||||
const_expressions: HandleMap<crate::Expression>,
|
||||
}
|
||||
|
||||
impl From<ModuleTracer<'_>> for ModuleMap {
|
||||
fn from(used: ModuleTracer) -> Self {
|
||||
ModuleMap {
|
||||
types: HandleMap::from_set(used.types_used),
|
||||
constants: HandleMap::from_set(used.constants_used),
|
||||
const_expressions: HandleMap::from_set(used.const_expressions_used),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ModuleMap {
|
||||
fn adjust_special_types(&self, special: &mut crate::SpecialTypes) {
|
||||
let crate::SpecialTypes {
|
||||
ref mut ray_desc,
|
||||
ref mut ray_intersection,
|
||||
ref mut predeclared_types,
|
||||
} = *special;
|
||||
|
||||
if let Some(ref mut ray_desc) = *ray_desc {
|
||||
self.types.adjust(ray_desc);
|
||||
}
|
||||
if let Some(ref mut ray_intersection) = *ray_intersection {
|
||||
self.types.adjust(ray_intersection);
|
||||
}
|
||||
|
||||
for handle in predeclared_types.values_mut() {
|
||||
self.types.adjust(handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct FunctionMap {
|
||||
expressions: HandleMap<crate::Expression>,
|
||||
}
|
||||
|
||||
impl From<FunctionTracer<'_>> for FunctionMap {
|
||||
fn from(used: FunctionTracer) -> Self {
|
||||
FunctionMap {
|
||||
expressions: HandleMap::from_set(used.expressions_used),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,302 @@
|
|||
use super::functions::FunctionTracer;
|
||||
use super::FunctionMap;
|
||||
use crate::arena::Handle;
|
||||
|
||||
impl FunctionTracer<'_> {
|
||||
pub fn trace_block(&mut self, block: &[crate::Statement]) {
|
||||
let mut worklist: Vec<&[crate::Statement]> = vec![block];
|
||||
while let Some(last) = worklist.pop() {
|
||||
for stmt in last {
|
||||
use crate::Statement as St;
|
||||
match *stmt {
|
||||
St::Emit(ref range) => {
|
||||
for expr in range.clone() {
|
||||
log::trace!("trace emitted expression {:?}", expr);
|
||||
self.trace_expression(expr);
|
||||
}
|
||||
}
|
||||
St::Block(ref block) => worklist.push(block),
|
||||
St::If {
|
||||
condition,
|
||||
ref accept,
|
||||
ref reject,
|
||||
} => {
|
||||
self.trace_expression(condition);
|
||||
worklist.push(accept);
|
||||
worklist.push(reject);
|
||||
}
|
||||
St::Switch {
|
||||
selector,
|
||||
ref cases,
|
||||
} => {
|
||||
self.trace_expression(selector);
|
||||
for case in cases {
|
||||
worklist.push(&case.body);
|
||||
}
|
||||
}
|
||||
St::Loop {
|
||||
ref body,
|
||||
ref continuing,
|
||||
break_if,
|
||||
} => {
|
||||
if let Some(break_if) = break_if {
|
||||
self.trace_expression(break_if);
|
||||
}
|
||||
worklist.push(body);
|
||||
worklist.push(continuing);
|
||||
}
|
||||
St::Return { value: Some(value) } => self.trace_expression(value),
|
||||
St::Store { pointer, value } => {
|
||||
self.trace_expression(pointer);
|
||||
self.trace_expression(value);
|
||||
}
|
||||
St::ImageStore {
|
||||
image,
|
||||
coordinate,
|
||||
array_index,
|
||||
value,
|
||||
} => {
|
||||
self.trace_expression(image);
|
||||
self.trace_expression(coordinate);
|
||||
if let Some(array_index) = array_index {
|
||||
self.trace_expression(array_index);
|
||||
}
|
||||
self.trace_expression(value);
|
||||
}
|
||||
St::Atomic {
|
||||
pointer,
|
||||
ref fun,
|
||||
value,
|
||||
result,
|
||||
} => {
|
||||
self.trace_expression(pointer);
|
||||
self.trace_atomic_function(fun);
|
||||
self.trace_expression(value);
|
||||
self.trace_expression(result);
|
||||
}
|
||||
St::WorkGroupUniformLoad { pointer, result } => {
|
||||
self.trace_expression(pointer);
|
||||
self.trace_expression(result);
|
||||
}
|
||||
St::Call {
|
||||
function: _,
|
||||
ref arguments,
|
||||
result,
|
||||
} => {
|
||||
for expr in arguments {
|
||||
self.trace_expression(*expr);
|
||||
}
|
||||
if let Some(result) = result {
|
||||
self.trace_expression(result);
|
||||
}
|
||||
}
|
||||
St::RayQuery { query, ref fun } => {
|
||||
self.trace_expression(query);
|
||||
self.trace_ray_query_function(fun);
|
||||
}
|
||||
|
||||
// Trivial statements.
|
||||
St::Break
|
||||
| St::Continue
|
||||
| St::Kill
|
||||
| St::Barrier(_)
|
||||
| St::Return { value: None } => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn trace_atomic_function(&mut self, fun: &crate::AtomicFunction) {
|
||||
use crate::AtomicFunction as Af;
|
||||
match *fun {
|
||||
Af::Exchange {
|
||||
compare: Some(expr),
|
||||
} => self.trace_expression(expr),
|
||||
Af::Exchange { compare: None }
|
||||
| Af::Add
|
||||
| Af::Subtract
|
||||
| Af::And
|
||||
| Af::ExclusiveOr
|
||||
| Af::InclusiveOr
|
||||
| Af::Min
|
||||
| Af::Max => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn trace_ray_query_function(&mut self, fun: &crate::RayQueryFunction) {
|
||||
use crate::RayQueryFunction as Qf;
|
||||
match *fun {
|
||||
Qf::Initialize {
|
||||
acceleration_structure,
|
||||
descriptor,
|
||||
} => {
|
||||
self.trace_expression(acceleration_structure);
|
||||
self.trace_expression(descriptor);
|
||||
}
|
||||
Qf::Proceed { result } => self.trace_expression(result),
|
||||
Qf::Terminate => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FunctionMap {
|
||||
pub fn adjust_block(&self, block: &mut [crate::Statement]) {
|
||||
let mut worklist: Vec<&mut [crate::Statement]> = vec![block];
|
||||
let adjust = |handle: &mut Handle<crate::Expression>| {
|
||||
self.expressions.adjust(handle);
|
||||
};
|
||||
while let Some(last) = worklist.pop() {
|
||||
for stmt in last {
|
||||
use crate::Statement as St;
|
||||
match *stmt {
|
||||
St::Emit(ref mut range) => {
|
||||
// Fortunately, compaction doesn't arbitrarily scramble
|
||||
// the expressions in the arena, but instead preserves
|
||||
// the order of the elements while squeezing out unused
|
||||
// ones. That means that a contiguous range in the
|
||||
// pre-compacted arena always maps to a contiguous range
|
||||
// in the post-compacted arena. So we just need to
|
||||
// adjust the endpoints.
|
||||
let (mut first, mut last) = range.first_and_last().unwrap();
|
||||
self.expressions.adjust(&mut first);
|
||||
self.expressions.adjust(&mut last);
|
||||
*range = crate::arena::Range::new_from_bounds(first, last);
|
||||
}
|
||||
St::Block(ref mut block) => worklist.push(block),
|
||||
St::If {
|
||||
ref mut condition,
|
||||
ref mut accept,
|
||||
ref mut reject,
|
||||
} => {
|
||||
adjust(condition);
|
||||
worklist.push(accept);
|
||||
worklist.push(reject);
|
||||
}
|
||||
St::Switch {
|
||||
ref mut selector,
|
||||
ref mut cases,
|
||||
} => {
|
||||
adjust(selector);
|
||||
for case in cases {
|
||||
worklist.push(&mut case.body);
|
||||
}
|
||||
}
|
||||
St::Loop {
|
||||
ref mut body,
|
||||
ref mut continuing,
|
||||
ref mut break_if,
|
||||
} => {
|
||||
if let Some(ref mut break_if) = *break_if {
|
||||
adjust(break_if);
|
||||
}
|
||||
worklist.push(body);
|
||||
worklist.push(continuing);
|
||||
}
|
||||
St::Return {
|
||||
value: Some(ref mut value),
|
||||
} => adjust(value),
|
||||
St::Store {
|
||||
ref mut pointer,
|
||||
ref mut value,
|
||||
} => {
|
||||
adjust(pointer);
|
||||
adjust(value);
|
||||
}
|
||||
St::ImageStore {
|
||||
ref mut image,
|
||||
ref mut coordinate,
|
||||
ref mut array_index,
|
||||
ref mut value,
|
||||
} => {
|
||||
adjust(image);
|
||||
adjust(coordinate);
|
||||
if let Some(ref mut array_index) = *array_index {
|
||||
adjust(array_index);
|
||||
}
|
||||
adjust(value);
|
||||
}
|
||||
St::Atomic {
|
||||
ref mut pointer,
|
||||
ref mut fun,
|
||||
ref mut value,
|
||||
ref mut result,
|
||||
} => {
|
||||
adjust(pointer);
|
||||
self.adjust_atomic_function(fun);
|
||||
adjust(value);
|
||||
adjust(result);
|
||||
}
|
||||
St::WorkGroupUniformLoad {
|
||||
ref mut pointer,
|
||||
ref mut result,
|
||||
} => {
|
||||
adjust(pointer);
|
||||
adjust(result);
|
||||
}
|
||||
St::Call {
|
||||
function: _,
|
||||
ref mut arguments,
|
||||
ref mut result,
|
||||
} => {
|
||||
for expr in arguments {
|
||||
adjust(expr);
|
||||
}
|
||||
if let Some(ref mut result) = *result {
|
||||
adjust(result);
|
||||
}
|
||||
}
|
||||
St::RayQuery {
|
||||
ref mut query,
|
||||
ref mut fun,
|
||||
} => {
|
||||
adjust(query);
|
||||
self.adjust_ray_query_function(fun);
|
||||
}
|
||||
|
||||
// Trivial statements.
|
||||
St::Break
|
||||
| St::Continue
|
||||
| St::Kill
|
||||
| St::Barrier(_)
|
||||
| St::Return { value: None } => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn adjust_atomic_function(&self, fun: &mut crate::AtomicFunction) {
|
||||
use crate::AtomicFunction as Af;
|
||||
match *fun {
|
||||
Af::Exchange {
|
||||
compare: Some(ref mut expr),
|
||||
} => {
|
||||
self.expressions.adjust(expr);
|
||||
}
|
||||
Af::Exchange { compare: None }
|
||||
| Af::Add
|
||||
| Af::Subtract
|
||||
| Af::And
|
||||
| Af::ExclusiveOr
|
||||
| Af::InclusiveOr
|
||||
| Af::Min
|
||||
| Af::Max => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn adjust_ray_query_function(&self, fun: &mut crate::RayQueryFunction) {
|
||||
use crate::RayQueryFunction as Qf;
|
||||
match *fun {
|
||||
Qf::Initialize {
|
||||
ref mut acceleration_structure,
|
||||
ref mut descriptor,
|
||||
} => {
|
||||
self.expressions.adjust(acceleration_structure);
|
||||
self.expressions.adjust(descriptor);
|
||||
}
|
||||
Qf::Proceed { ref mut result } => {
|
||||
self.expressions.adjust(result);
|
||||
}
|
||||
Qf::Terminate => {}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
use super::{HandleSet, ModuleMap};
|
||||
use crate::{Handle, UniqueArena};
|
||||
|
||||
pub struct TypeTracer<'a> {
|
||||
pub types: &'a UniqueArena<crate::Type>,
|
||||
pub types_used: &'a mut HandleSet<crate::Type>,
|
||||
}
|
||||
|
||||
impl<'a> TypeTracer<'a> {
|
||||
pub fn trace_type(&mut self, ty: Handle<crate::Type>) {
|
||||
let mut work_list = vec![ty];
|
||||
while let Some(ty) = work_list.pop() {
|
||||
// If we've already seen this type, no need to traverse further.
|
||||
if !self.types_used.insert(ty) {
|
||||
continue;
|
||||
}
|
||||
|
||||
use crate::TypeInner as Ti;
|
||||
match self.types[ty].inner {
|
||||
// Types that do not contain handles.
|
||||
Ti::Scalar { .. }
|
||||
| Ti::Vector { .. }
|
||||
| Ti::Matrix { .. }
|
||||
| Ti::Atomic { .. }
|
||||
| Ti::ValuePointer { .. }
|
||||
| Ti::Image { .. }
|
||||
| Ti::Sampler { .. }
|
||||
| Ti::AccelerationStructure
|
||||
| Ti::RayQuery => {}
|
||||
|
||||
// Types that do contain handles.
|
||||
Ti::Pointer { base, space: _ } => work_list.push(base),
|
||||
Ti::Array {
|
||||
base,
|
||||
size: _,
|
||||
stride: _,
|
||||
} => work_list.push(base),
|
||||
Ti::Struct {
|
||||
ref members,
|
||||
span: _,
|
||||
} => {
|
||||
work_list.extend(members.iter().map(|m| m.ty));
|
||||
}
|
||||
Ti::BindingArray { base, size: _ } => work_list.push(base),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ModuleMap {
|
||||
pub fn adjust_type(&self, ty: &mut crate::Type) {
|
||||
let adjust = |ty: &mut Handle<crate::Type>| self.types.adjust(ty);
|
||||
|
||||
use crate::TypeInner as Ti;
|
||||
match ty.inner {
|
||||
// Types that do not contain handles.
|
||||
Ti::Scalar { .. }
|
||||
| Ti::Vector { .. }
|
||||
| Ti::Matrix { .. }
|
||||
| Ti::Atomic { .. }
|
||||
| Ti::ValuePointer { .. }
|
||||
| Ti::Image { .. }
|
||||
| Ti::Sampler { .. }
|
||||
| Ti::AccelerationStructure
|
||||
| Ti::RayQuery => {}
|
||||
|
||||
// Types that do contain handles.
|
||||
Ti::Pointer {
|
||||
ref mut base,
|
||||
space: _,
|
||||
} => adjust(base),
|
||||
Ti::Array {
|
||||
ref mut base,
|
||||
size: _,
|
||||
stride: _,
|
||||
} => adjust(base),
|
||||
Ti::Struct {
|
||||
ref mut members,
|
||||
span: _,
|
||||
} => {
|
||||
for member in members {
|
||||
self.types.adjust(&mut member.ty);
|
||||
}
|
||||
}
|
||||
Ti::BindingArray {
|
||||
ref mut base,
|
||||
size: _,
|
||||
} => {
|
||||
adjust(base);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -401,6 +401,7 @@ fn map_image_format(word: &str) -> Option<crate::StorageFormat> {
|
|||
"r32f" => Sf::R32Float,
|
||||
"r16f" => Sf::R16Float,
|
||||
"rgba16" => Sf::Rgba16Unorm,
|
||||
"rgb10_a2ui" => Sf::Rgb10a2Uint,
|
||||
"rgb10_a2" => Sf::Rgb10a2Unorm,
|
||||
"rgba8" => Sf::Rgba8Unorm,
|
||||
"rg16" => Sf::Rg16Unorm,
|
||||
|
|
|
@ -105,7 +105,8 @@ pub(super) fn map_image_format(word: spirv::Word) -> Result<crate::StorageFormat
|
|||
Some(spirv::ImageFormat::Rgba8Snorm) => Ok(crate::StorageFormat::Rgba8Snorm),
|
||||
Some(spirv::ImageFormat::Rgba8ui) => Ok(crate::StorageFormat::Rgba8Uint),
|
||||
Some(spirv::ImageFormat::Rgba8i) => Ok(crate::StorageFormat::Rgba8Sint),
|
||||
Some(spirv::ImageFormat::Rgb10a2ui) => Ok(crate::StorageFormat::Rgb10a2Unorm),
|
||||
Some(spirv::ImageFormat::Rgb10a2ui) => Ok(crate::StorageFormat::Rgb10a2Uint),
|
||||
Some(spirv::ImageFormat::Rgb10A2) => Ok(crate::StorageFormat::Rgb10a2Unorm),
|
||||
Some(spirv::ImageFormat::R11fG11fB10f) => Ok(crate::StorageFormat::Rg11b10Float),
|
||||
Some(spirv::ImageFormat::Rg32ui) => Ok(crate::StorageFormat::Rg32Uint),
|
||||
Some(spirv::ImageFormat::Rg32i) => Ok(crate::StorageFormat::Rg32Sint),
|
||||
|
|
|
@ -40,7 +40,7 @@ use function::*;
|
|||
use crate::{
|
||||
arena::{Arena, Handle, UniqueArena},
|
||||
proc::{Alignment, Layouter},
|
||||
FastHashMap, FastHashSet,
|
||||
FastHashMap, FastHashSet, FastIndexMap,
|
||||
};
|
||||
|
||||
use num_traits::cast::FromPrimitive;
|
||||
|
@ -596,11 +596,7 @@ pub struct Frontend<I> {
|
|||
/// use that target block id.
|
||||
///
|
||||
/// Used to preserve allocations between instruction parsing.
|
||||
switch_cases: indexmap::IndexMap<
|
||||
spirv::Word,
|
||||
(BodyIndex, Vec<i32>),
|
||||
std::hash::BuildHasherDefault<rustc_hash::FxHasher>,
|
||||
>,
|
||||
switch_cases: FastIndexMap<spirv::Word, (BodyIndex, Vec<i32>)>,
|
||||
|
||||
/// Tracks access to gl_PerVertex's builtins, it is used to cull unused builtins since initializing those can
|
||||
/// affect performance and the mere presence of some of these builtins might cause backends to error since they
|
||||
|
@ -641,7 +637,7 @@ impl<I: Iterator<Item = u32>> Frontend<I> {
|
|||
dummy_functions: Arena::new(),
|
||||
function_call_graph: GraphMap::new(),
|
||||
options: options.clone(),
|
||||
switch_cases: indexmap::IndexMap::default(),
|
||||
switch_cases: FastIndexMap::default(),
|
||||
gl_per_vertex_builtin_access: FastHashSet::default(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,8 +6,7 @@ use crate::front::wgsl::parse::number::Number;
|
|||
use crate::front::wgsl::parse::{ast, conv};
|
||||
use crate::front::{Emitter, Typifier};
|
||||
use crate::proc::{ensure_block_returns, Alignment, Layouter, ResolveContext, TypeResolution};
|
||||
use crate::{Arena, FastHashMap, Handle, Span};
|
||||
use indexmap::IndexMap;
|
||||
use crate::{Arena, FastHashMap, FastIndexMap, Handle, Span};
|
||||
|
||||
mod construction;
|
||||
|
||||
|
@ -79,10 +78,17 @@ pub struct StatementContext<'source, 'temp, 'out> {
|
|||
/// `Handle`s we have built for them, owned by `Lowerer::lower`.
|
||||
globals: &'temp mut FastHashMap<&'source str, LoweredGlobalDecl>,
|
||||
|
||||
/// A map from `ast::Local` handles to the Naga expressions we've built for them.
|
||||
/// A map from each `ast::Local` handle to the Naga expression
|
||||
/// we've built for it:
|
||||
///
|
||||
/// The Naga expressions are either [`LocalVariable`] or
|
||||
/// [`FunctionArgument`] expressions.
|
||||
/// - WGSL function arguments become Naga [`FunctionArgument`] expressions.
|
||||
///
|
||||
/// - WGSL `var` declarations become Naga [`LocalVariable`] expressions.
|
||||
///
|
||||
/// - WGSL `let` declararations become arbitrary Naga expressions.
|
||||
///
|
||||
/// This always borrows the `local_table` local variable in
|
||||
/// [`Lowerer::function`].
|
||||
///
|
||||
/// [`LocalVariable`]: crate::Expression::LocalVariable
|
||||
/// [`FunctionArgument`]: crate::Expression::FunctionArgument
|
||||
|
@ -94,7 +100,7 @@ pub struct StatementContext<'source, 'temp, 'out> {
|
|||
naga_expressions: &'out mut Arena<crate::Expression>,
|
||||
/// Stores the names of expressions that are assigned in `let` statement
|
||||
/// Also stores the spans of the names, for use in errors.
|
||||
named_expressions: &'out mut IndexMap<Handle<crate::Expression>, (String, Span)>,
|
||||
named_expressions: &'out mut FastIndexMap<Handle<crate::Expression>, (String, Span)>,
|
||||
arguments: &'out [crate::FunctionArgument],
|
||||
module: &'out mut crate::Module,
|
||||
}
|
||||
|
@ -167,7 +173,11 @@ impl<'a, 'temp> StatementContext<'a, 'temp, '_> {
|
|||
}
|
||||
|
||||
pub struct RuntimeExpressionContext<'temp, 'out> {
|
||||
local_table: &'temp mut FastHashMap<Handle<ast::Local>, TypedExpression>,
|
||||
/// 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>, TypedExpression>,
|
||||
|
||||
naga_expressions: &'out mut Arena<crate::Expression>,
|
||||
local_vars: &'out Arena<crate::LocalVariable>,
|
||||
|
@ -904,7 +914,7 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
|
|||
let mut local_table = FastHashMap::default();
|
||||
let mut local_variables = Arena::new();
|
||||
let mut expressions = Arena::new();
|
||||
let mut named_expressions = IndexMap::default();
|
||||
let mut named_expressions = FastIndexMap::default();
|
||||
|
||||
let arguments = f
|
||||
.arguments
|
||||
|
|
|
@ -71,6 +71,7 @@ impl crate::StorageFormat {
|
|||
Sf::Rgba8Snorm => "rgba8snorm",
|
||||
Sf::Rgba8Uint => "rgba8uint",
|
||||
Sf::Rgba8Sint => "rgba8sint",
|
||||
Sf::Rgb10a2Uint => "rgb10a2uint",
|
||||
Sf::Rgb10a2Unorm => "rgb10a2unorm",
|
||||
Sf::Rg11b10Float => "rg11b10float",
|
||||
Sf::Rg32Uint => "rg32uint",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::front::wgsl::parse::number::Number;
|
||||
use crate::{Arena, FastHashSet, Handle, Span};
|
||||
use crate::{Arena, FastIndexSet, Handle, Span};
|
||||
use std::hash::Hash;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
|
@ -73,7 +73,7 @@ pub struct GlobalDecl<'a> {
|
|||
|
||||
/// Names of all module-scope or predeclared objects this
|
||||
/// declaration uses.
|
||||
pub dependencies: FastHashSet<Dependency<'a>>,
|
||||
pub dependencies: FastIndexSet<Dependency<'a>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
@ -84,6 +84,7 @@ pub fn map_storage_format(word: &str, span: Span) -> Result<crate::StorageFormat
|
|||
"rgba8snorm" => Sf::Rgba8Snorm,
|
||||
"rgba8uint" => Sf::Rgba8Uint,
|
||||
"rgba8sint" => Sf::Rgba8Sint,
|
||||
"rgb10a2uint" => Sf::Rgb10a2Uint,
|
||||
"rgb10a2unorm" => Sf::Rgb10a2Unorm,
|
||||
"rg11b10float" => Sf::Rg11b10Float,
|
||||
"rg32uint" => Sf::Rg32Uint,
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::front::wgsl::error::{Error, ExpectedToken};
|
|||
use crate::front::wgsl::parse::lexer::{Lexer, Token};
|
||||
use crate::front::wgsl::parse::number::Number;
|
||||
use crate::front::SymbolTable;
|
||||
use crate::{Arena, FastHashSet, Handle, ShaderStage, Span};
|
||||
use crate::{Arena, FastIndexSet, Handle, ShaderStage, Span};
|
||||
|
||||
pub mod ast;
|
||||
pub mod conv;
|
||||
|
@ -51,7 +51,7 @@ struct ExpressionContext<'input, 'temp, 'out> {
|
|||
///
|
||||
/// [`GlobalDecl`]: ast::GlobalDecl
|
||||
/// [`dependencies`]: ast::GlobalDecl::dependencies
|
||||
unresolved: &'out mut FastHashSet<ast::Dependency<'input>>,
|
||||
unresolved: &'out mut FastIndexSet<ast::Dependency<'input>>,
|
||||
}
|
||||
|
||||
impl<'a> ExpressionContext<'a, '_, '_> {
|
||||
|
@ -2076,7 +2076,7 @@ impl Parser {
|
|||
&mut self,
|
||||
lexer: &mut Lexer<'a>,
|
||||
out: &mut ast::TranslationUnit<'a>,
|
||||
dependencies: &mut FastHashSet<ast::Dependency<'a>>,
|
||||
dependencies: &mut FastIndexSet<ast::Dependency<'a>>,
|
||||
) -> Result<ast::Function<'a>, Error<'a>> {
|
||||
self.push_rule_span(Rule::FunctionDecl, lexer);
|
||||
// read function name
|
||||
|
@ -2238,7 +2238,7 @@ impl Parser {
|
|||
(None, None) => {}
|
||||
}
|
||||
|
||||
let mut dependencies = FastHashSet::default();
|
||||
let mut dependencies = FastIndexSet::default();
|
||||
let mut ctx = ExpressionContext {
|
||||
expressions: &mut out.expressions,
|
||||
local_table: &mut SymbolTable::default(),
|
||||
|
|
|
@ -279,6 +279,8 @@ An override expression can be evaluated at pipeline creation time.
|
|||
mod arena;
|
||||
pub mod back;
|
||||
mod block;
|
||||
#[cfg(feature = "compact")]
|
||||
pub mod compact;
|
||||
pub mod front;
|
||||
pub mod keywords;
|
||||
pub mod proc;
|
||||
|
@ -308,12 +310,13 @@ pub type FastHashSet<K> = rustc_hash::FxHashSet<K>;
|
|||
pub type FastIndexSet<K> =
|
||||
indexmap::IndexSet<K, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>;
|
||||
|
||||
/// Insertion-order-preserving hash map (`IndexMap<K, V>`), but with the same
|
||||
/// hasher as `FastHashMap<K, V>` (faster but not resilient to DoS attacks).
|
||||
pub type FastIndexMap<K, V> =
|
||||
indexmap::IndexMap<K, V, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>;
|
||||
|
||||
/// Map of expressions that have associated variable names
|
||||
pub(crate) type NamedExpressions = indexmap::IndexMap<
|
||||
Handle<Expression>,
|
||||
String,
|
||||
std::hash::BuildHasherDefault<rustc_hash::FxHasher>,
|
||||
>;
|
||||
pub(crate) type NamedExpressions = FastIndexMap<Handle<Expression>, String>;
|
||||
|
||||
/// Early fragment tests.
|
||||
///
|
||||
|
@ -598,6 +601,7 @@ pub enum StorageFormat {
|
|||
Rgba8Sint,
|
||||
|
||||
// Packed 32-bit formats
|
||||
Rgb10a2Uint,
|
||||
Rgb10a2Unorm,
|
||||
Rg11b10Float,
|
||||
|
||||
|
@ -1993,7 +1997,7 @@ pub struct SpecialTypes {
|
|||
///
|
||||
/// Call [`Module::generate_predeclared_type`] to populate this if
|
||||
/// needed and return the handle.
|
||||
pub predeclared_types: indexmap::IndexMap<PredeclaredType, Handle<Type>>,
|
||||
pub predeclared_types: FastIndexMap<PredeclaredType, Handle<Type>>,
|
||||
}
|
||||
|
||||
/// Shader module.
|
||||
|
|
|
@ -39,6 +39,7 @@ impl From<super::StorageFormat> for super::ScalarKind {
|
|||
Sf::Rgba8Snorm => Sk::Float,
|
||||
Sf::Rgba8Uint => Sk::Uint,
|
||||
Sf::Rgba8Sint => Sk::Sint,
|
||||
Sf::Rgb10a2Uint => Sk::Uint,
|
||||
Sf::Rgb10a2Unorm => Sk::Float,
|
||||
Sf::Rg11b10Float => Sk::Float,
|
||||
Sf::Rg32Uint => Sk::Uint,
|
||||
|
|
|
@ -36,6 +36,7 @@ impl Namer {
|
|||
/// - Drop leading digits.
|
||||
/// - Retain only alphanumeric and `_` characters.
|
||||
/// - Avoid prefixes in [`Namer::reserved_prefixes`].
|
||||
/// - Replace consecutive `_` characters with a single `_` character.
|
||||
///
|
||||
/// The return value is a valid identifier prefix in all of Naga's output languages,
|
||||
/// and it never ends with a `SEPARATOR` character.
|
||||
|
@ -46,6 +47,7 @@ impl Namer {
|
|||
.trim_end_matches(SEPARATOR);
|
||||
|
||||
let base = if !string.is_empty()
|
||||
&& !string.contains("__")
|
||||
&& string
|
||||
.chars()
|
||||
.all(|c: char| c.is_ascii_alphanumeric() || c == '_')
|
||||
|
@ -55,7 +57,13 @@ impl Namer {
|
|||
let mut filtered = string
|
||||
.chars()
|
||||
.filter(|&c| c.is_ascii_alphanumeric() || c == '_')
|
||||
.collect::<String>();
|
||||
.fold(String::new(), |mut s, c| {
|
||||
if s.ends_with('_') && c == '_' {
|
||||
return s;
|
||||
}
|
||||
s.push(c);
|
||||
s
|
||||
});
|
||||
let stripped_len = filtered.trim_end_matches(SEPARATOR).len();
|
||||
filtered.truncate(stripped_len);
|
||||
if filtered.is_empty() {
|
||||
|
@ -268,4 +276,6 @@ fn test() {
|
|||
assert_eq!(namer.call("x"), "x");
|
||||
assert_eq!(namer.call("x"), "x_1");
|
||||
assert_eq!(namer.call("x1"), "x1_");
|
||||
assert_eq!(namer.call("__x"), "_x");
|
||||
assert_eq!(namer.call("1___x"), "_x_1");
|
||||
}
|
||||
|
|
|
@ -16,6 +16,10 @@ use std::ops;
|
|||
|
||||
pub type NonUniformResult = Option<Handle<crate::Expression>>;
|
||||
|
||||
// Remove this once we update our uniformity analysis and
|
||||
// add support for the `derivative_uniformity` diagnostic
|
||||
const DISABLE_UNIFORMITY_REQ_FOR_FRAGMENT_STAGE: bool = true;
|
||||
|
||||
bitflags::bitflags! {
|
||||
/// Kinds of expressions that require uniform control flow.
|
||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
|
||||
|
@ -23,8 +27,8 @@ bitflags::bitflags! {
|
|||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub struct UniformityRequirements: u8 {
|
||||
const WORK_GROUP_BARRIER = 0x1;
|
||||
const DERIVATIVE = 0x2;
|
||||
const IMPLICIT_LEVEL = 0x4;
|
||||
const DERIVATIVE = if DISABLE_UNIFORMITY_REQ_FOR_FRAGMENT_STAGE { 0 } else { 0x2 };
|
||||
const IMPLICIT_LEVEL = if DISABLE_UNIFORMITY_REQ_FOR_FRAGMENT_STAGE { 0 } else { 0x4 };
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1185,21 +1189,28 @@ fn uniform_control_flow() {
|
|||
.into(),
|
||||
reject: crate::Block::new(),
|
||||
};
|
||||
assert_eq!(
|
||||
info.process_block(
|
||||
{
|
||||
let block_info = info.process_block(
|
||||
&vec![stmt_emit2, stmt_if_non_uniform].into(),
|
||||
&[],
|
||||
None,
|
||||
&expressions
|
||||
),
|
||||
Err(FunctionError::NonUniformControlFlow(
|
||||
UniformityRequirements::DERIVATIVE,
|
||||
derivative_expr,
|
||||
UniformityDisruptor::Expression(non_uniform_global_expr)
|
||||
)
|
||||
.with_span()),
|
||||
);
|
||||
assert_eq!(info[derivative_expr].ref_count, 1);
|
||||
&expressions,
|
||||
);
|
||||
if DISABLE_UNIFORMITY_REQ_FOR_FRAGMENT_STAGE {
|
||||
assert_eq!(info[derivative_expr].ref_count, 2);
|
||||
} else {
|
||||
assert_eq!(
|
||||
block_info,
|
||||
Err(FunctionError::NonUniformControlFlow(
|
||||
UniformityRequirements::DERIVATIVE,
|
||||
derivative_expr,
|
||||
UniformityDisruptor::Expression(non_uniform_global_expr)
|
||||
)
|
||||
.with_span()),
|
||||
);
|
||||
assert_eq!(info[derivative_expr].ref_count, 1);
|
||||
}
|
||||
}
|
||||
assert_eq!(info[non_uniform_global], GlobalUse::READ);
|
||||
|
||||
let stmt_emit3 = S::Emit(emit_range_globals);
|
||||
|
|
|
@ -492,7 +492,7 @@ impl super::Validator {
|
|||
} => {}
|
||||
_ => return Err(ExpressionError::InvalidSampleLevelBiasType(expr)),
|
||||
}
|
||||
ShaderStages::all()
|
||||
ShaderStages::FRAGMENT
|
||||
}
|
||||
crate::SampleLevel::Gradient { x, y } => {
|
||||
match resolver[x] {
|
||||
|
|
|
@ -33,6 +33,8 @@ pub enum GlobalVariableError {
|
|||
),
|
||||
#[error("Initializer doesn't match the variable type")]
|
||||
InitializerType,
|
||||
#[error("Initializer can't be used with address space {0:?}")]
|
||||
InitializerNotAllowed(crate::AddressSpace),
|
||||
#[error("Storage address space doesn't support write-only access")]
|
||||
StorageAddressSpaceWriteOnlyNotSupported,
|
||||
}
|
||||
|
@ -90,6 +92,8 @@ pub enum EntryPointError {
|
|||
ForbiddenStageOperations,
|
||||
#[error("Global variable {0:?} is used incorrectly as {1:?}")]
|
||||
InvalidGlobalUsage(Handle<crate::GlobalVariable>, GlobalUse),
|
||||
#[error("More than 1 push constant variable is used")]
|
||||
MoreThanOnePushConstantUsed,
|
||||
#[error("Bindings for {0:?} conflict with other resource")]
|
||||
BindingCollision(Handle<crate::GlobalVariable>),
|
||||
#[error("Argument {0} varying error")]
|
||||
|
@ -570,6 +574,13 @@ impl super::Validator {
|
|||
}
|
||||
|
||||
if let Some(init) = var.init {
|
||||
match var.space {
|
||||
crate::AddressSpace::Private | crate::AddressSpace::Function => {}
|
||||
_ => {
|
||||
return Err(GlobalVariableError::InitializerNotAllowed(var.space));
|
||||
}
|
||||
}
|
||||
|
||||
let decl_ty = &gctx.types[var.ty].inner;
|
||||
let init_ty = mod_info[init].inner_with(gctx.types);
|
||||
if !decl_ty.equivalent(init_ty, gctx.types) {
|
||||
|
@ -701,6 +712,23 @@ impl super::Validator {
|
|||
bg.clear();
|
||||
}
|
||||
|
||||
#[cfg(feature = "validate")]
|
||||
{
|
||||
let used_push_constants = module
|
||||
.global_variables
|
||||
.iter()
|
||||
.filter(|&(_, var)| var.space == crate::AddressSpace::PushConstant)
|
||||
.map(|(handle, _)| handle)
|
||||
.filter(|&handle| !info[handle].is_empty());
|
||||
// Check if there is more than one push constant, and error if so.
|
||||
// Use a loop for when returning multiple errors is supported.
|
||||
#[allow(clippy::never_loop)]
|
||||
for handle in used_push_constants.skip(1) {
|
||||
return Err(EntryPointError::MoreThanOnePushConstantUsed
|
||||
.with_span_handle(handle, &module.global_variables));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "validate")]
|
||||
for (var_handle, var) in module.global_variables.iter() {
|
||||
let usage = info[var_handle];
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"34e400c82ab56ff7ed3b3e7fcd3d96246d68d6a246c7f12b3403465af1006772","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","src/binding_model.rs":"3322f03854b92abeb4aeb65dda4ef776094713bce1277047fe85be73a9bc7b4e","src/command/bind.rs":"c243a4448b87e9b7274b10873b7091b385413ec0a4ea93cccd6d612214ec9abb","src/command/bundle.rs":"b26eb6cb877a19d203e9d2b8ac3b10e81f6a94b8b68617eac97a3b861cbe102b","src/command/clear.rs":"bf78a5eab40f67343054dc982c51f45caab36fb5bddaf065b7a4c1b7a0ada803","src/command/compute.rs":"08dc942a650315f8f768c3e7632c35ceb385e131e83517e91e3144aa8e53b0dc","src/command/draw.rs":"92facdd0e3fd553af590ecbc0de3491f212e237ea66494ff99f67dbf090d10df","src/command/memory_init.rs":"b50d3d20dbf659052f19da2e79469ba6435e06370f19d6ef45e1b1128d9900b7","src/command/mod.rs":"2d3a4ed71cb865918aec2a60449f785d11a5e8bce188c20bbbaae5d25f6d792e","src/command/query.rs":"d39e1b8cb6a054fd31333a916da5d79a6671a724212c90c490c13e55043a1685","src/command/render.rs":"66f4764771b4c5847931b10da270c227df6446ebc65eaa187f5f7764161482d5","src/command/transfer.rs":"2b6f266ba1155ab42bed23b28abffc1008ce26d60b656f56012b896e63daa111","src/conv.rs":"da95b36b7680ae74ebf810ad8f1decf01bd3eeaff44b3c5af1d4b3c3f0e2059a","src/device/global.rs":"714b06c2c51f7f009e111ca5d07712d3ca2f377c04b5e30e3b551f584c3a1a60","src/device/life.rs":"4afecaf3602e23a4d8c795c29b9e5e148866e728b008884d55f658de29af4fe9","src/device/mod.rs":"df2336f19ff74e7339c02a579d970dbecbee88cbc315f8f35fb355888302fe5a","src/device/queue.rs":"c87ac5e748fc80563dab27f05434612580f89092904d7bcf0550f0be8e68218f","src/device/resource.rs":"e99ed822889179dbccb5ce77e3fe480505298c4bcb02da8b70a527744bb6e22f","src/device/trace.rs":"21408dfd2c99e3ce36a77d08ba86cf52f32bb376ed82690bbbf74937bfd42cbe","src/error.rs":"ca37282283985e2b7d184b2ab7ca6f53f726432d920f8d8477bfff6fab9b34e2","src/global.rs":"cf551de97c3eb5acd0c2710da09ebd92cc863ad0bb0f53c0fd4911bf8cd3ad97","src/hal_api.rs":"92a2f0cb80f192693530ed61048919bbad446742c2370bf0944c44b1c5df8362","src/hub.rs":"48ccada54672a88169c23975ddc3758cd32ed5de577c55ca4f665d0ed17d3233","src/id.rs":"f6245d024586c7fe63ded13b3cb926b940c191bbee56aedc655e8cef74bdd66b","src/identity.rs":"3ce6a3b57c7c4fc0808d13cd342d928c214f32368e45c79d8e2bbf8df887f97f","src/init_tracker/buffer.rs":"a0ebf54a1e6d269c7b4aa0ac7bb8b04fd2cea3221a1d058ff33cb683b2aea3e9","src/init_tracker/mod.rs":"0867f79f83555390d0982d1dc6dcf0d4340e10cb89aa633d3c3ecc45deb3c78c","src/init_tracker/texture.rs":"37b6584aaca11c407d91f77002dcbb48d8a4876e27edd1b71b7929ef966f901d","src/instance.rs":"4a515e6c6895107a9ab8ceffad25a9ced03f7c40a198315dabd7c326c8a21d64","src/lib.rs":"27ff8dd787d41cf412e90d0c4674aa70db59e608f9eb3be485c0bd18e9f13369","src/pipeline.rs":"212d469bc1a2256871f64b3f666f05995a92ce39391c32de3856ef2e11c08e16","src/present.rs":"e92aab52a020ae0ee63a25bf5cb3174cdce09792493e2d5e0644c8861436e805","src/registry.rs":"4098413de7f48e9ff15d0246793be47a0d54c95b4c8594baf9fafd222a90ba84","src/resource.rs":"7d1d841dd185a1a857814cab424a8b892aa8731dddf3373ea9436fa619d655b7","src/storage.rs":"bc70689ba299e9b4d9f4992c4d3f4dd36b1d8e71327595094981fdfd624f811a","src/track/buffer.rs":"dd6f632c6f31b15807148d705c516a8a1a8d72d02b137dd3b9d7c939447917cb","src/track/metadata.rs":"a80bd086ce825f7484ce6318a586c482d06fea0efc9c76bfa0124e480cc8b75e","src/track/mod.rs":"42b791d9a41eb6e62f6d79cae7abb5ab523eeb9e6030b0f95bbb0e26d56ad0ec","src/track/range.rs":"5bbfed6e103b3234d9de8e42057022da6d628c2cc1db6bb51b88f87f2d8adf8b","src/track/stateless.rs":"1d786b5e9558672243ba7d913736561065ef2bd5c6105c935e982486d10841f0","src/track/texture.rs":"7d60dc81ba7f7e2c2819525b90e6e6c7760cb0920e36aeefe98e76cedd49d26e","src/validation.rs":"fa84594ad2804684d298adf540b07723dd744bb5d6b19f1e85e00cbe86337f54"},"package":null}
|
||||
{"files":{"Cargo.toml":"f3fb91bc5168505f7cfa214f6512f80c2045836165790d882da31d5c31ab45de","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","src/binding_model.rs":"f6d9b170a9328751b3109c81d6f1b555a6db1410f1b7e67c59cc596a1fd1d293","src/command/bind.rs":"67b8431a32f403e358b9c1593e6e0d64519f5f0b699059e6ea5374800d5c23d9","src/command/bundle.rs":"b26eb6cb877a19d203e9d2b8ac3b10e81f6a94b8b68617eac97a3b861cbe102b","src/command/clear.rs":"bf78a5eab40f67343054dc982c51f45caab36fb5bddaf065b7a4c1b7a0ada803","src/command/compute.rs":"08dc942a650315f8f768c3e7632c35ceb385e131e83517e91e3144aa8e53b0dc","src/command/draw.rs":"92facdd0e3fd553af590ecbc0de3491f212e237ea66494ff99f67dbf090d10df","src/command/memory_init.rs":"b50d3d20dbf659052f19da2e79469ba6435e06370f19d6ef45e1b1128d9900b7","src/command/mod.rs":"2d3a4ed71cb865918aec2a60449f785d11a5e8bce188c20bbbaae5d25f6d792e","src/command/query.rs":"d39e1b8cb6a054fd31333a916da5d79a6671a724212c90c490c13e55043a1685","src/command/render.rs":"0f8983c27484d5fd4cfcce4d48770e0f878db0e9cf607cf8e28ceba7dc202b95","src/command/transfer.rs":"2b6f266ba1155ab42bed23b28abffc1008ce26d60b656f56012b896e63daa111","src/conv.rs":"da95b36b7680ae74ebf810ad8f1decf01bd3eeaff44b3c5af1d4b3c3f0e2059a","src/device/global.rs":"d89d50d2d1a6c5440fbeb3753ba10b65a86e213ac537989f8fbc49582bd68893","src/device/life.rs":"9ac0aab46de65fd2b493f3ee2c3527e37eaad9dbde1583752958eace71423cef","src/device/mod.rs":"ea7cb19551dcedd010d4c27479f037a34451563d717f6273fe9e3ef29751ff11","src/device/queue.rs":"0cf8b91791d78fb8fa87df1b728b335eeab8511f8f4f9628a9fb90262f33a12d","src/device/resource.rs":"3862067de696bfd9ff2f9ba162835c39e51121e959ea71739e39684edcb16de2","src/device/trace.rs":"21408dfd2c99e3ce36a77d08ba86cf52f32bb376ed82690bbbf74937bfd42cbe","src/error.rs":"ca37282283985e2b7d184b2ab7ca6f53f726432d920f8d8477bfff6fab9b34e2","src/global.rs":"cf551de97c3eb5acd0c2710da09ebd92cc863ad0bb0f53c0fd4911bf8cd3ad97","src/hal_api.rs":"92a2f0cb80f192693530ed61048919bbad446742c2370bf0944c44b1c5df8362","src/hub.rs":"bf10b7c35849bbe63c2541670a56b625ac55370f2cefdf927cec1a0d2e0c64ff","src/id.rs":"f6245d024586c7fe63ded13b3cb926b940c191bbee56aedc655e8cef74bdd66b","src/identity.rs":"3ce6a3b57c7c4fc0808d13cd342d928c214f32368e45c79d8e2bbf8df887f97f","src/init_tracker/buffer.rs":"a0ebf54a1e6d269c7b4aa0ac7bb8b04fd2cea3221a1d058ff33cb683b2aea3e9","src/init_tracker/mod.rs":"0867f79f83555390d0982d1dc6dcf0d4340e10cb89aa633d3c3ecc45deb3c78c","src/init_tracker/texture.rs":"37b6584aaca11c407d91f77002dcbb48d8a4876e27edd1b71b7929ef966f901d","src/instance.rs":"4a515e6c6895107a9ab8ceffad25a9ced03f7c40a198315dabd7c326c8a21d64","src/lib.rs":"27ff8dd787d41cf412e90d0c4674aa70db59e608f9eb3be485c0bd18e9f13369","src/pipeline.rs":"212d469bc1a2256871f64b3f666f05995a92ce39391c32de3856ef2e11c08e16","src/present.rs":"e92aab52a020ae0ee63a25bf5cb3174cdce09792493e2d5e0644c8861436e805","src/registry.rs":"4098413de7f48e9ff15d0246793be47a0d54c95b4c8594baf9fafd222a90ba84","src/resource.rs":"7d1d841dd185a1a857814cab424a8b892aa8731dddf3373ea9436fa619d655b7","src/storage.rs":"bc70689ba299e9b4d9f4992c4d3f4dd36b1d8e71327595094981fdfd624f811a","src/track/buffer.rs":"dd6f632c6f31b15807148d705c516a8a1a8d72d02b137dd3b9d7c939447917cb","src/track/metadata.rs":"a80bd086ce825f7484ce6318a586c482d06fea0efc9c76bfa0124e480cc8b75e","src/track/mod.rs":"42b791d9a41eb6e62f6d79cae7abb5ab523eeb9e6030b0f95bbb0e26d56ad0ec","src/track/range.rs":"5bbfed6e103b3234d9de8e42057022da6d628c2cc1db6bb51b88f87f2d8adf8b","src/track/stateless.rs":"1d786b5e9558672243ba7d913736561065ef2bd5c6105c935e982486d10841f0","src/track/texture.rs":"7d60dc81ba7f7e2c2819525b90e6e6c7760cb0920e36aeefe98e76cedd49d26e","src/validation.rs":"e01e2504cc55bb360dd2294735d516b0ba024605b10d69a8f1fba527f4b4625d"},"package":null}
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
[package]
|
||||
edition = "2021"
|
||||
rust-version = "1.65"
|
||||
name = "wgpu-core"
|
||||
version = "0.17.0"
|
||||
authors = ["wgpu developers"]
|
||||
|
@ -55,7 +56,7 @@ package = "wgpu-hal"
|
|||
[dependencies.naga]
|
||||
version = "0.13.0"
|
||||
git = "https://github.com/gfx-rs/naga"
|
||||
rev = "df8107b7"
|
||||
rev = "6668d0694cc51ee66c71c2ca3a1ab1081956299b"
|
||||
features = [
|
||||
"clone",
|
||||
"span",
|
||||
|
@ -85,7 +86,6 @@ path = "../wgpu-types"
|
|||
package = "wgpu-types"
|
||||
|
||||
[features]
|
||||
angle = ["hal/gles"]
|
||||
default = ["link"]
|
||||
dx11 = ["hal/dx11"]
|
||||
dx12 = ["hal/dx12"]
|
||||
|
|
|
@ -446,18 +446,25 @@ pub type BindGroupLayouts<A> = crate::storage::Storage<BindGroupLayout<A>, BindG
|
|||
/// - produced bind groups
|
||||
/// - produced pipeline layouts
|
||||
/// - pipelines with implicit layouts
|
||||
#[derive(Debug)]
|
||||
pub struct BindGroupLayout<A: hal::Api> {
|
||||
pub(crate) raw: A::BindGroupLayout,
|
||||
pub(crate) device_id: Stored<DeviceId>,
|
||||
pub(crate) multi_ref_count: MultiRefCount,
|
||||
pub(crate) entries: BindEntryMap,
|
||||
// When a layout created and there already exists a compatible layout the new layout
|
||||
// keeps a reference to the older compatible one. In some places we substitute the
|
||||
// bind group layout id with its compatible sibling.
|
||||
// Since this substitution can come at a cost, it is skipped when wgpu-core generates
|
||||
// its own resource IDs.
|
||||
pub(crate) compatible_layout: Option<Valid<BindGroupLayoutId>>,
|
||||
pub(crate) inner: BglOrDuplicate<A>,
|
||||
}
|
||||
|
||||
pub(crate) enum BglOrDuplicate<A: hal::Api> {
|
||||
Inner(BindGroupLayoutInner<A>),
|
||||
Duplicate(Valid<BindGroupLayoutId>),
|
||||
}
|
||||
|
||||
pub struct BindGroupLayoutInner<A: hal::Api> {
|
||||
pub(crate) raw: A::BindGroupLayout,
|
||||
pub(crate) entries: BindEntryMap,
|
||||
#[allow(unused)]
|
||||
pub(crate) dynamic_count: usize,
|
||||
pub(crate) count_validator: BindingTypeMaxCountValidator,
|
||||
|
@ -465,6 +472,34 @@ pub struct BindGroupLayout<A: hal::Api> {
|
|||
pub(crate) label: String,
|
||||
}
|
||||
|
||||
impl<A: hal::Api> BindGroupLayout<A> {
|
||||
#[track_caller]
|
||||
pub(crate) fn assume_deduplicated(&self) -> &BindGroupLayoutInner<A> {
|
||||
self.as_inner().unwrap()
|
||||
}
|
||||
|
||||
pub(crate) fn as_inner(&self) -> Option<&BindGroupLayoutInner<A>> {
|
||||
match self.inner {
|
||||
BglOrDuplicate::Inner(ref inner) => Some(inner),
|
||||
BglOrDuplicate::Duplicate(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn into_inner(self) -> Option<BindGroupLayoutInner<A>> {
|
||||
match self.inner {
|
||||
BglOrDuplicate::Inner(inner) => Some(inner),
|
||||
BglOrDuplicate::Duplicate(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn as_duplicate(&self) -> Option<Valid<BindGroupLayoutId>> {
|
||||
match self.inner {
|
||||
BglOrDuplicate::Duplicate(id) => Some(id),
|
||||
BglOrDuplicate::Inner(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: hal::Api> Resource for BindGroupLayout<A> {
|
||||
const TYPE: &'static str = "BindGroupLayout";
|
||||
|
||||
|
@ -474,7 +509,7 @@ impl<A: hal::Api> Resource for BindGroupLayout<A> {
|
|||
|
||||
fn label(&self) -> &str {
|
||||
#[cfg(debug_assertions)]
|
||||
return &self.label;
|
||||
return self.as_inner().map_or("", |inner| &inner.label);
|
||||
#[cfg(not(debug_assertions))]
|
||||
return "";
|
||||
}
|
||||
|
@ -486,8 +521,8 @@ pub(crate) fn try_get_bind_group_layout<A: HalApi>(
|
|||
id: BindGroupLayoutId,
|
||||
) -> Option<&BindGroupLayout<A>> {
|
||||
let layout = layouts.get(id).ok()?;
|
||||
if let Some(compat) = layout.compatible_layout {
|
||||
return Some(&layouts[compat]);
|
||||
if let BglOrDuplicate::Duplicate(original_id) = layout.inner {
|
||||
return Some(&layouts[original_id]);
|
||||
}
|
||||
|
||||
Some(layout)
|
||||
|
@ -499,9 +534,8 @@ pub(crate) fn get_bind_group_layout<A: HalApi>(
|
|||
) -> (Valid<BindGroupLayoutId>, &BindGroupLayout<A>) {
|
||||
let layout = &layouts[id];
|
||||
layout
|
||||
.compatible_layout
|
||||
.map(|compat| (compat, &layouts[compat]))
|
||||
.unwrap_or((id, layout))
|
||||
.as_duplicate()
|
||||
.map_or((id, layout), |deduped| (deduped, &layouts[deduped]))
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Error)]
|
||||
|
|
|
@ -38,7 +38,7 @@ mod compat {
|
|||
}
|
||||
|
||||
if let Some(id) = self.assigned {
|
||||
return bind_group_layouts[id].compatible_layout == self.expected;
|
||||
return bind_group_layouts[id].as_duplicate() == self.expected;
|
||||
}
|
||||
|
||||
false
|
||||
|
|
|
@ -10,7 +10,7 @@ use crate::{
|
|||
RenderCommand, RenderCommandError, StateChange,
|
||||
},
|
||||
device::{
|
||||
AttachmentData, Device, MissingDownlevelFlags, MissingFeatures,
|
||||
AttachmentData, Device, DeviceError, MissingDownlevelFlags, MissingFeatures,
|
||||
RenderPassCompatibilityCheckType, RenderPassCompatibilityError, RenderPassContext,
|
||||
},
|
||||
error::{ErrorFormatter, PrettyError},
|
||||
|
@ -18,7 +18,6 @@ use crate::{
|
|||
hal_api::HalApi,
|
||||
hub::Token,
|
||||
id,
|
||||
id::DeviceId,
|
||||
identity::GlobalIdentityHandlerFactory,
|
||||
init_tracker::{MemoryInitKind, TextureInitRange, TextureInitTrackerAction},
|
||||
pipeline::{self, PipelineFlags},
|
||||
|
@ -520,12 +519,12 @@ pub enum ColorAttachmentError {
|
|||
/// Error encountered when performing a render pass.
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub enum RenderPassErrorInner {
|
||||
#[error(transparent)]
|
||||
Device(DeviceError),
|
||||
#[error(transparent)]
|
||||
ColorAttachment(#[from] ColorAttachmentError),
|
||||
#[error(transparent)]
|
||||
Encoder(#[from] CommandEncoderError),
|
||||
#[error("Device {0:?} is invalid")]
|
||||
InvalidDevice(DeviceId),
|
||||
#[error("Attachment texture view {0:?} is invalid")]
|
||||
InvalidAttachment(id::TextureViewId),
|
||||
#[error("The format of the depth-stencil attachment ({0:?}) is not a depth-stencil format")]
|
||||
|
@ -658,6 +657,12 @@ impl From<MissingTextureUsageError> for RenderPassErrorInner {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<DeviceError> for RenderPassErrorInner {
|
||||
fn from(error: DeviceError) -> Self {
|
||||
Self::Device(error)
|
||||
}
|
||||
}
|
||||
|
||||
/// Error encountered when performing a render pass.
|
||||
#[derive(Clone, Debug, Error)]
|
||||
#[error("{scope}")]
|
||||
|
@ -1314,7 +1319,10 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
timestamp_writes: Option<&RenderPassTimestampWrites>,
|
||||
occlusion_query_set_id: Option<id::QuerySetId>,
|
||||
) -> Result<(), RenderPassError> {
|
||||
profiling::scope!("CommandEncoder::run_render_pass");
|
||||
profiling::scope!(
|
||||
"CommandEncoder::run_render_pass {}",
|
||||
base.label.unwrap_or("")
|
||||
);
|
||||
let init_scope = PassErrorScope::Pass(encoder_id);
|
||||
|
||||
let hub = A::hub(self);
|
||||
|
@ -1348,12 +1356,11 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
});
|
||||
}
|
||||
|
||||
let device = &device_guard[cmd_buf.device_id.value];
|
||||
let device_id = cmd_buf.device_id.value;
|
||||
|
||||
let device = &device_guard[device_id];
|
||||
if !device.is_valid() {
|
||||
return Err(RenderPassErrorInner::InvalidDevice(
|
||||
cmd_buf.device_id.value.0,
|
||||
))
|
||||
.map_pass_err(init_scope);
|
||||
return Err(DeviceError::Invalid).map_pass_err(init_scope);
|
||||
}
|
||||
cmd_buf.encoder.open_pass(base.label);
|
||||
|
||||
|
@ -1423,6 +1430,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
num_dynamic_offsets,
|
||||
bind_group_id,
|
||||
} => {
|
||||
log::trace!("RenderPass::set_bind_group {index} {bind_group_id:?}");
|
||||
|
||||
let scope = PassErrorScope::SetBindGroup(bind_group_id);
|
||||
let max_bind_groups = device.limits.max_bind_groups;
|
||||
if index >= max_bind_groups {
|
||||
|
@ -1446,6 +1455,11 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
.add_single(&*bind_group_guard, bind_group_id)
|
||||
.ok_or(RenderCommandError::InvalidBindGroup(bind_group_id))
|
||||
.map_pass_err(scope)?;
|
||||
|
||||
if bind_group.device_id.value != device_id {
|
||||
return Err(DeviceError::WrongDevice).map_pass_err(scope);
|
||||
}
|
||||
|
||||
bind_group
|
||||
.validate_dynamic_bindings(index, &temp_offsets, &cmd_buf.limits)
|
||||
.map_pass_err(scope)?;
|
||||
|
@ -1501,6 +1515,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
}
|
||||
}
|
||||
RenderCommand::SetPipeline(pipeline_id) => {
|
||||
log::trace!("RenderPass::set_pipeline {pipeline_id:?}");
|
||||
|
||||
let scope = PassErrorScope::SetPipelineRender(pipeline_id);
|
||||
state.pipeline = Some(pipeline_id);
|
||||
|
||||
|
@ -1511,6 +1527,10 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
.ok_or(RenderCommandError::InvalidPipeline(pipeline_id))
|
||||
.map_pass_err(scope)?;
|
||||
|
||||
if pipeline.device_id.value != device_id {
|
||||
return Err(DeviceError::WrongDevice).map_pass_err(scope);
|
||||
}
|
||||
|
||||
info.context
|
||||
.check_compatible(
|
||||
&pipeline.pass_context,
|
||||
|
@ -1620,12 +1640,19 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
offset,
|
||||
size,
|
||||
} => {
|
||||
log::trace!("RenderPass::set_index_buffer {buffer_id:?}");
|
||||
|
||||
let scope = PassErrorScope::SetIndexBuffer(buffer_id);
|
||||
let buffer: &Buffer<A> = info
|
||||
.usage_scope
|
||||
.buffers
|
||||
.merge_single(&*buffer_guard, buffer_id, hal::BufferUses::INDEX)
|
||||
.map_pass_err(scope)?;
|
||||
|
||||
if buffer.device_id.value != device_id {
|
||||
return Err(DeviceError::WrongDevice).map_pass_err(scope);
|
||||
}
|
||||
|
||||
check_buffer_usage(buffer.usage, BufferUsages::INDEX)
|
||||
.map_pass_err(scope)?;
|
||||
let buf_raw = buffer
|
||||
|
@ -1666,12 +1693,19 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
offset,
|
||||
size,
|
||||
} => {
|
||||
log::trace!("RenderPass::set_vertex_buffer {slot} {buffer_id:?}");
|
||||
|
||||
let scope = PassErrorScope::SetVertexBuffer(buffer_id);
|
||||
let buffer: &Buffer<A> = info
|
||||
.usage_scope
|
||||
.buffers
|
||||
.merge_single(&*buffer_guard, buffer_id, hal::BufferUses::VERTEX)
|
||||
.map_pass_err(scope)?;
|
||||
|
||||
if buffer.device_id.value != device_id {
|
||||
return Err(DeviceError::WrongDevice).map_pass_err(scope);
|
||||
}
|
||||
|
||||
check_buffer_usage(buffer.usage, BufferUsages::VERTEX)
|
||||
.map_pass_err(scope)?;
|
||||
let buf_raw = buffer
|
||||
|
@ -1713,6 +1747,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
state.vertex.update_limits();
|
||||
}
|
||||
RenderCommand::SetBlendConstant(ref color) => {
|
||||
log::trace!("RenderPass::set_blend_constant");
|
||||
|
||||
state.blend_constant = OptionalState::Set;
|
||||
let array = [
|
||||
color.r as f32,
|
||||
|
@ -1725,6 +1761,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
}
|
||||
}
|
||||
RenderCommand::SetStencilReference(value) => {
|
||||
log::trace!("RenderPass::set_stencil_reference {value}");
|
||||
|
||||
state.stencil_reference = value;
|
||||
if state
|
||||
.pipeline_flags
|
||||
|
@ -1740,6 +1778,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
depth_min,
|
||||
depth_max,
|
||||
} => {
|
||||
log::trace!("RenderPass::set_viewport {rect:?}");
|
||||
|
||||
let scope = PassErrorScope::SetViewport;
|
||||
if rect.x < 0.0
|
||||
|| rect.y < 0.0
|
||||
|
@ -1776,6 +1816,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
size_bytes,
|
||||
values_offset,
|
||||
} => {
|
||||
log::trace!("RenderPass::set_push_constants");
|
||||
|
||||
let scope = PassErrorScope::SetPushConstant;
|
||||
let values_offset = values_offset
|
||||
.ok_or(RenderPassErrorInner::InvalidValuesOffset)
|
||||
|
@ -1804,6 +1846,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
}
|
||||
}
|
||||
RenderCommand::SetScissor(ref rect) => {
|
||||
log::trace!("RenderPass::set_scissor_rect {rect:?}");
|
||||
|
||||
let scope = PassErrorScope::SetScissorRect;
|
||||
if rect.x + rect.w > info.extent.width
|
||||
|| rect.y + rect.h > info.extent.height
|
||||
|
@ -1827,6 +1871,10 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
first_vertex,
|
||||
first_instance,
|
||||
} => {
|
||||
log::trace!(
|
||||
"RenderPass::draw {vertex_count} {instance_count} {first_vertex} {first_instance}"
|
||||
);
|
||||
|
||||
let indexed = false;
|
||||
let scope = PassErrorScope::Draw {
|
||||
indexed,
|
||||
|
@ -1869,6 +1917,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
base_vertex,
|
||||
first_instance,
|
||||
} => {
|
||||
log::trace!("RenderPass::draw_indexed {index_count} {instance_count} {first_index} {base_vertex} {first_instance}");
|
||||
|
||||
let indexed = true;
|
||||
let scope = PassErrorScope::Draw {
|
||||
indexed,
|
||||
|
@ -1917,6 +1967,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
count,
|
||||
indexed,
|
||||
} => {
|
||||
log::trace!("RenderPass::draw_indirect (indexed:{indexed}) {buffer_id:?} {offset} {count:?}");
|
||||
|
||||
let scope = PassErrorScope::Draw {
|
||||
indexed,
|
||||
indirect: true,
|
||||
|
@ -1991,6 +2043,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
max_count,
|
||||
indexed,
|
||||
} => {
|
||||
log::trace!("RenderPass::multi_draw_indirect_count (indexed:{indexed}) {buffer_id:?} {offset} {count_buffer_id:?} {count_buffer_offset:?} {max_count:?}");
|
||||
|
||||
let scope = PassErrorScope::Draw {
|
||||
indexed,
|
||||
indirect: true,
|
||||
|
@ -2104,12 +2158,16 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
let label =
|
||||
str::from_utf8(&base.string_data[string_offset..string_offset + len])
|
||||
.unwrap();
|
||||
|
||||
log::trace!("RenderPass::push_debug_group {label:?}");
|
||||
string_offset += len;
|
||||
unsafe {
|
||||
raw.begin_debug_marker(label);
|
||||
}
|
||||
}
|
||||
RenderCommand::PopDebugGroup => {
|
||||
log::trace!("RenderPass::pop_debug_group");
|
||||
|
||||
let scope = PassErrorScope::PopDebugGroup;
|
||||
if state.debug_scope_depth == 0 {
|
||||
return Err(RenderPassErrorInner::InvalidPopDebugGroup)
|
||||
|
@ -2124,6 +2182,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
let label =
|
||||
str::from_utf8(&base.string_data[string_offset..string_offset + len])
|
||||
.unwrap();
|
||||
log::trace!("RenderPass::insert_debug_marker {label:?}");
|
||||
string_offset += len;
|
||||
unsafe {
|
||||
raw.insert_debug_marker(label);
|
||||
|
@ -2133,6 +2192,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
query_set_id,
|
||||
query_index,
|
||||
} => {
|
||||
log::trace!("RenderPass::write_timestamps {query_set_id:?} {query_index}");
|
||||
let scope = PassErrorScope::WriteTimestamp;
|
||||
|
||||
device
|
||||
|
@ -2156,6 +2216,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
.map_pass_err(scope)?;
|
||||
}
|
||||
RenderCommand::BeginOcclusionQuery { query_index } => {
|
||||
log::trace!("RenderPass::begin_occlusion_query {query_index}");
|
||||
let scope = PassErrorScope::BeginOcclusionQuery;
|
||||
|
||||
let query_set_id = occlusion_query_set_id
|
||||
|
@ -2180,6 +2241,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
.map_pass_err(scope)?;
|
||||
}
|
||||
RenderCommand::EndOcclusionQuery => {
|
||||
log::trace!("RenderPass::end_occlusion_query");
|
||||
let scope = PassErrorScope::EndOcclusionQuery;
|
||||
|
||||
end_occlusion_query(raw, &*query_set_guard, &mut active_query)
|
||||
|
@ -2189,6 +2251,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
query_set_id,
|
||||
query_index,
|
||||
} => {
|
||||
log::trace!("RenderPass::begin_pipeline_statistics_query {query_set_id:?} {query_index}");
|
||||
let scope = PassErrorScope::BeginPipelineStatisticsQuery;
|
||||
|
||||
let query_set = cmd_buf
|
||||
|
@ -2209,12 +2272,14 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
.map_pass_err(scope)?;
|
||||
}
|
||||
RenderCommand::EndPipelineStatisticsQuery => {
|
||||
log::trace!("RenderPass::end_pipeline_statistics_query");
|
||||
let scope = PassErrorScope::EndPipelineStatisticsQuery;
|
||||
|
||||
end_pipeline_statistics_query(raw, &*query_set_guard, &mut active_query)
|
||||
.map_pass_err(scope)?;
|
||||
}
|
||||
RenderCommand::ExecuteBundle(bundle_id) => {
|
||||
log::trace!("RenderPass::execute_bundle {bundle_id:?}");
|
||||
let scope = PassErrorScope::ExecuteBundle;
|
||||
let bundle: &command::RenderBundle<A> = cmd_buf
|
||||
.trackers
|
||||
|
@ -2223,6 +2288,10 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
.ok_or(RenderCommandError::InvalidRenderBundle(bundle_id))
|
||||
.map_pass_err(scope)?;
|
||||
|
||||
if bundle.device_id.value != device_id {
|
||||
return Err(DeviceError::WrongDevice).map_pass_err(scope);
|
||||
}
|
||||
|
||||
info.context
|
||||
.check_compatible(
|
||||
&bundle.context,
|
||||
|
@ -2393,7 +2462,6 @@ pub mod render_ffi {
|
|||
pass: &mut RenderPass,
|
||||
pipeline_id: id::RenderPipelineId,
|
||||
) {
|
||||
log::trace!("RenderPass::set_pipeline {pipeline_id:?}");
|
||||
if pass.current_pipeline.set_and_check_redundant(pipeline_id) {
|
||||
return;
|
||||
}
|
||||
|
@ -2411,7 +2479,6 @@ pub mod render_ffi {
|
|||
offset: BufferAddress,
|
||||
size: Option<BufferSize>,
|
||||
) {
|
||||
log::trace!("RenderPass::set_vertex_buffer {buffer_id:?}");
|
||||
pass.base.commands.push(RenderCommand::SetVertexBuffer {
|
||||
slot,
|
||||
buffer_id,
|
||||
|
@ -2428,13 +2495,11 @@ pub mod render_ffi {
|
|||
offset: BufferAddress,
|
||||
size: Option<BufferSize>,
|
||||
) {
|
||||
log::trace!("RenderPass::set_index_buffer {buffer:?}");
|
||||
pass.set_index_buffer(buffer, index_format, offset, size);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wgpu_render_pass_set_blend_constant(pass: &mut RenderPass, color: &Color) {
|
||||
log::trace!("RenderPass::set_blend_constant");
|
||||
pass.base
|
||||
.commands
|
||||
.push(RenderCommand::SetBlendConstant(*color));
|
||||
|
@ -2442,7 +2507,6 @@ pub mod render_ffi {
|
|||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wgpu_render_pass_set_stencil_reference(pass: &mut RenderPass, value: u32) {
|
||||
log::trace!("RenderPass::set_stencil_reference {value}");
|
||||
pass.base
|
||||
.commands
|
||||
.push(RenderCommand::SetStencilReference(value));
|
||||
|
@ -2458,7 +2522,6 @@ pub mod render_ffi {
|
|||
depth_min: f32,
|
||||
depth_max: f32,
|
||||
) {
|
||||
log::trace!("RenderPass::set_viewport {x} {y} {w} {h}");
|
||||
pass.base.commands.push(RenderCommand::SetViewport {
|
||||
rect: Rect { x, y, w, h },
|
||||
depth_min,
|
||||
|
@ -2474,7 +2537,6 @@ pub mod render_ffi {
|
|||
w: u32,
|
||||
h: u32,
|
||||
) {
|
||||
log::trace!("RenderPass::set_scissor_rect {x} {y} {w} {h}");
|
||||
pass.base
|
||||
.commands
|
||||
.push(RenderCommand::SetScissor(Rect { x, y, w, h }));
|
||||
|
@ -2492,7 +2554,6 @@ pub mod render_ffi {
|
|||
size_bytes: u32,
|
||||
data: *const u8,
|
||||
) {
|
||||
log::trace!("RenderPass::set_push_constants");
|
||||
assert_eq!(
|
||||
offset & (wgt::PUSH_CONSTANT_ALIGNMENT - 1),
|
||||
0,
|
||||
|
@ -2530,10 +2591,6 @@ pub mod render_ffi {
|
|||
first_vertex: u32,
|
||||
first_instance: u32,
|
||||
) {
|
||||
log::trace!(
|
||||
"RenderPass::draw {vertex_count} {instance_count} {first_vertex} {first_instance}"
|
||||
);
|
||||
|
||||
pass.base.commands.push(RenderCommand::Draw {
|
||||
vertex_count,
|
||||
instance_count,
|
||||
|
@ -2551,7 +2608,6 @@ pub mod render_ffi {
|
|||
base_vertex: i32,
|
||||
first_instance: u32,
|
||||
) {
|
||||
log::trace!("RenderPass::draw_indexed {index_count} {instance_count} {first_index} {base_vertex} {first_instance}");
|
||||
pass.base.commands.push(RenderCommand::DrawIndexed {
|
||||
index_count,
|
||||
instance_count,
|
||||
|
@ -2567,7 +2623,6 @@ pub mod render_ffi {
|
|||
buffer_id: id::BufferId,
|
||||
offset: BufferAddress,
|
||||
) {
|
||||
log::trace!("RenderPass::draw_indirect {buffer_id:?} {offset}");
|
||||
pass.base.commands.push(RenderCommand::MultiDrawIndirect {
|
||||
buffer_id,
|
||||
offset,
|
||||
|
@ -2582,7 +2637,6 @@ pub mod render_ffi {
|
|||
buffer_id: id::BufferId,
|
||||
offset: BufferAddress,
|
||||
) {
|
||||
log::trace!("RenderPass::draw_indexed_indirect {buffer_id:?} {offset}");
|
||||
pass.base.commands.push(RenderCommand::MultiDrawIndirect {
|
||||
buffer_id,
|
||||
offset,
|
||||
|
@ -2598,7 +2652,6 @@ pub mod render_ffi {
|
|||
offset: BufferAddress,
|
||||
count: u32,
|
||||
) {
|
||||
log::trace!("RenderPass::multi_draw_indirect {buffer_id:?} {offset} {count}");
|
||||
pass.base.commands.push(RenderCommand::MultiDrawIndirect {
|
||||
buffer_id,
|
||||
offset,
|
||||
|
@ -2614,7 +2667,6 @@ pub mod render_ffi {
|
|||
offset: BufferAddress,
|
||||
count: u32,
|
||||
) {
|
||||
log::trace!("RenderPass::multi_draw_indexed_indirect {buffer_id:?} {offset} {count}");
|
||||
pass.base.commands.push(RenderCommand::MultiDrawIndirect {
|
||||
buffer_id,
|
||||
offset,
|
||||
|
@ -2632,7 +2684,6 @@ pub mod render_ffi {
|
|||
count_buffer_offset: BufferAddress,
|
||||
max_count: u32,
|
||||
) {
|
||||
log::trace!("RenderPass::multi_draw_indirect_count {buffer_id:?} {offset} {count_buffer_id:?} {count_buffer_offset} {max_count}");
|
||||
pass.base
|
||||
.commands
|
||||
.push(RenderCommand::MultiDrawIndirectCount {
|
||||
|
@ -2654,7 +2705,6 @@ pub mod render_ffi {
|
|||
count_buffer_offset: BufferAddress,
|
||||
max_count: u32,
|
||||
) {
|
||||
log::trace!("RenderPass::multi_draw_indexed_indirect_count {buffer_id:?} {offset} {count_buffer_id:?} {count_buffer_offset} {max_count}");
|
||||
pass.base
|
||||
.commands
|
||||
.push(RenderCommand::MultiDrawIndirectCount {
|
||||
|
@ -2677,10 +2727,7 @@ pub mod render_ffi {
|
|||
label: RawString,
|
||||
color: u32,
|
||||
) {
|
||||
let cstr = unsafe { ffi::CStr::from_ptr(label) };
|
||||
log::trace!("RenderPass::push_debug_group {cstr:?}");
|
||||
|
||||
let bytes = cstr.to_bytes();
|
||||
let bytes = unsafe { ffi::CStr::from_ptr(label) }.to_bytes();
|
||||
pass.base.string_data.extend_from_slice(bytes);
|
||||
|
||||
pass.base.commands.push(RenderCommand::PushDebugGroup {
|
||||
|
@ -2691,7 +2738,6 @@ pub mod render_ffi {
|
|||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wgpu_render_pass_pop_debug_group(pass: &mut RenderPass) {
|
||||
log::trace!("RenderPass::pop_debug_group");
|
||||
pass.base.commands.push(RenderCommand::PopDebugGroup);
|
||||
}
|
||||
|
||||
|
@ -2705,10 +2751,7 @@ pub mod render_ffi {
|
|||
label: RawString,
|
||||
color: u32,
|
||||
) {
|
||||
let cstr = unsafe { ffi::CStr::from_ptr(label) };
|
||||
log::trace!("RenderPass::insert_debug_marker {cstr:?}");
|
||||
|
||||
let bytes = cstr.to_bytes();
|
||||
let bytes = unsafe { ffi::CStr::from_ptr(label) }.to_bytes();
|
||||
pass.base.string_data.extend_from_slice(bytes);
|
||||
|
||||
pass.base.commands.push(RenderCommand::InsertDebugMarker {
|
||||
|
@ -2723,7 +2766,6 @@ pub mod render_ffi {
|
|||
query_set_id: id::QuerySetId,
|
||||
query_index: u32,
|
||||
) {
|
||||
log::trace!("RenderPass::write_timestamps {query_set_id:?} {query_index}");
|
||||
pass.base.commands.push(RenderCommand::WriteTimestamp {
|
||||
query_set_id,
|
||||
query_index,
|
||||
|
@ -2735,7 +2777,6 @@ pub mod render_ffi {
|
|||
pass: &mut RenderPass,
|
||||
query_index: u32,
|
||||
) {
|
||||
log::trace!("RenderPass::begin_occlusion_query {query_index}");
|
||||
pass.base
|
||||
.commands
|
||||
.push(RenderCommand::BeginOcclusionQuery { query_index });
|
||||
|
@ -2743,7 +2784,6 @@ pub mod render_ffi {
|
|||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wgpu_render_pass_end_occlusion_query(pass: &mut RenderPass) {
|
||||
log::trace!("RenderPass::end_occlusion_query");
|
||||
pass.base.commands.push(RenderCommand::EndOcclusionQuery);
|
||||
}
|
||||
|
||||
|
@ -2753,7 +2793,6 @@ pub mod render_ffi {
|
|||
query_set_id: id::QuerySetId,
|
||||
query_index: u32,
|
||||
) {
|
||||
log::trace!("RenderPass::begin_pipeline_statistics_query {query_set_id:?} {query_index}");
|
||||
pass.base
|
||||
.commands
|
||||
.push(RenderCommand::BeginPipelineStatisticsQuery {
|
||||
|
@ -2764,7 +2803,6 @@ pub mod render_ffi {
|
|||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wgpu_render_pass_end_pipeline_statistics_query(pass: &mut RenderPass) {
|
||||
log::trace!("RenderPass::end_pipeline_statistics_query");
|
||||
pass.base
|
||||
.commands
|
||||
.push(RenderCommand::EndPipelineStatisticsQuery);
|
||||
|
@ -2780,7 +2818,6 @@ pub mod render_ffi {
|
|||
render_bundle_ids: *const id::RenderBundleId,
|
||||
render_bundle_ids_length: usize,
|
||||
) {
|
||||
log::trace!("RenderPass::execute_bundles");
|
||||
for &bundle_id in
|
||||
unsafe { slice::from_raw_parts(render_bundle_ids, render_bundle_ids_length) }
|
||||
{
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
#[cfg(feature = "trace")]
|
||||
use crate::device::trace;
|
||||
use crate::{
|
||||
binding_model, command, conv,
|
||||
binding_model::{self, BindGroupLayout},
|
||||
command, conv,
|
||||
device::{life::WaitIdleError, map_buffer, queue, Device, DeviceError, HostMap},
|
||||
global::Global,
|
||||
hal_api::HalApi,
|
||||
|
@ -262,7 +263,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
};
|
||||
|
||||
let id = fid.assign(buffer, &mut token);
|
||||
log::trace!("Device::create_buffer -> {:?}", id);
|
||||
log::trace!("Device::create_buffer -> {:?}", id.0);
|
||||
|
||||
device
|
||||
.trackers
|
||||
|
@ -616,7 +617,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
let ref_count = texture.life_guard.add_ref();
|
||||
|
||||
let id = fid.assign(texture, &mut token);
|
||||
log::trace!("Device::create_texture -> {id:?}");
|
||||
log::trace!("Device::create_texture -> {:?}", id.0);
|
||||
|
||||
device.trackers.lock().textures.insert_single(
|
||||
id.0,
|
||||
|
@ -696,7 +697,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
let ref_count = texture.life_guard.add_ref();
|
||||
|
||||
let id = fid.assign(texture, &mut token);
|
||||
log::trace!("Device::create_texture -> {id:?}");
|
||||
log::trace!("Device::create_texture -> {:?}", id.0);
|
||||
|
||||
device.trackers.lock().textures.insert_single(
|
||||
id.0,
|
||||
|
@ -756,7 +757,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
let ref_count = buffer.life_guard.add_ref();
|
||||
|
||||
let id = fid.assign(buffer, &mut token);
|
||||
log::trace!("Device::create_buffer -> {id:?}");
|
||||
log::trace!("Device::create_buffer -> {:?}", id.0);
|
||||
|
||||
device
|
||||
.trackers
|
||||
|
@ -1115,7 +1116,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
}
|
||||
|
||||
let mut compatible_layout = None;
|
||||
{
|
||||
let layout = {
|
||||
let (bgl_guard, _) = hub.bind_group_layouts.read(&mut token);
|
||||
if let Some(id) =
|
||||
Device::deduplicate_bind_group_layout(device_id, &entry_map, &*bgl_guard)
|
||||
|
@ -1134,19 +1135,26 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
|
||||
compatible_layout = Some(id::Valid(id));
|
||||
}
|
||||
}
|
||||
|
||||
let mut layout = match device.create_bind_group_layout(
|
||||
device_id,
|
||||
desc.label.borrow_option(),
|
||||
entry_map,
|
||||
) {
|
||||
Ok(layout) => layout,
|
||||
Err(e) => break e,
|
||||
if let Some(original_id) = compatible_layout {
|
||||
let original = &bgl_guard[original_id];
|
||||
BindGroupLayout {
|
||||
device_id: original.device_id.clone(),
|
||||
inner: crate::binding_model::BglOrDuplicate::Duplicate(original_id),
|
||||
multi_ref_count: crate::MultiRefCount::new(),
|
||||
}
|
||||
} else {
|
||||
match device.create_bind_group_layout(
|
||||
device_id,
|
||||
desc.label.borrow_option(),
|
||||
entry_map,
|
||||
) {
|
||||
Ok(layout) => layout,
|
||||
Err(e) => break e,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
layout.compatible_layout = compatible_layout;
|
||||
|
||||
let id = fid.assign(layout, &mut token);
|
||||
|
||||
if let Some(dupe) = compatible_layout {
|
||||
|
@ -1318,8 +1326,12 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
Err(..) => break binding_model::CreateBindGroupError::InvalidLayout,
|
||||
};
|
||||
|
||||
if bind_group_layout.device_id.value.0 != device_id {
|
||||
break DeviceError::WrongDevice.into();
|
||||
}
|
||||
|
||||
let mut layout_id = id::Valid(desc.layout);
|
||||
if let Some(id) = bind_group_layout.compatible_layout {
|
||||
if let Some(id) = bind_group_layout.as_duplicate() {
|
||||
layout_id = id;
|
||||
bind_group_layout = &bind_group_layout_guard[id];
|
||||
}
|
||||
|
@ -1869,7 +1881,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
let ref_count = pipeline.life_guard.add_ref();
|
||||
|
||||
let id = fid.assign(pipeline, &mut token);
|
||||
log::trace!("Device::create_render_pipeline -> {id:?}");
|
||||
log::trace!("Device::create_render_pipeline -> {:?}", id.0);
|
||||
|
||||
device
|
||||
.trackers
|
||||
|
@ -1916,7 +1928,24 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
None => break binding_model::GetBindGroupLayoutError::InvalidGroupIndex(index),
|
||||
};
|
||||
|
||||
bgl_guard[*id].multi_ref_count.inc();
|
||||
let layout = &bgl_guard[*id];
|
||||
layout.multi_ref_count.inc();
|
||||
|
||||
if G::ids_are_generated_in_wgpu() {
|
||||
return (id.0, None);
|
||||
}
|
||||
|
||||
// The ID is provided externally, so we must create a new bind group layout
|
||||
// with the given ID as a duplicate of the existing one.
|
||||
let new_layout = BindGroupLayout {
|
||||
device_id: layout.device_id.clone(),
|
||||
inner: crate::binding_model::BglOrDuplicate::<A>::Duplicate(*id),
|
||||
multi_ref_count: crate::MultiRefCount::new(),
|
||||
};
|
||||
|
||||
let fid = hub.bind_group_layouts.prepare(id_in);
|
||||
let id = fid.assign(new_layout, &mut Token::root());
|
||||
|
||||
return (id.0, None);
|
||||
};
|
||||
|
||||
|
@ -2014,7 +2043,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
let ref_count = pipeline.life_guard.add_ref();
|
||||
|
||||
let id = fid.assign(pipeline, &mut token);
|
||||
log::trace!("Device::create_compute_pipeline -> {id:?}");
|
||||
log::trace!("Device::create_compute_pipeline -> {:?}", id.0);
|
||||
|
||||
device
|
||||
.trackers
|
||||
|
|
|
@ -776,7 +776,7 @@ impl<A: HalApi> LifetimeTracker<A> {
|
|||
if bgl.multi_ref_count.dec_and_check_empty() {
|
||||
// If This layout points to a compatible one, go over the latter
|
||||
// to decrement the ref count and potentially destroy it.
|
||||
bgl_to_check = bgl.compatible_layout;
|
||||
bgl_to_check = bgl.as_duplicate();
|
||||
|
||||
log::debug!("Bind group layout {:?} will be destroyed", id);
|
||||
#[cfg(feature = "trace")]
|
||||
|
@ -786,7 +786,9 @@ impl<A: HalApi> LifetimeTracker<A> {
|
|||
if let Some(lay) =
|
||||
hub.bind_group_layouts.unregister_locked(id.0, &mut *guard)
|
||||
{
|
||||
self.free_resources.bind_group_layouts.push(lay.raw);
|
||||
if let Some(inner) = lay.into_inner() {
|
||||
self.free_resources.bind_group_layouts.push(inner.raw);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -300,6 +300,8 @@ pub enum DeviceError {
|
|||
OutOfMemory,
|
||||
#[error("Creation of a resource failed for a reason other than running out of memory.")]
|
||||
ResourceCreationFailed,
|
||||
#[error("Attempt to use a resource with a different device from the one that created it")]
|
||||
WrongDevice,
|
||||
}
|
||||
|
||||
impl From<hal::DeviceError> for DeviceError {
|
||||
|
|
|
@ -397,6 +397,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
}
|
||||
|
||||
let result = self.queue_write_staging_buffer_impl(
|
||||
queue_id,
|
||||
device,
|
||||
device_token,
|
||||
&staging_buffer,
|
||||
|
@ -464,6 +465,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
}
|
||||
|
||||
let result = self.queue_write_staging_buffer_impl(
|
||||
queue_id,
|
||||
device,
|
||||
device_token,
|
||||
&staging_buffer,
|
||||
|
@ -531,6 +533,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
|
||||
fn queue_write_staging_buffer_impl<A: HalApi>(
|
||||
&self,
|
||||
device_id: id::DeviceId,
|
||||
device: &mut super::Device<A>,
|
||||
device_token: &mut Token<super::Device<A>>,
|
||||
staging_buffer: &StagingBuffer<A>,
|
||||
|
@ -551,6 +554,10 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
.as_ref()
|
||||
.ok_or(TransferError::InvalidBuffer(buffer_id))?;
|
||||
|
||||
if dst.device_id.value.0 != device_id {
|
||||
return Err(DeviceError::WrongDevice.into());
|
||||
}
|
||||
|
||||
let src_buffer_size = staging_buffer.size;
|
||||
self.queue_validate_write_buffer_impl(dst, buffer_id, buffer_offset, src_buffer_size)?;
|
||||
|
||||
|
@ -627,6 +634,10 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
.get_mut(destination.texture)
|
||||
.map_err(|_| TransferError::InvalidTexture(destination.texture))?;
|
||||
|
||||
if dst.device_id.value.0 != queue_id {
|
||||
return Err(DeviceError::WrongDevice.into());
|
||||
}
|
||||
|
||||
if !dst.desc.usage.contains(wgt::TextureUsages::COPY_DST) {
|
||||
return Err(
|
||||
TransferError::MissingCopyDstUsageFlag(None, Some(destination.texture)).into(),
|
||||
|
@ -1105,6 +1116,11 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||
Some(cmdbuf) => cmdbuf,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
if cmdbuf.device_id.value.0 != queue_id {
|
||||
return Err(DeviceError::WrongDevice.into());
|
||||
}
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
if let Some(ref trace) = device.trace {
|
||||
trace.lock().add(Action::Submit(
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
#[cfg(feature = "trace")]
|
||||
use crate::device::trace;
|
||||
use crate::{
|
||||
binding_model::{self, get_bind_group_layout, try_get_bind_group_layout},
|
||||
binding_model::{
|
||||
self, get_bind_group_layout, try_get_bind_group_layout, BglOrDuplicate,
|
||||
BindGroupLayoutInner,
|
||||
},
|
||||
command, conv,
|
||||
device::life::WaitIdleError,
|
||||
device::{
|
||||
|
@ -1392,8 +1395,9 @@ impl<A: HalApi> Device<A> {
|
|||
.iter(self_id.backend())
|
||||
.find(|&(_, bgl)| {
|
||||
bgl.device_id.value.0 == self_id
|
||||
&& bgl.compatible_layout.is_none()
|
||||
&& bgl.entries == *entry_map
|
||||
&& bgl
|
||||
.as_inner()
|
||||
.map_or(false, |inner| inner.entries == *entry_map)
|
||||
})
|
||||
.map(|(id, value)| {
|
||||
value.multi_ref_count.inc();
|
||||
|
@ -1408,7 +1412,12 @@ impl<A: HalApi> Device<A> {
|
|||
pipeline_layout
|
||||
.bind_group_layout_ids
|
||||
.iter()
|
||||
.map(|&id| &bgl_guard[id].entries)
|
||||
.map(|&id| {
|
||||
&get_bind_group_layout(bgl_guard, id)
|
||||
.1
|
||||
.assume_deduplicated()
|
||||
.entries
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
@ -1427,7 +1436,9 @@ impl<A: HalApi> Device<A> {
|
|||
.iter()
|
||||
.enumerate()
|
||||
.map(|(group_index, &bgl_id)| pipeline::LateSizedBufferGroup {
|
||||
shader_sizes: bgl_guard[bgl_id]
|
||||
shader_sizes: get_bind_group_layout(bgl_guard, bgl_id)
|
||||
.1
|
||||
.assume_deduplicated()
|
||||
.entries
|
||||
.values()
|
||||
.filter_map(|entry| match entry.ty {
|
||||
|
@ -1639,25 +1650,27 @@ impl<A: HalApi> Device<A> {
|
|||
.map_err(binding_model::CreateBindGroupLayoutError::TooManyBindings)?;
|
||||
|
||||
Ok(binding_model::BindGroupLayout {
|
||||
raw,
|
||||
device_id: Stored {
|
||||
value: id::Valid(self_id),
|
||||
ref_count: self.life_guard.add_ref(),
|
||||
},
|
||||
multi_ref_count: MultiRefCount::new(),
|
||||
dynamic_count: entry_map
|
||||
.values()
|
||||
.filter(|b| b.ty.has_dynamic_offset())
|
||||
.count(),
|
||||
count_validator,
|
||||
entries: entry_map,
|
||||
#[cfg(debug_assertions)]
|
||||
label: label.unwrap_or("").to_string(),
|
||||
compatible_layout: None,
|
||||
inner: BglOrDuplicate::Inner(BindGroupLayoutInner {
|
||||
raw,
|
||||
dynamic_count: entry_map
|
||||
.values()
|
||||
.filter(|b| b.ty.has_dynamic_offset())
|
||||
.count(),
|
||||
count_validator,
|
||||
entries: entry_map,
|
||||
#[cfg(debug_assertions)]
|
||||
label: label.unwrap_or("").to_string(),
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
fn create_buffer_binding<'a>(
|
||||
device_id: id::DeviceId,
|
||||
bb: &binding_model::BufferBinding,
|
||||
binding: u32,
|
||||
decl: &wgt::BindGroupLayoutEntry,
|
||||
|
@ -1715,6 +1728,11 @@ impl<A: HalApi> Device<A> {
|
|||
.buffers
|
||||
.add_single(storage, bb.buffer_id, internal_use)
|
||||
.ok_or(Error::InvalidBuffer(bb.buffer_id))?;
|
||||
|
||||
if buffer.device_id.value.0 != device_id {
|
||||
return Err(DeviceError::WrongDevice.into());
|
||||
}
|
||||
|
||||
check_buffer_usage(buffer.usage, pub_usage)?;
|
||||
let raw_buffer = buffer
|
||||
.raw
|
||||
|
@ -1785,6 +1803,7 @@ impl<A: HalApi> Device<A> {
|
|||
}
|
||||
|
||||
fn create_texture_binding(
|
||||
device_id: id::DeviceId,
|
||||
view: &resource::TextureView<A>,
|
||||
texture_guard: &Storage<resource::Texture<A>, id::TextureId>,
|
||||
internal_use: hal::TextureUses,
|
||||
|
@ -1806,6 +1825,11 @@ impl<A: HalApi> Device<A> {
|
|||
.ok_or(binding_model::CreateBindGroupError::InvalidTexture(
|
||||
view.parent_id.value.0,
|
||||
))?;
|
||||
|
||||
if texture.device_id.value.0 != device_id {
|
||||
return Err(DeviceError::WrongDevice.into());
|
||||
}
|
||||
|
||||
check_texture_usage(texture.desc.usage, pub_usage)?;
|
||||
|
||||
used_texture_ranges.push(TextureInitTrackerAction {
|
||||
|
@ -1823,6 +1847,8 @@ impl<A: HalApi> Device<A> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
// This function expects the provided bind group layout to be resolved
|
||||
// (not passing a duplicate) beforehand.
|
||||
pub(super) fn create_bind_group<G: GlobalIdentityHandlerFactory>(
|
||||
&self,
|
||||
self_id: id::DeviceId,
|
||||
|
@ -1837,7 +1863,7 @@ impl<A: HalApi> Device<A> {
|
|||
// Check that the number of entries in the descriptor matches
|
||||
// the number of entries in the layout.
|
||||
let actual = desc.entries.len();
|
||||
let expected = layout.entries.len();
|
||||
let expected = layout.assume_deduplicated().entries.len();
|
||||
if actual != expected {
|
||||
return Err(Error::BindingsNumMismatch { expected, actual });
|
||||
}
|
||||
|
@ -1868,12 +1894,14 @@ impl<A: HalApi> Device<A> {
|
|||
let binding = entry.binding;
|
||||
// Find the corresponding declaration in the layout
|
||||
let decl = layout
|
||||
.assume_deduplicated()
|
||||
.entries
|
||||
.get(&binding)
|
||||
.ok_or(Error::MissingBindingDeclaration(binding))?;
|
||||
let (res_index, count) = match entry.resource {
|
||||
Br::Buffer(ref bb) => {
|
||||
let bb = Self::create_buffer_binding(
|
||||
self_id,
|
||||
bb,
|
||||
binding,
|
||||
decl,
|
||||
|
@ -1896,6 +1924,7 @@ impl<A: HalApi> Device<A> {
|
|||
let res_index = hal_buffers.len();
|
||||
for bb in bindings_array.iter() {
|
||||
let bb = Self::create_buffer_binding(
|
||||
self_id,
|
||||
bb,
|
||||
binding,
|
||||
decl,
|
||||
|
@ -1918,6 +1947,10 @@ impl<A: HalApi> Device<A> {
|
|||
.add_single(&*sampler_guard, id)
|
||||
.ok_or(Error::InvalidSampler(id))?;
|
||||
|
||||
if sampler.device_id.value.0 != self_id {
|
||||
return Err(DeviceError::WrongDevice.into());
|
||||
}
|
||||
|
||||
// Allowed sampler values for filtering and comparison
|
||||
let (allowed_filtering, allowed_comparison) = match ty {
|
||||
wgt::SamplerBindingType::Filtering => (None, false),
|
||||
|
@ -1966,6 +1999,11 @@ impl<A: HalApi> Device<A> {
|
|||
.samplers
|
||||
.add_single(&*sampler_guard, id)
|
||||
.ok_or(Error::InvalidSampler(id))?;
|
||||
|
||||
if sampler.device_id.value.0 != self_id {
|
||||
return Err(DeviceError::WrongDevice.into());
|
||||
}
|
||||
|
||||
hal_samplers.push(&sampler.raw);
|
||||
}
|
||||
|
||||
|
@ -1983,6 +2021,7 @@ impl<A: HalApi> Device<A> {
|
|||
"SampledTexture, ReadonlyStorageTexture or WriteonlyStorageTexture",
|
||||
)?;
|
||||
Self::create_texture_binding(
|
||||
self_id,
|
||||
view,
|
||||
&texture_guard,
|
||||
internal_use,
|
||||
|
@ -2011,6 +2050,7 @@ impl<A: HalApi> Device<A> {
|
|||
Self::texture_use_parameters(binding, decl, view,
|
||||
"SampledTextureArray, ReadonlyStorageTextureArray or WriteonlyStorageTextureArray")?;
|
||||
Self::create_texture_binding(
|
||||
self_id,
|
||||
view,
|
||||
&texture_guard,
|
||||
internal_use,
|
||||
|
@ -2044,9 +2084,11 @@ impl<A: HalApi> Device<A> {
|
|||
}
|
||||
}
|
||||
|
||||
let layout_inner = layout.assume_deduplicated();
|
||||
|
||||
let hal_desc = hal::BindGroupDescriptor {
|
||||
label: desc.label.borrow_option(),
|
||||
layout: &layout.raw,
|
||||
layout: &layout_inner.raw,
|
||||
entries: &hal_entries,
|
||||
buffers: &hal_buffers,
|
||||
samplers: &hal_samplers,
|
||||
|
@ -2074,7 +2116,7 @@ impl<A: HalApi> Device<A> {
|
|||
used_texture_ranges,
|
||||
dynamic_binding_info,
|
||||
// collect in the order of BGL iteration
|
||||
late_buffer_binding_sizes: layout
|
||||
late_buffer_binding_sizes: layout_inner
|
||||
.entries
|
||||
.keys()
|
||||
.flat_map(|binding| late_buffer_binding_sizes.get(binding).cloned())
|
||||
|
@ -2304,10 +2346,15 @@ impl<A: HalApi> Device<A> {
|
|||
|
||||
// validate total resource counts
|
||||
for &id in desc.bind_group_layouts.iter() {
|
||||
let bind_group_layout = bgl_guard
|
||||
.get(id)
|
||||
.map_err(|_| Error::InvalidBindGroupLayout(id))?;
|
||||
count_validator.merge(&bind_group_layout.count_validator);
|
||||
let Some(bind_group_layout) = try_get_bind_group_layout(bgl_guard, id) else {
|
||||
return Err(Error::InvalidBindGroupLayout(id));
|
||||
};
|
||||
|
||||
if bind_group_layout.device_id.value.0 != self_id {
|
||||
return Err(DeviceError::WrongDevice.into());
|
||||
}
|
||||
|
||||
count_validator.merge(&bind_group_layout.assume_deduplicated().count_validator);
|
||||
}
|
||||
count_validator
|
||||
.validate(&self.limits)
|
||||
|
@ -2316,7 +2363,12 @@ impl<A: HalApi> Device<A> {
|
|||
let bgl_vec = desc
|
||||
.bind_group_layouts
|
||||
.iter()
|
||||
.map(|&id| &try_get_bind_group_layout(bgl_guard, id).unwrap().raw)
|
||||
.map(|&id| {
|
||||
&try_get_bind_group_layout(bgl_guard, id)
|
||||
.unwrap()
|
||||
.assume_deduplicated()
|
||||
.raw
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let hal_desc = hal::PipelineLayoutDescriptor {
|
||||
label: desc.label.borrow_option(),
|
||||
|
@ -2435,6 +2487,10 @@ impl<A: HalApi> Device<A> {
|
|||
.get(desc.stage.module)
|
||||
.map_err(|_| validation::StageError::InvalidModule)?;
|
||||
|
||||
if shader_module.device_id.value.0 != self_id {
|
||||
return Err(DeviceError::WrongDevice.into());
|
||||
}
|
||||
|
||||
{
|
||||
let flag = wgt::ShaderStages::COMPUTE;
|
||||
let provided_layouts = match desc.layout {
|
||||
|
@ -2478,6 +2534,10 @@ impl<A: HalApi> Device<A> {
|
|||
.get(pipeline_layout_id)
|
||||
.map_err(|_| pipeline::CreateComputePipelineError::InvalidLayout)?;
|
||||
|
||||
if layout.device_id.value.0 != self_id {
|
||||
return Err(DeviceError::WrongDevice.into());
|
||||
}
|
||||
|
||||
let late_sized_buffer_groups =
|
||||
Device::make_late_sized_buffer_groups(&shader_binding_sizes, layout, &*bgl_guard);
|
||||
|
||||
|
@ -2821,11 +2881,20 @@ impl<A: HalApi> Device<A> {
|
|||
}
|
||||
})?;
|
||||
|
||||
if shader_module.device_id.value.0 != self_id {
|
||||
return Err(DeviceError::WrongDevice.into());
|
||||
}
|
||||
|
||||
let provided_layouts = match desc.layout {
|
||||
Some(pipeline_layout_id) => {
|
||||
let pipeline_layout = pipeline_layout_guard
|
||||
.get(pipeline_layout_id)
|
||||
.map_err(|_| pipeline::CreateRenderPipelineError::InvalidLayout)?;
|
||||
|
||||
if pipeline_layout.device_id.value.0 != self_id {
|
||||
return Err(DeviceError::WrongDevice.into());
|
||||
}
|
||||
|
||||
Some(Device::get_introspection_bind_group_layouts(
|
||||
pipeline_layout,
|
||||
&*bgl_guard,
|
||||
|
|
|
@ -575,8 +575,10 @@ impl<A: HalApi, F: GlobalIdentityHandlerFactory> Hub<A, F> {
|
|||
for element in self.bind_group_layouts.data.write().map.drain(..) {
|
||||
if let Element::Occupied(bgl, _) = element {
|
||||
let device = &devices[bgl.device_id.value];
|
||||
unsafe {
|
||||
device.raw.destroy_bind_group_layout(bgl.raw);
|
||||
if let Some(inner) = bgl.into_inner() {
|
||||
unsafe {
|
||||
device.raw.destroy_bind_group_layout(inner.raw);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -296,6 +296,7 @@ fn map_storage_format_to_naga(format: wgt::TextureFormat) -> Option<naga::Storag
|
|||
Tf::Rgba8Uint => Sf::Rgba8Uint,
|
||||
Tf::Rgba8Sint => Sf::Rgba8Sint,
|
||||
|
||||
Tf::Rgb10a2Uint => Sf::Rgb10a2Uint,
|
||||
Tf::Rgb10a2Unorm => Sf::Rgb10a2Unorm,
|
||||
Tf::Rg11b10Float => Sf::Rg11b10Float,
|
||||
|
||||
|
@ -350,6 +351,7 @@ fn map_storage_format_from_naga(format: naga::StorageFormat) -> wgt::TextureForm
|
|||
Sf::Rgba8Uint => Tf::Rgba8Uint,
|
||||
Sf::Rgba8Sint => Tf::Rgba8Sint,
|
||||
|
||||
Sf::Rgb10a2Uint => Tf::Rgb10a2Uint,
|
||||
Sf::Rgb10a2Unorm => Tf::Rgb10a2Unorm,
|
||||
Sf::Rg11b10Float => Tf::Rg11b10Float,
|
||||
|
||||
|
@ -667,7 +669,7 @@ impl NumericType {
|
|||
| Tf::Rgb10a2Unorm
|
||||
| Tf::Rgba16Float
|
||||
| Tf::Rgba32Float => (NumericDimension::Vector(Vs::Quad), Sk::Float),
|
||||
Tf::Rgba8Uint | Tf::Rgba16Uint | Tf::Rgba32Uint => {
|
||||
Tf::Rgba8Uint | Tf::Rgba16Uint | Tf::Rgba32Uint | Tf::Rgb10a2Uint => {
|
||||
(NumericDimension::Vector(Vs::Quad), Sk::Uint)
|
||||
}
|
||||
Tf::Rgba8Sint | Tf::Rgba16Sint | Tf::Rgba32Sint => {
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -11,7 +11,7 @@
|
|||
|
||||
[package]
|
||||
edition = "2021"
|
||||
rust-version = "1.60"
|
||||
rust-version = "1.65"
|
||||
name = "wgpu-hal"
|
||||
version = "0.17.0"
|
||||
authors = ["wgpu developers"]
|
||||
|
@ -64,7 +64,7 @@ optional = true
|
|||
[dependencies.naga]
|
||||
version = "0.13.0"
|
||||
git = "https://github.com/gfx-rs/naga"
|
||||
rev = "df8107b7"
|
||||
rev = "6668d0694cc51ee66c71c2ca3a1ab1081956299b"
|
||||
features = ["clone"]
|
||||
|
||||
[dependencies.profiling]
|
||||
|
@ -83,7 +83,7 @@ env_logger = "0.10"
|
|||
[dev-dependencies.naga]
|
||||
version = "0.13.0"
|
||||
git = "https://github.com/gfx-rs/naga"
|
||||
rev = "df8107b7"
|
||||
rev = "6668d0694cc51ee66c71c2ca3a1ab1081956299b"
|
||||
features = ["wgsl-in"]
|
||||
|
||||
[dev-dependencies.winit]
|
||||
|
@ -186,7 +186,7 @@ features = ["dynamic"]
|
|||
optional = true
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.libloading]
|
||||
version = ">=0.7,<0.9"
|
||||
version = ">=0.7, <0.9"
|
||||
optional = true
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.renderdoc-sys]
|
||||
|
@ -212,7 +212,7 @@ features = [
|
|||
]
|
||||
|
||||
[target."cfg(target_os = \"emscripten\")".dependencies.libloading]
|
||||
version = ">=0.7,<0.9"
|
||||
version = ">=0.7, <0.9"
|
||||
optional = true
|
||||
|
||||
[target."cfg(unix)".dependencies]
|
||||
|
@ -228,10 +228,9 @@ features = ["libloading"]
|
|||
optional = true
|
||||
|
||||
[target."cfg(windows)".dependencies.gpu-allocator]
|
||||
version = "0.22"
|
||||
version = "0.23"
|
||||
features = [
|
||||
"d3d12",
|
||||
"windows",
|
||||
"public-winapi",
|
||||
]
|
||||
optional = true
|
||||
|
|
|
@ -34,6 +34,7 @@ pub fn map_texture_format_failable(format: wgt::TextureFormat) -> Option<dxgifor
|
|||
Tf::Rgba8Uint => DXGI_FORMAT_R8G8B8A8_UINT,
|
||||
Tf::Rgba8Sint => DXGI_FORMAT_R8G8B8A8_SINT,
|
||||
Tf::Rgb9e5Ufloat => DXGI_FORMAT_R9G9B9E5_SHAREDEXP,
|
||||
Tf::Rgb10a2Uint => DXGI_FORMAT_R10G10B10A2_UINT,
|
||||
Tf::Rgb10a2Unorm => DXGI_FORMAT_R10G10B10A2_UNORM,
|
||||
Tf::Rg11b10Float => DXGI_FORMAT_R11G11B10_FLOAT,
|
||||
Tf::Rg32Uint => DXGI_FORMAT_R32G32_UINT,
|
||||
|
|
|
@ -49,8 +49,9 @@ mod placed {
|
|||
let device = raw.as_ptr();
|
||||
|
||||
match gpu_allocator::d3d12::Allocator::new(&gpu_allocator::d3d12::AllocatorCreateDesc {
|
||||
device: device.as_windows().clone(),
|
||||
device: gpu_allocator::d3d12::ID3D12DeviceVersion::Device(device.as_windows().clone()),
|
||||
debug_settings: Default::default(),
|
||||
allocation_sizes: gpu_allocator::AllocationSizes::default(),
|
||||
}) {
|
||||
Ok(allocator) => Ok(Some(Mutex::new(GpuAllocatorWrapper { allocator }))),
|
||||
Err(e) => {
|
||||
|
@ -213,6 +214,7 @@ mod placed {
|
|||
log::error!("DX12 gpu-allocator: Internal Error: {}", e);
|
||||
Self::Lost
|
||||
}
|
||||
gpu_allocator::AllocationError::BarrierLayoutNeedsDevice10 => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -828,6 +828,7 @@ impl crate::Adapter<super::Api> for super::Adapter {
|
|||
Tf::Rgba8Snorm => filterable,
|
||||
Tf::Rgba8Uint => renderable | storage,
|
||||
Tf::Rgba8Sint => renderable | storage,
|
||||
Tf::Rgb10a2Uint => renderable,
|
||||
Tf::Rgb10a2Unorm => filterable_renderable,
|
||||
Tf::Rg11b10Float => filterable | float_renderable,
|
||||
Tf::Rg32Uint => renderable,
|
||||
|
|
|
@ -35,6 +35,11 @@ impl super::AdapterShared {
|
|||
Tf::Bgra8Unorm => (glow::RGBA8, glow::BGRA, glow::UNSIGNED_BYTE), //TODO?
|
||||
Tf::Rgba8Uint => (glow::RGBA8UI, glow::RGBA_INTEGER, glow::UNSIGNED_BYTE),
|
||||
Tf::Rgba8Sint => (glow::RGBA8I, glow::RGBA_INTEGER, glow::BYTE),
|
||||
Tf::Rgb10a2Uint => (
|
||||
glow::RGB10_A2UI,
|
||||
glow::RGBA_INTEGER,
|
||||
glow::UNSIGNED_INT_2_10_10_10_REV,
|
||||
),
|
||||
Tf::Rgb10a2Unorm => (
|
||||
glow::RGB10_A2,
|
||||
glow::RGBA,
|
||||
|
|
|
@ -166,6 +166,11 @@ impl crate::Adapter<super::Api> for super::Adapter {
|
|||
flags.set(Tfc::STORAGE, pc.format_rgba8_srgb_all);
|
||||
flags
|
||||
}
|
||||
Tf::Rgb10a2Uint => {
|
||||
let mut flags = Tfc::COLOR_ATTACHMENT | msaa_count;
|
||||
flags.set(Tfc::STORAGE, pc.format_rgb10a2_uint_write);
|
||||
flags
|
||||
}
|
||||
Tf::Rgb10a2Unorm => {
|
||||
let mut flags = all_caps;
|
||||
flags.set(Tfc::STORAGE, pc.format_rgb10a2_unorm_all);
|
||||
|
@ -399,7 +404,7 @@ const RGB10A2UNORM_ALL: &[MTLFeatureSet] = &[
|
|||
MTLFeatureSet::macOS_GPUFamily1_v1,
|
||||
];
|
||||
|
||||
const RGB10A2UINT_COLOR_WRITE: &[MTLFeatureSet] = &[
|
||||
const RGB10A2UINT_WRITE: &[MTLFeatureSet] = &[
|
||||
MTLFeatureSet::iOS_GPUFamily3_v1,
|
||||
MTLFeatureSet::tvOS_GPUFamily2_v1,
|
||||
MTLFeatureSet::macOS_GPUFamily1_v1,
|
||||
|
@ -636,8 +641,7 @@ impl super::PrivateCapabilities {
|
|||
format_rgba8_srgb_no_write: !Self::supports_any(device, RGBA8_SRGB),
|
||||
format_rgb10a2_unorm_all: Self::supports_any(device, RGB10A2UNORM_ALL),
|
||||
format_rgb10a2_unorm_no_write: !Self::supports_any(device, RGB10A2UNORM_ALL),
|
||||
format_rgb10a2_uint_color: !Self::supports_any(device, RGB10A2UINT_COLOR_WRITE),
|
||||
format_rgb10a2_uint_color_write: Self::supports_any(device, RGB10A2UINT_COLOR_WRITE),
|
||||
format_rgb10a2_uint_write: Self::supports_any(device, RGB10A2UINT_WRITE),
|
||||
format_rg11b10_all: Self::supports_any(device, RG11B10FLOAT_ALL),
|
||||
format_rg11b10_no_write: !Self::supports_any(device, RG11B10FLOAT_ALL),
|
||||
format_rgb9e5_all: Self::supports_any(device, RGB9E5FLOAT_ALL),
|
||||
|
@ -971,6 +975,7 @@ impl super::PrivateCapabilities {
|
|||
Tf::Bgra8Unorm => BGRA8Unorm,
|
||||
Tf::Rgba8Uint => RGBA8Uint,
|
||||
Tf::Rgba8Sint => RGBA8Sint,
|
||||
Tf::Rgb10a2Uint => RGB10A2Uint,
|
||||
Tf::Rgb10a2Unorm => RGB10A2Unorm,
|
||||
Tf::Rg11b10Float => RG11B10Float,
|
||||
Tf::Rg32Uint => RG32Uint,
|
||||
|
|
|
@ -208,8 +208,7 @@ struct PrivateCapabilities {
|
|||
format_rgba8_srgb_no_write: bool,
|
||||
format_rgb10a2_unorm_all: bool,
|
||||
format_rgb10a2_unorm_no_write: bool,
|
||||
format_rgb10a2_uint_color: bool,
|
||||
format_rgb10a2_uint_color_write: bool,
|
||||
format_rgb10a2_uint_write: bool,
|
||||
format_rg11b10_all: bool,
|
||||
format_rg11b10_no_write: bool,
|
||||
format_rgb9e5_all: bool,
|
||||
|
|
|
@ -1223,6 +1223,8 @@ impl super::Adapter {
|
|||
let naga_options = {
|
||||
use naga::back::spv;
|
||||
|
||||
// The following capabilities are always available
|
||||
// see https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap52.html#spirvenv-capabilities
|
||||
let mut capabilities = vec![
|
||||
spv::Capability::Shader,
|
||||
spv::Capability::Matrix,
|
||||
|
@ -1230,15 +1232,23 @@ impl super::Adapter {
|
|||
spv::Capability::Image1D,
|
||||
spv::Capability::ImageQuery,
|
||||
spv::Capability::DerivativeControl,
|
||||
spv::Capability::SampledCubeArray,
|
||||
spv::Capability::SampleRateShading,
|
||||
//Note: this is requested always, no matter what the actual
|
||||
// adapter supports. It's not the responsibility of SPV-out
|
||||
// translation to handle the storage support for formats.
|
||||
spv::Capability::StorageImageExtendedFormats,
|
||||
//TODO: fill out the rest
|
||||
];
|
||||
|
||||
if self
|
||||
.downlevel_flags
|
||||
.contains(wgt::DownlevelFlags::CUBE_ARRAY_TEXTURES)
|
||||
{
|
||||
capabilities.push(spv::Capability::SampledCubeArray);
|
||||
}
|
||||
|
||||
if self
|
||||
.downlevel_flags
|
||||
.contains(wgt::DownlevelFlags::MULTISAMPLED_SHADING)
|
||||
{
|
||||
capabilities.push(spv::Capability::SampleRateShading);
|
||||
}
|
||||
|
||||
if features.contains(wgt::Features::MULTIVIEW) {
|
||||
capabilities.push(spv::Capability::MultiView);
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ impl super::PrivateCapabilities {
|
|||
Tf::Bgra8Unorm => F::B8G8R8A8_UNORM,
|
||||
Tf::Rgba8Uint => F::R8G8B8A8_UINT,
|
||||
Tf::Rgba8Sint => F::R8G8B8A8_SINT,
|
||||
Tf::Rgb10a2Uint => F::A2B10G10R10_UINT_PACK32,
|
||||
Tf::Rgb10a2Unorm => F::A2B10G10R10_UNORM_PACK32,
|
||||
Tf::Rg11b10Float => F::B10G11R11_UFLOAT_PACK32,
|
||||
Tf::Rg32Uint => F::R32G32_UINT,
|
||||
|
|
|
@ -157,6 +157,12 @@ impl super::Swapchain {
|
|||
/// - The device must have been made idle before calling this function.
|
||||
unsafe fn release_resources(self, device: &ash::Device) -> Self {
|
||||
profiling::scope!("Swapchain::release_resources");
|
||||
{
|
||||
profiling::scope!("vkDeviceWaitIdle");
|
||||
// We need to also wait until all presentation work is done. Because there is no way to portably wait until
|
||||
// the presentation work is done, we are forced to wait until the device is idle.
|
||||
let _ = unsafe { device.device_wait_idle() };
|
||||
};
|
||||
unsafe { device.destroy_fence(self.fence, None) };
|
||||
self
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"468c2c0c8fc2f2105248e445cb029a11338f8bde5e0444db5a362ad08c0b68aa","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","src/assertions.rs":"3fe98027aa73970c8ab7874a3e13dbfd6faa87df2081beb5c83aeec4c60f372f","src/lib.rs":"b4a6796691445880ffd9473769db832197f7fc626ccd2c5602a11abddfc7e6d0","src/math.rs":"4d03039736dd6926feb139bc68734cb59df34ede310427bbf059e5c925e0af3b"},"package":null}
|
||||
{"files":{"Cargo.toml":"60d11013451ea3e3d460b7548e2cc0e3d72ec0fa4d9961d4d4eda3f089bda729","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","src/assertions.rs":"3fe98027aa73970c8ab7874a3e13dbfd6faa87df2081beb5c83aeec4c60f372f","src/lib.rs":"3adc0f2e05ece59fdb86c7a360f8e773dbd60f71911db6f429edc48412949250","src/math.rs":"4d03039736dd6926feb139bc68734cb59df34ede310427bbf059e5c925e0af3b"},"package":null}
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
[package]
|
||||
edition = "2021"
|
||||
rust-version = "1.65"
|
||||
name = "wgpu-types"
|
||||
version = "0.17.0"
|
||||
authors = ["wgpu developers"]
|
||||
|
|
|
@ -2148,6 +2148,8 @@ pub enum TextureFormat {
|
|||
// Packed 32 bit formats
|
||||
/// Packed unsigned float with 9 bits mantisa for each RGB component, then a common 5 bits exponent
|
||||
Rgb9e5Ufloat,
|
||||
/// Red, green, blue, and alpha channels. 10 bit integer for RGB channels, 2 bit integer for alpha channel. Unsigned in shader.
|
||||
Rgb10a2Uint,
|
||||
/// Red, green, blue, and alpha channels. 10 bit integer for RGB channels, 2 bit integer for alpha channel. [0, 1023] ([0, 3] for alpha) converted to/from float [0, 1] in shader.
|
||||
Rgb10a2Unorm,
|
||||
/// Red, green, and blue channels. 11 bit float with no sign bit for RG channels. 10 bit float with no sign bit for blue channel. Float in shader.
|
||||
|
@ -2408,6 +2410,7 @@ impl<'de> Deserialize<'de> for TextureFormat {
|
|||
"rgba8sint" => TextureFormat::Rgba8Sint,
|
||||
"bgra8unorm" => TextureFormat::Bgra8Unorm,
|
||||
"bgra8unorm-srgb" => TextureFormat::Bgra8UnormSrgb,
|
||||
"rgb10a2uint" => TextureFormat::Rgb10a2Uint,
|
||||
"rgb10a2unorm" => TextureFormat::Rgb10a2Unorm,
|
||||
"rg11b10ufloat" => TextureFormat::Rg11b10Float,
|
||||
"rg32uint" => TextureFormat::Rg32Uint,
|
||||
|
@ -2534,6 +2537,7 @@ impl Serialize for TextureFormat {
|
|||
TextureFormat::Rgba8Sint => "rgba8sint",
|
||||
TextureFormat::Bgra8Unorm => "bgra8unorm",
|
||||
TextureFormat::Bgra8UnormSrgb => "bgra8unorm-srgb",
|
||||
TextureFormat::Rgb10a2Uint => "rgb10a2uint",
|
||||
TextureFormat::Rgb10a2Unorm => "rgb10a2unorm",
|
||||
TextureFormat::Rg11b10Float => "rg11b10ufloat",
|
||||
TextureFormat::Rg32Uint => "rg32uint",
|
||||
|
@ -2724,6 +2728,7 @@ impl TextureFormat {
|
|||
| Self::Bgra8Unorm
|
||||
| Self::Bgra8UnormSrgb
|
||||
| Self::Rgb9e5Ufloat
|
||||
| Self::Rgb10a2Uint
|
||||
| Self::Rgb10a2Unorm
|
||||
| Self::Rg11b10Float
|
||||
| Self::Rg32Uint
|
||||
|
@ -2822,6 +2827,7 @@ impl TextureFormat {
|
|||
| Self::Bgra8Unorm
|
||||
| Self::Bgra8UnormSrgb
|
||||
| Self::Rgb9e5Ufloat
|
||||
| Self::Rgb10a2Uint
|
||||
| Self::Rgb10a2Unorm
|
||||
| Self::Rg11b10Float
|
||||
| Self::Rg32Uint
|
||||
|
@ -2931,6 +2937,7 @@ impl TextureFormat {
|
|||
Self::Rgba8Sint => ( msaa, all_flags),
|
||||
Self::Bgra8Unorm => (msaa_resolve, attachment),
|
||||
Self::Bgra8UnormSrgb => (msaa_resolve, attachment),
|
||||
Self::Rgb10a2Uint => ( msaa, attachment),
|
||||
Self::Rgb10a2Unorm => (msaa_resolve, attachment),
|
||||
Self::Rg11b10Float => ( msaa, rg11b10f),
|
||||
Self::Rg32Uint => ( noaa, all_flags),
|
||||
|
@ -3036,7 +3043,8 @@ impl TextureFormat {
|
|||
| Self::Rgba16Uint
|
||||
| Self::R32Uint
|
||||
| Self::Rg32Uint
|
||||
| Self::Rgba32Uint => Some(uint),
|
||||
| Self::Rgba32Uint
|
||||
| Self::Rgb10a2Uint => Some(uint),
|
||||
|
||||
Self::R8Sint
|
||||
| Self::Rg8Sint
|
||||
|
@ -3124,7 +3132,9 @@ impl TextureFormat {
|
|||
| Self::Rg16Sint
|
||||
| Self::Rg16Float => Some(4),
|
||||
Self::R32Uint | Self::R32Sint | Self::R32Float => Some(4),
|
||||
Self::Rgb9e5Ufloat | Self::Rgb10a2Unorm | Self::Rg11b10Float => Some(4),
|
||||
Self::Rgb9e5Ufloat | Self::Rgb10a2Uint | Self::Rgb10a2Unorm | Self::Rg11b10Float => {
|
||||
Some(4)
|
||||
}
|
||||
|
||||
Self::Rgba16Unorm
|
||||
| Self::Rgba16Snorm
|
||||
|
@ -3232,7 +3242,7 @@ impl TextureFormat {
|
|||
| Self::Rgba32Float => 4,
|
||||
|
||||
Self::Rgb9e5Ufloat | Self::Rg11b10Float => 3,
|
||||
Self::Rgb10a2Unorm => 4,
|
||||
Self::Rgb10a2Uint | Self::Rgb10a2Unorm => 4,
|
||||
|
||||
Self::Stencil8 | Self::Depth16Unorm | Self::Depth24Plus | Self::Depth32Float => 1,
|
||||
|
||||
|
@ -3431,6 +3441,10 @@ fn texture_format_serialize() {
|
|||
serde_json::to_string(&TextureFormat::Bgra8UnormSrgb).unwrap(),
|
||||
"\"bgra8unorm-srgb\"".to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
serde_json::to_string(&TextureFormat::Rgb10a2Uint).unwrap(),
|
||||
"\"rgb10a2uint\"".to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
serde_json::to_string(&TextureFormat::Rgb10a2Unorm).unwrap(),
|
||||
"\"rgb10a2unorm\"".to_string()
|
||||
|
@ -3723,6 +3737,10 @@ fn texture_format_deserialize() {
|
|||
serde_json::from_str::<TextureFormat>("\"bgra8unorm-srgb\"").unwrap(),
|
||||
TextureFormat::Bgra8UnormSrgb
|
||||
);
|
||||
assert_eq!(
|
||||
serde_json::from_str::<TextureFormat>("\"rgb10a2uint\"").unwrap(),
|
||||
TextureFormat::Rgb10a2Uint
|
||||
);
|
||||
assert_eq!(
|
||||
serde_json::from_str::<TextureFormat>("\"rgb10a2unorm\"").unwrap(),
|
||||
TextureFormat::Rgb10a2Unorm
|
||||
|
@ -6129,6 +6147,7 @@ impl<T: Copy> ImageCopyTextureTagged<T> {
|
|||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
|
||||
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
|
||||
pub struct ImageSubresourceRange {
|
||||
/// Aspect of the texture. Color textures must be [`TextureAspect::All`][TAA].
|
||||
///
|
||||
|
|
Загрузка…
Ссылка в новой задаче