Bug 1865218 - Update wgpu to revision 3ec547cdcaaa14488327d8f1b5f7736278c4178d. r=webgpu-reviewers,supply-chain-reviewers,ErichDonGubler

Differential Revision: https://phabricator.services.mozilla.com/D193850
This commit is contained in:
Teodor Tanasoaia 2023-11-17 18:26:48 +00:00
parent e246c64e78
commit efa811a62f
80 changed files with 2807 additions and 2437 deletions

View File

@ -25,9 +25,9 @@ git = "https://github.com/franziskuskiefer/cose-rust"
rev = "43c22248d136c8b38fe42ea709d08da6355cf04b"
replace-with = "vendored-sources"
[source."git+https://github.com/gfx-rs/wgpu?rev=ba3d6898f18c25bb5a2b8ba18790134b97758e83"]
[source."git+https://github.com/gfx-rs/wgpu?rev=3ec547cdcaaa14488327d8f1b5f7736278c4178d"]
git = "https://github.com/gfx-rs/wgpu"
rev = "ba3d6898f18c25bb5a2b8ba18790134b97758e83"
rev = "3ec547cdcaaa14488327d8f1b5f7736278c4178d"
replace-with = "vendored-sources"
[source."git+https://github.com/glandium/warp?rev=4af45fae95bc98b0eba1ef0db17e1dac471bb23d"]

14
Cargo.lock generated
View File

@ -1146,7 +1146,7 @@ dependencies = [
[[package]]
name = "d3d12"
version = "0.7.0"
source = "git+https://github.com/gfx-rs/wgpu?rev=ba3d6898f18c25bb5a2b8ba18790134b97758e83#ba3d6898f18c25bb5a2b8ba18790134b97758e83"
source = "git+https://github.com/gfx-rs/wgpu?rev=3ec547cdcaaa14488327d8f1b5f7736278c4178d#3ec547cdcaaa14488327d8f1b5f7736278c4178d"
dependencies = [
"bitflags 2.4.0",
"libloading",
@ -3760,7 +3760,7 @@ checksum = "a2983372caf4480544083767bf2d27defafe32af49ab4df3a0b7fc90793a3664"
[[package]]
name = "naga"
version = "0.14.0"
source = "git+https://github.com/gfx-rs/wgpu?rev=ba3d6898f18c25bb5a2b8ba18790134b97758e83#ba3d6898f18c25bb5a2b8ba18790134b97758e83"
source = "git+https://github.com/gfx-rs/wgpu?rev=3ec547cdcaaa14488327d8f1b5f7736278c4178d#3ec547cdcaaa14488327d8f1b5f7736278c4178d"
dependencies = [
"bit-set",
"bitflags 2.4.0",
@ -5426,9 +5426,9 @@ dependencies = [
[[package]]
name = "termcolor"
version = "1.2.0"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449"
dependencies = [
"winapi-util",
]
@ -6347,7 +6347,7 @@ dependencies = [
[[package]]
name = "wgpu-core"
version = "0.18.0"
source = "git+https://github.com/gfx-rs/wgpu?rev=ba3d6898f18c25bb5a2b8ba18790134b97758e83#ba3d6898f18c25bb5a2b8ba18790134b97758e83"
source = "git+https://github.com/gfx-rs/wgpu?rev=3ec547cdcaaa14488327d8f1b5f7736278c4178d#3ec547cdcaaa14488327d8f1b5f7736278c4178d"
dependencies = [
"arrayvec",
"bit-vec",
@ -6370,7 +6370,7 @@ dependencies = [
[[package]]
name = "wgpu-hal"
version = "0.18.0"
source = "git+https://github.com/gfx-rs/wgpu?rev=ba3d6898f18c25bb5a2b8ba18790134b97758e83#ba3d6898f18c25bb5a2b8ba18790134b97758e83"
source = "git+https://github.com/gfx-rs/wgpu?rev=3ec547cdcaaa14488327d8f1b5f7736278c4178d#3ec547cdcaaa14488327d8f1b5f7736278c4178d"
dependencies = [
"android_system_properties",
"arrayvec",
@ -6407,7 +6407,7 @@ dependencies = [
[[package]]
name = "wgpu-types"
version = "0.18.0"
source = "git+https://github.com/gfx-rs/wgpu?rev=ba3d6898f18c25bb5a2b8ba18790134b97758e83#ba3d6898f18c25bb5a2b8ba18790134b97758e83"
source = "git+https://github.com/gfx-rs/wgpu?rev=3ec547cdcaaa14488327d8f1b5f7736278c4178d#3ec547cdcaaa14488327d8f1b5f7736278c4178d"
dependencies = [
"bitflags 2.4.0",
"js-sys",

View File

@ -17,7 +17,7 @@ default = []
[dependencies.wgc]
package = "wgpu-core"
git = "https://github.com/gfx-rs/wgpu"
rev = "ba3d6898f18c25bb5a2b8ba18790134b97758e83"
rev = "3ec547cdcaaa14488327d8f1b5f7736278c4178d"
#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,36 +27,36 @@ 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 = "ba3d6898f18c25bb5a2b8ba18790134b97758e83"
rev = "3ec547cdcaaa14488327d8f1b5f7736278c4178d"
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 = "ba3d6898f18c25bb5a2b8ba18790134b97758e83"
rev = "3ec547cdcaaa14488327d8f1b5f7736278c4178d"
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 = "ba3d6898f18c25bb5a2b8ba18790134b97758e83"
rev = "3ec547cdcaaa14488327d8f1b5f7736278c4178d"
features = ["vulkan"]
[dependencies.wgt]
package = "wgpu-types"
git = "https://github.com/gfx-rs/wgpu"
rev = "ba3d6898f18c25bb5a2b8ba18790134b97758e83"
rev = "3ec547cdcaaa14488327d8f1b5f7736278c4178d"
[dependencies.wgh]
package = "wgpu-hal"
git = "https://github.com/gfx-rs/wgpu"
rev = "ba3d6898f18c25bb5a2b8ba18790134b97758e83"
rev = "3ec547cdcaaa14488327d8f1b5f7736278c4178d"
[target.'cfg(windows)'.dependencies.d3d12]
git = "https://github.com/gfx-rs/wgpu"
rev = "ba3d6898f18c25bb5a2b8ba18790134b97758e83"
rev = "3ec547cdcaaa14488327d8f1b5f7736278c4178d"
[target.'cfg(windows)'.dependencies]
winapi = "0.3"

View File

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

View File

@ -1294,7 +1294,7 @@ pub unsafe extern "C" fn wgpu_queue_write_texture(
/// Returns the block size or zero if the format has multiple aspects (for example depth+stencil).
#[no_mangle]
pub extern "C" fn wgpu_texture_format_block_size_single_aspect(format: wgt::TextureFormat) -> u32 {
format.block_size(None).unwrap_or(0)
format.block_copy_size(None).unwrap_or(0)
}
#[no_mangle]

View File

@ -1166,6 +1166,11 @@ who = "Nicolas Silva <nical@fastmail.com>"
criteria = "safe-to-deploy"
delta = "0.7.0 -> 0.7.0@git:ba3d6898f18c25bb5a2b8ba18790134b97758e83"
[[audits.d3d12]]
who = "Teodor Tanasoaia <ttanasoaia@mozilla.com>"
criteria = "safe-to-deploy"
delta = "0.7.0@git:ba3d6898f18c25bb5a2b8ba18790134b97758e83 -> 0.7.0@git:3ec547cdcaaa14488327d8f1b5f7736278c4178d"
[[audits.darling]]
who = "Mike Hommey <mh+mozilla@glandium.org>"
criteria = "safe-to-deploy"
@ -2349,6 +2354,11 @@ who = "Nicolas Silva <nical@fastmail.com>"
criteria = "safe-to-deploy"
delta = "0.14.0@git:34e947de4b3e0b0d6b0e2f40cede926467ea9f1e -> 0.14.0@git:ba3d6898f18c25bb5a2b8ba18790134b97758e83"
[[audits.naga]]
who = "Teodor Tanasoaia <ttanasoaia@mozilla.com>"
criteria = "safe-to-deploy"
delta = "0.14.0@git:ba3d6898f18c25bb5a2b8ba18790134b97758e83 -> 0.14.0@git:3ec547cdcaaa14488327d8f1b5f7736278c4178d"
[[audits.net2]]
who = "Mike Hommey <mh+mozilla@glandium.org>"
criteria = "safe-to-run"
@ -4048,6 +4058,11 @@ who = "Nicolas Silva <nical@fastmail.com>"
criteria = "safe-to-deploy"
delta = "0.18.0@git:34e947de4b3e0b0d6b0e2f40cede926467ea9f1e -> 0.18.0@git:ba3d6898f18c25bb5a2b8ba18790134b97758e83"
[[audits.wgpu-core]]
who = "Teodor Tanasoaia <ttanasoaia@mozilla.com>"
criteria = "safe-to-deploy"
delta = "0.18.0@git:ba3d6898f18c25bb5a2b8ba18790134b97758e83 -> 0.18.0@git:3ec547cdcaaa14488327d8f1b5f7736278c4178d"
[[audits.wgpu-hal]]
who = "Dzmitry Malyshau <kvark@fastmail.com>"
criteria = "safe-to-deploy"
@ -4101,6 +4116,11 @@ who = "Nicolas Silva <nical@fastmail.com>"
criteria = "safe-to-deploy"
delta = "0.18.0@git:34e947de4b3e0b0d6b0e2f40cede926467ea9f1e -> 0.18.0@git:ba3d6898f18c25bb5a2b8ba18790134b97758e83"
[[audits.wgpu-hal]]
who = "Teodor Tanasoaia <ttanasoaia@mozilla.com>"
criteria = "safe-to-deploy"
delta = "0.18.0@git:ba3d6898f18c25bb5a2b8ba18790134b97758e83 -> 0.18.0@git:3ec547cdcaaa14488327d8f1b5f7736278c4178d"
[[audits.wgpu-types]]
who = "Dzmitry Malyshau <kvark@fastmail.com>"
criteria = "safe-to-deploy"
@ -4154,6 +4174,11 @@ who = "Nicolas Silva <nical@fastmail.com>"
criteria = "safe-to-deploy"
delta = "0.18.0@git:34e947de4b3e0b0d6b0e2f40cede926467ea9f1e -> 0.18.0@git:ba3d6898f18c25bb5a2b8ba18790134b97758e83"
[[audits.wgpu-types]]
who = "Teodor Tanasoaia <ttanasoaia@mozilla.com>"
criteria = "safe-to-deploy"
delta = "0.18.0@git:ba3d6898f18c25bb5a2b8ba18790134b97758e83 -> 0.18.0@git:3ec547cdcaaa14488327d8f1b5f7736278c4178d"
[[audits.whatsys]]
who = "Bobby Holley <bobbyholley@gmail.com>"
criteria = "safe-to-deploy"

View File

@ -538,6 +538,13 @@ user-id = 189
user-login = "BurntSushi"
user-name = "Andrew Gallant"
[[publisher.termcolor]]
version = "1.4.0"
when = "2023-11-14"
user-id = 189
user-login = "BurntSushi"
user-name = "Andrew Gallant"
[[publisher.threadbound]]
version = "0.1.5"
when = "2022-12-17"

File diff suppressed because one or more lines are too long

View File

@ -74,7 +74,7 @@ version = "0.2.1"
optional = true
[dependencies.serde]
version = "1.0.191"
version = "1.0.192"
features = ["derive"]
optional = true
@ -83,7 +83,7 @@ version = "0.2"
optional = true
[dependencies.termcolor]
version = "1.0.4"
version = "1.4.0"
optional = true
[dependencies.unicode-xid]

View File

@ -430,11 +430,26 @@ impl<T> Arena<T> {
P: FnMut(Handle<T>, &mut T) -> bool,
{
let mut index = 0;
let mut retained = 0;
self.data.retain_mut(|elt| {
let handle = Handle::new(Index::new(index as u32 + 1).unwrap());
let keep = predicate(handle, elt);
// Since `predicate` needs mutable access to each element,
// we can't feasibly call it twice, so we have to compact
// spans by hand in parallel as part of this iteration.
#[cfg(feature = "span")]
if keep {
self.span_info[retained] = self.span_info[index];
retained += 1;
}
index += 1;
let handle = Handle::new(Index::new(index).unwrap());
predicate(handle, elt)
})
keep
});
#[cfg(feature = "span")]
self.span_info.truncate(retained);
}
}

View File

@ -1,7 +1,7 @@
use super::{BackendResult, Error, Version, Writer};
use crate::{
AddressSpace, Binding, Bytes, Expression, Handle, ImageClass, ImageDimension, Interpolation,
Sampling, ScalarKind, ShaderStage, StorageFormat, Type, TypeInner,
AddressSpace, Binding, Expression, Handle, ImageClass, ImageDimension, Interpolation, Sampling,
Scalar, ScalarKind, ShaderStage, StorageFormat, Type, TypeInner,
};
use std::fmt::Write;
@ -275,10 +275,10 @@ impl<'a, W> Writer<'a, W> {
for (ty_handle, ty) in self.module.types.iter() {
match ty.inner {
TypeInner::Scalar { kind, width } => self.scalar_required_features(kind, width),
TypeInner::Vector { kind, width, .. } => self.scalar_required_features(kind, width),
TypeInner::Scalar(scalar) => self.scalar_required_features(scalar),
TypeInner::Vector { scalar, .. } => self.scalar_required_features(scalar),
TypeInner::Matrix { width, .. } => {
self.scalar_required_features(ScalarKind::Float, width)
self.scalar_required_features(Scalar::float(width))
}
TypeInner::Array { base, size, .. } => {
if let TypeInner::Array { .. } = self.module.types[base].inner {
@ -463,8 +463,8 @@ impl<'a, W> Writer<'a, W> {
}
/// Helper method that checks the [`Features`] needed by a scalar
fn scalar_required_features(&mut self, kind: ScalarKind, width: Bytes) {
if kind == ScalarKind::Float && width == 8 {
fn scalar_required_features(&mut self, scalar: Scalar) {
if scalar.kind == ScalarKind::Float && scalar.width == 8 {
self.features.request(Features::DOUBLE_TYPE);
}
}

View File

@ -471,8 +471,8 @@ pub enum Error {
#[error("A call was made to an unsupported external: {0}")]
UnsupportedExternal(String),
/// A scalar with an unsupported width was requested.
#[error("A scalar with an unsupported width was requested: {0:?} {1:?}")]
UnsupportedScalar(crate::ScalarKind, crate::Bytes),
#[error("A scalar with an unsupported width was requested: {0:?}")]
UnsupportedScalar(crate::Scalar),
/// A image was used with multiple samplers, which isn't supported.
#[error("A image was used with multiple samplers")]
ImageMultipleSamplers,
@ -963,27 +963,20 @@ impl<'a, W: Write> Writer<'a, W> {
fn write_value_type(&mut self, inner: &TypeInner) -> BackendResult {
match *inner {
// Scalars are simple we just get the full name from `glsl_scalar`
TypeInner::Scalar { kind, width }
| TypeInner::Atomic { kind, width }
TypeInner::Scalar(scalar)
| TypeInner::Atomic(scalar)
| TypeInner::ValuePointer {
size: None,
kind,
width,
scalar,
space: _,
} => write!(self.out, "{}", glsl_scalar(kind, width)?.full)?,
} => write!(self.out, "{}", glsl_scalar(scalar)?.full)?,
// Vectors are just `gvecN` where `g` is the scalar prefix and `N` is the vector size
TypeInner::Vector { size, kind, width }
TypeInner::Vector { size, scalar }
| TypeInner::ValuePointer {
size: Some(size),
kind,
width,
scalar,
space: _,
} => write!(
self.out,
"{}vec{}",
glsl_scalar(kind, width)?.prefix,
size as u8
)?,
} => write!(self.out, "{}vec{}", glsl_scalar(scalar)?.prefix, size as u8)?,
// Matrices are written with `gmatMxN` where `g` is the scalar prefix (only floats and
// doubles are allowed), `M` is the columns count and `N` is the rows count
//
@ -996,7 +989,7 @@ impl<'a, W: Write> Writer<'a, W> {
} => write!(
self.out,
"{}mat{}x{}",
glsl_scalar(crate::ScalarKind::Float, width)?.prefix,
glsl_scalar(crate::Scalar::float(width))?.prefix,
columns as u8,
rows as u8
)?,
@ -1083,7 +1076,7 @@ impl<'a, W: Write> Writer<'a, W> {
self.out,
"{}{}{}{}{}{}{}",
precision,
glsl_scalar(kind, 4)?.prefix,
glsl_scalar(crate::Scalar { kind, width: 4 })?.prefix,
base,
glsl_dimension(dim),
ms,
@ -1278,7 +1271,7 @@ impl<'a, W: Write> Writer<'a, W> {
crate::MathFunction::Dot => {
// if the expression is a Dot product with integer arguments,
// then the args needs baking as well
if let TypeInner::Scalar { kind, .. } = *inner {
if let TypeInner::Scalar(crate::Scalar { kind, .. }) = *inner {
match kind {
crate::ScalarKind::Sint | crate::ScalarKind::Uint => {
self.need_bake_expressions.insert(arg);
@ -2802,10 +2795,10 @@ impl<'a, W: Write> Writer<'a, W> {
if let Some(expr) = level {
let cast_to_int = matches!(
*ctx.resolve_type(expr, &self.module.types),
crate::TypeInner::Scalar {
crate::TypeInner::Scalar(crate::Scalar {
kind: crate::ScalarKind::Uint,
..
}
})
);
write!(self.out, ", ")?;
@ -2906,19 +2899,19 @@ impl<'a, W: Write> Writer<'a, W> {
let right_inner = ctx.resolve_type(right, &self.module.types);
let function = match (left_inner, right_inner) {
(&Ti::Vector { kind, .. }, &Ti::Vector { .. }) => match op {
(&Ti::Vector { scalar, .. }, &Ti::Vector { .. }) => match op {
Bo::Less
| Bo::LessEqual
| Bo::Greater
| Bo::GreaterEqual
| Bo::Equal
| Bo::NotEqual => BinaryOperation::VectorCompare,
Bo::Modulo if kind == Sk::Float => BinaryOperation::Modulo,
Bo::And if kind == Sk::Bool => {
Bo::Modulo if scalar.kind == Sk::Float => BinaryOperation::Modulo,
Bo::And if scalar.kind == Sk::Bool => {
op = crate::BinaryOperator::LogicalAnd;
BinaryOperation::VectorComponentWise
}
Bo::InclusiveOr if kind == Sk::Bool => {
Bo::InclusiveOr if scalar.kind == Sk::Bool => {
op = crate::BinaryOperator::LogicalOr;
BinaryOperation::VectorComponentWise
}
@ -3171,7 +3164,11 @@ impl<'a, W: Write> Writer<'a, W> {
// geometry
Mf::Dot => match *ctx.resolve_type(arg, &self.module.types) {
crate::TypeInner::Vector {
kind: crate::ScalarKind::Float,
scalar:
crate::Scalar {
kind: crate::ScalarKind::Float,
..
},
..
} => "dot",
crate::TypeInner::Vector { size, .. } => {
@ -3226,9 +3223,9 @@ impl<'a, W: Write> Writer<'a, W> {
// bits
Mf::CountTrailingZeros => {
match *ctx.resolve_type(arg, &self.module.types) {
crate::TypeInner::Vector { size, kind, .. } => {
crate::TypeInner::Vector { size, scalar, .. } => {
let s = back::vector_size_str(size);
if let crate::ScalarKind::Uint = kind {
if let crate::ScalarKind::Uint = scalar.kind {
write!(self.out, "min(uvec{s}(findLSB(")?;
self.write_expr(arg, ctx)?;
write!(self.out, ")), uvec{s}(32u))")?;
@ -3238,8 +3235,8 @@ impl<'a, W: Write> Writer<'a, W> {
write!(self.out, ")), uvec{s}(32u)))")?;
}
}
crate::TypeInner::Scalar { kind, .. } => {
if let crate::ScalarKind::Uint = kind {
crate::TypeInner::Scalar(scalar) => {
if let crate::ScalarKind::Uint = scalar.kind {
write!(self.out, "min(uint(findLSB(")?;
self.write_expr(arg, ctx)?;
write!(self.out, ")), 32u)")?;
@ -3256,10 +3253,10 @@ impl<'a, W: Write> Writer<'a, W> {
Mf::CountLeadingZeros => {
if self.options.version.supports_integer_functions() {
match *ctx.resolve_type(arg, &self.module.types) {
crate::TypeInner::Vector { size, kind, .. } => {
crate::TypeInner::Vector { size, scalar } => {
let s = back::vector_size_str(size);
if let crate::ScalarKind::Uint = kind {
if let crate::ScalarKind::Uint = scalar.kind {
write!(self.out, "uvec{s}(ivec{s}(31) - findMSB(")?;
self.write_expr(arg, ctx)?;
write!(self.out, "))")?;
@ -3271,8 +3268,8 @@ impl<'a, W: Write> Writer<'a, W> {
write!(self.out, ", ivec{s}(0)))")?;
}
}
crate::TypeInner::Scalar { kind, .. } => {
if let crate::ScalarKind::Uint = kind {
crate::TypeInner::Scalar(scalar) => {
if let crate::ScalarKind::Uint = scalar.kind {
write!(self.out, "uint(31 - findMSB(")?;
} else {
write!(self.out, "(")?;
@ -3287,10 +3284,10 @@ impl<'a, W: Write> Writer<'a, W> {
};
} else {
match *ctx.resolve_type(arg, &self.module.types) {
crate::TypeInner::Vector { size, kind, .. } => {
crate::TypeInner::Vector { size, scalar } => {
let s = back::vector_size_str(size);
if let crate::ScalarKind::Uint = kind {
if let crate::ScalarKind::Uint = scalar.kind {
write!(self.out, "uvec{s}(")?;
write!(self.out, "vec{s}(31.0) - floor(log2(vec{s}(")?;
self.write_expr(arg, ctx)?;
@ -3305,8 +3302,8 @@ impl<'a, W: Write> Writer<'a, W> {
write!(self.out, ", ivec{s}(0u))))")?;
}
}
crate::TypeInner::Scalar { kind, .. } => {
if let crate::ScalarKind::Uint = kind {
crate::TypeInner::Scalar(scalar) => {
if let crate::ScalarKind::Uint = scalar.kind {
write!(self.out, "uint(31.0 - floor(log2(float(")?;
self.write_expr(arg, ctx)?;
write!(self.out, ") + 0.5)))")?;
@ -3360,14 +3357,17 @@ impl<'a, W: Write> Writer<'a, W> {
// Check if the argument is an unsigned integer and return the vector size
// in case it's a vector
let maybe_uint_size = match *ctx.resolve_type(arg, &self.module.types) {
crate::TypeInner::Scalar {
crate::TypeInner::Scalar(crate::Scalar {
kind: crate::ScalarKind::Uint,
..
} => Some(None),
}) => Some(None),
crate::TypeInner::Vector {
kind: crate::ScalarKind::Uint,
scalar:
crate::Scalar {
kind: crate::ScalarKind::Uint,
..
},
size,
..
} => Some(Some(size)),
_ => None,
};
@ -3450,7 +3450,10 @@ impl<'a, W: Write> Writer<'a, W> {
match convert {
Some(width) => {
// this is similar to `write_type`, but with the target kind
let scalar = glsl_scalar(target_kind, width)?;
let scalar = glsl_scalar(crate::Scalar {
kind: target_kind,
width,
})?;
match *inner {
TypeInner::Matrix { columns, rows, .. } => write!(
self.out,
@ -3471,10 +3474,12 @@ impl<'a, W: Write> Writer<'a, W> {
use crate::ScalarKind as Sk;
let target_vector_type = match *inner {
TypeInner::Vector { size, width, .. } => Some(TypeInner::Vector {
TypeInner::Vector { size, scalar } => Some(TypeInner::Vector {
size,
width,
kind: target_kind,
scalar: crate::Scalar {
kind: target_kind,
width: scalar.width,
},
}),
_ => None,
};
@ -3613,14 +3618,17 @@ impl<'a, W: Write> Writer<'a, W> {
// Otherwise write just the expression (and the 1D hack if needed)
None => {
let uvec_size = match *ctx.resolve_type(coordinate, &self.module.types) {
TypeInner::Scalar {
TypeInner::Scalar(crate::Scalar {
kind: crate::ScalarKind::Uint,
..
} => Some(None),
}) => Some(None),
TypeInner::Vector {
size,
kind: crate::ScalarKind::Uint,
..
scalar:
crate::Scalar {
kind: crate::ScalarKind::Uint,
..
},
} => Some(Some(size as u32)),
_ => None,
};
@ -3953,7 +3961,11 @@ impl<'a, W: Write> Writer<'a, W> {
// End the first branch
write!(self.out, " : ")?;
// Write the 0 value
write!(self.out, "{}vec4(", glsl_scalar(kind, 4)?.prefix,)?;
write!(
self.out,
"{}vec4(",
glsl_scalar(crate::Scalar { kind, width: 4 })?.prefix,
)?;
self.write_zero_init_scalar(kind)?;
// Close the zero value constructor
write!(self.out, ")")?;
@ -4006,13 +4018,13 @@ impl<'a, W: Write> Writer<'a, W> {
fn write_zero_init_value(&mut self, ty: Handle<crate::Type>) -> BackendResult {
let inner = &self.module.types[ty].inner;
match *inner {
TypeInner::Scalar { kind, .. } | TypeInner::Atomic { kind, .. } => {
self.write_zero_init_scalar(kind)?;
TypeInner::Scalar(scalar) | TypeInner::Atomic(scalar) => {
self.write_zero_init_scalar(scalar.kind)?;
}
TypeInner::Vector { kind, .. } => {
TypeInner::Vector { scalar, .. } => {
self.write_value_type(inner)?;
write!(self.out, "(")?;
self.write_zero_init_scalar(kind)?;
self.write_zero_init_scalar(scalar.kind)?;
write!(self.out, ")")?;
}
TypeInner::Matrix { .. } => {
@ -4265,13 +4277,10 @@ struct ScalarString<'a> {
///
/// # Errors
/// If a [`Float`](crate::ScalarKind::Float) with an width that isn't 4 or 8
const fn glsl_scalar(
kind: crate::ScalarKind,
width: crate::Bytes,
) -> Result<ScalarString<'static>, Error> {
const fn glsl_scalar(scalar: crate::Scalar) -> Result<ScalarString<'static>, Error> {
use crate::ScalarKind as Sk;
Ok(match kind {
Ok(match scalar.kind {
Sk::Sint => ScalarString {
prefix: "i",
full: "int",
@ -4280,7 +4289,7 @@ const fn glsl_scalar(
prefix: "u",
full: "uint",
},
Sk::Float => match width {
Sk::Float => match scalar.width {
4 => ScalarString {
prefix: "",
full: "float",
@ -4289,7 +4298,7 @@ const fn glsl_scalar(
prefix: "d",
full: "double",
},
_ => return Err(Error::UnsupportedScalar(kind, width)),
_ => return Err(Error::UnsupportedScalar(scalar)),
},
Sk::Bool => ScalarString {
prefix: "b",

View File

@ -13,21 +13,23 @@ impl crate::ScalarKind {
Self::Bool => unreachable!(),
}
}
}
impl crate::Scalar {
/// Helper function that returns scalar related strings
///
/// <https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-scalar>
pub(super) const fn to_hlsl_str(self, width: crate::Bytes) -> Result<&'static str, Error> {
match self {
Self::Sint => Ok("int"),
Self::Uint => Ok("uint"),
Self::Float => match width {
pub(super) const fn to_hlsl_str(self) -> Result<&'static str, Error> {
match self.kind {
crate::ScalarKind::Sint => Ok("int"),
crate::ScalarKind::Uint => Ok("uint"),
crate::ScalarKind::Float => match self.width {
2 => Ok("half"),
4 => Ok("float"),
8 => Ok("double"),
_ => Err(Error::UnsupportedScalar(self, width)),
_ => Err(Error::UnsupportedScalar(self)),
},
Self::Bool => Ok("bool"),
crate::ScalarKind::Bool => Ok("bool"),
}
}
}
@ -71,10 +73,10 @@ impl crate::TypeInner {
names: &'a crate::FastHashMap<crate::proc::NameKey, String>,
) -> Result<Cow<'a, str>, Error> {
Ok(match gctx.types[base].inner {
crate::TypeInner::Scalar { kind, width } => Cow::Borrowed(kind.to_hlsl_str(width)?),
crate::TypeInner::Vector { size, kind, width } => Cow::Owned(format!(
crate::TypeInner::Scalar(scalar) => Cow::Borrowed(scalar.to_hlsl_str()?),
crate::TypeInner::Vector { size, scalar } => Cow::Owned(format!(
"{}{}",
kind.to_hlsl_str(width)?,
scalar.to_hlsl_str()?,
crate::back::vector_size_str(size)
)),
crate::TypeInner::Matrix {
@ -83,7 +85,7 @@ impl crate::TypeInner {
width,
} => Cow::Owned(format!(
"{}{}x{}",
crate::ScalarKind::Float.to_hlsl_str(width)?,
crate::Scalar::float(width).to_hlsl_str()?,
crate::back::vector_size_str(columns),
crate::back::vector_size_str(rows),
)),

View File

@ -133,7 +133,7 @@ impl<'a, W: Write> super::Writer<'a, W> {
}
crate::ImageClass::Sampled { kind, multi } => {
let multi_str = if multi { "MS" } else { "" };
let scalar_kind_str = kind.to_hlsl_str(4)?;
let scalar_kind_str = crate::Scalar { kind, width: 4 }.to_hlsl_str()?;
write!(self.out, "{multi_str}<{scalar_kind_str}4>")?
}
crate::ImageClass::Storage { format, .. } => {
@ -658,8 +658,7 @@ impl<'a, W: Write> super::Writer<'a, W> {
let vec_ty = match module.types[member.ty].inner {
crate::TypeInner::Matrix { rows, width, .. } => crate::TypeInner::Vector {
size: rows,
kind: crate::ScalarKind::Float,
width,
scalar: crate::Scalar::float(width),
},
_ => unreachable!(),
};
@ -737,10 +736,9 @@ impl<'a, W: Write> super::Writer<'a, W> {
_ => unreachable!(),
};
let scalar_ty = match module.types[member.ty].inner {
crate::TypeInner::Matrix { width, .. } => crate::TypeInner::Scalar {
kind: crate::ScalarKind::Float,
width,
},
crate::TypeInner::Matrix { width, .. } => {
crate::TypeInner::Scalar(crate::Scalar::float(width))
}
_ => unreachable!(),
};
self.write_value_type(module, &scalar_ty)?;

View File

@ -241,8 +241,8 @@ pub struct ReflectionInfo {
pub enum Error {
#[error(transparent)]
IoError(#[from] FmtError),
#[error("A scalar with an unsupported width was requested: {0:?} {1:?}")]
UnsupportedScalar(crate::ScalarKind, crate::Bytes),
#[error("A scalar with an unsupported width was requested: {0:?}")]
UnsupportedScalar(crate::Scalar),
#[error("{0}")]
Unimplemented(String), // TODO: Error used only during development
#[error("{0}")]

View File

@ -157,25 +157,21 @@ impl<W: fmt::Write> super::Writer<'_, W> {
func_ctx: &FunctionCtx,
) -> BackendResult {
match *result_ty.inner_with(&module.types) {
crate::TypeInner::Scalar { kind, width: _ } => {
crate::TypeInner::Scalar(scalar) => {
// working around the borrow checker in `self.write_expr`
let chain = mem::take(&mut self.temp_access_chain);
let var_name = &self.names[&NameKey::GlobalVariable(var_handle)];
let cast = kind.to_hlsl_cast();
let cast = scalar.kind.to_hlsl_cast();
write!(self.out, "{cast}({var_name}.Load(")?;
self.write_storage_address(module, &chain, func_ctx)?;
write!(self.out, "))")?;
self.temp_access_chain = chain;
}
crate::TypeInner::Vector {
size,
kind,
width: _,
} => {
crate::TypeInner::Vector { size, scalar } => {
// working around the borrow checker in `self.write_expr`
let chain = mem::take(&mut self.temp_access_chain);
let var_name = &self.names[&NameKey::GlobalVariable(var_handle)];
let cast = kind.to_hlsl_cast();
let cast = scalar.kind.to_hlsl_cast();
write!(self.out, "{}({}.Load{}(", cast, var_name, size as u8)?;
self.write_storage_address(module, &chain, func_ctx)?;
write!(self.out, "))")?;
@ -189,7 +185,7 @@ impl<W: fmt::Write> super::Writer<'_, W> {
write!(
self.out,
"{}{}x{}(",
crate::ScalarKind::Float.to_hlsl_str(width)?,
crate::Scalar::float(width).to_hlsl_str()?,
columns as u8,
rows as u8,
)?;
@ -199,8 +195,7 @@ impl<W: fmt::Write> super::Writer<'_, W> {
let iter = (0..columns as u32).map(|i| {
let ty_inner = crate::TypeInner::Vector {
size: rows,
kind: crate::ScalarKind::Float,
width,
scalar: crate::Scalar::float(width),
};
(TypeResolution::Value(ty_inner), i * row_stride)
});
@ -296,7 +291,7 @@ impl<W: fmt::Write> super::Writer<'_, W> {
}
};
match *ty_resolution.inner_with(&module.types) {
crate::TypeInner::Scalar { .. } => {
crate::TypeInner::Scalar(_) => {
// working around the borrow checker in `self.write_expr`
let chain = mem::take(&mut self.temp_access_chain);
let var_name = &self.names[&NameKey::GlobalVariable(var_handle)];
@ -330,7 +325,7 @@ impl<W: fmt::Write> super::Writer<'_, W> {
self.out,
"{}{}{}x{} {}{} = ",
level.next(),
crate::ScalarKind::Float.to_hlsl_str(width)?,
crate::Scalar::float(width).to_hlsl_str()?,
columns as u8,
rows as u8,
STORE_TEMP_NAME,
@ -348,8 +343,7 @@ impl<W: fmt::Write> super::Writer<'_, W> {
.push(SubAccess::Offset(i * row_stride));
let ty_inner = crate::TypeInner::Vector {
size: rows,
kind: crate::ScalarKind::Float,
width,
scalar: crate::Scalar::float(width),
};
let sv = StoreValue::TempIndex {
depth,
@ -470,8 +464,8 @@ impl<W: fmt::Write> super::Writer<'_, W> {
crate::TypeInner::Pointer { base, .. } => match module.types[base].inner {
crate::TypeInner::Struct { ref members, .. } => Parent::Struct(members),
crate::TypeInner::Array { stride, .. } => Parent::Array { stride },
crate::TypeInner::Vector { width, .. } => Parent::Array {
stride: width as u32,
crate::TypeInner::Vector { scalar, .. } => Parent::Array {
stride: scalar.width as u32,
},
crate::TypeInner::Matrix { rows, width, .. } => Parent::Array {
// The stride between matrices is the count of rows as this is how
@ -480,8 +474,8 @@ impl<W: fmt::Write> super::Writer<'_, W> {
},
_ => unreachable!(),
},
crate::TypeInner::ValuePointer { width, .. } => Parent::Array {
stride: width as u32,
crate::TypeInner::ValuePointer { scalar, .. } => Parent::Array {
stride: scalar.width as u32,
},
_ => unreachable!(),
};

View File

@ -912,8 +912,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
} if member.binding.is_none() && rows == crate::VectorSize::Bi => {
let vec_ty = crate::TypeInner::Vector {
size: rows,
kind: crate::ScalarKind::Float,
width,
scalar: crate::Scalar::float(width),
};
let field_name_key = NameKey::StructMember(handle, index as u32);
@ -1024,14 +1023,14 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
/// Adds no trailing or leading whitespace
pub(super) fn write_value_type(&mut self, module: &Module, inner: &TypeInner) -> BackendResult {
match *inner {
TypeInner::Scalar { kind, width } | TypeInner::Atomic { kind, width } => {
write!(self.out, "{}", kind.to_hlsl_str(width)?)?;
TypeInner::Scalar(scalar) | TypeInner::Atomic(scalar) => {
write!(self.out, "{}", scalar.to_hlsl_str()?)?;
}
TypeInner::Vector { size, kind, width } => {
TypeInner::Vector { size, scalar } => {
write!(
self.out,
"{}{}",
kind.to_hlsl_str(width)?,
scalar.to_hlsl_str()?,
back::vector_size_str(size)
)?;
}
@ -1047,7 +1046,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
write!(
self.out,
"{}{}x{}",
crate::ScalarKind::Float.to_hlsl_str(width)?,
crate::Scalar::float(width).to_hlsl_str()?,
back::vector_size_str(columns),
back::vector_size_str(rows),
)?;
@ -2484,7 +2483,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
write!(self.out, ")")?;
// return x component if return type is scalar
if let TypeInner::Scalar { .. } = *func_ctx.resolve_type(expr, &module.types) {
if let TypeInner::Scalar(_) = *func_ctx.resolve_type(expr, &module.types) {
write!(self.out, ".x")?;
}
}
@ -2567,23 +2566,27 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
let inner = func_ctx.resolve_type(expr, &module.types);
match convert {
Some(dst_width) => {
let scalar = crate::Scalar {
kind,
width: dst_width,
};
match *inner {
TypeInner::Vector { size, .. } => {
write!(
self.out,
"{}{}(",
kind.to_hlsl_str(dst_width)?,
scalar.to_hlsl_str()?,
back::vector_size_str(size)
)?;
}
TypeInner::Scalar { .. } => {
write!(self.out, "{}(", kind.to_hlsl_str(dst_width)?,)?;
TypeInner::Scalar(_) => {
write!(self.out, "{}(", scalar.to_hlsl_str()?,)?;
}
TypeInner::Matrix { columns, rows, .. } => {
write!(
self.out,
"{}{}x{}(",
kind.to_hlsl_str(dst_width)?,
scalar.to_hlsl_str()?,
back::vector_size_str(columns),
back::vector_size_str(rows)
)?;
@ -2964,14 +2967,14 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
}
Function::CountTrailingZeros => {
match *func_ctx.resolve_type(arg, &module.types) {
TypeInner::Vector { size, kind, .. } => {
TypeInner::Vector { size, scalar } => {
let s = match size {
crate::VectorSize::Bi => ".xx",
crate::VectorSize::Tri => ".xxx",
crate::VectorSize::Quad => ".xxxx",
};
if let ScalarKind::Uint = kind {
if let ScalarKind::Uint = scalar.kind {
write!(self.out, "min((32u){s}, firstbitlow(")?;
self.write_expr(module, arg, func_ctx)?;
write!(self.out, "))")?;
@ -2981,8 +2984,8 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
write!(self.out, ")))")?;
}
}
TypeInner::Scalar { kind, .. } => {
if let ScalarKind::Uint = kind {
TypeInner::Scalar(scalar) => {
if let ScalarKind::Uint = scalar.kind {
write!(self.out, "min(32u, firstbitlow(")?;
self.write_expr(module, arg, func_ctx)?;
write!(self.out, "))")?;
@ -2999,14 +3002,14 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
}
Function::CountLeadingZeros => {
match *func_ctx.resolve_type(arg, &module.types) {
TypeInner::Vector { size, kind, .. } => {
TypeInner::Vector { size, scalar } => {
let s = match size {
crate::VectorSize::Bi => ".xx",
crate::VectorSize::Tri => ".xxx",
crate::VectorSize::Quad => ".xxxx",
};
if let ScalarKind::Uint = kind {
if let ScalarKind::Uint = scalar.kind {
write!(self.out, "((31u){s} - firstbithigh(")?;
self.write_expr(module, arg, func_ctx)?;
write!(self.out, "))")?;
@ -3021,8 +3024,8 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
write!(self.out, ")))")?;
}
}
TypeInner::Scalar { kind, .. } => {
if let ScalarKind::Uint = kind {
TypeInner::Scalar(scalar) => {
if let ScalarKind::Uint = scalar.kind {
write!(self.out, "(31u - firstbithigh(")?;
self.write_expr(module, arg, func_ctx)?;
write!(self.out, "))")?;

View File

@ -45,28 +45,28 @@ pub(crate) const FREXP_FUNCTION: &str = "naga_frexp";
/// - A two element slice `[ROWS COLUMNS]` produces a matrix of the given size.
fn put_numeric_type(
out: &mut impl Write,
kind: crate::ScalarKind,
scalar: crate::Scalar,
sizes: &[crate::VectorSize],
) -> Result<(), FmtError> {
match (kind, sizes) {
(kind, &[]) => {
write!(out, "{}", kind.to_msl_name())
match (scalar, sizes) {
(scalar, &[]) => {
write!(out, "{}", scalar.to_msl_name())
}
(kind, &[rows]) => {
(scalar, &[rows]) => {
write!(
out,
"{}::{}{}",
NAMESPACE,
kind.to_msl_name(),
scalar.to_msl_name(),
back::vector_size_str(rows)
)
}
(kind, &[rows, columns]) => {
(scalar, &[rows, columns]) => {
write!(
out,
"{}::{}{}x{}",
NAMESPACE,
kind.to_msl_name(),
scalar.to_msl_name(),
back::vector_size_str(columns),
back::vector_size_str(rows)
)
@ -96,13 +96,13 @@ impl<'a> Display for TypeContext<'a> {
}
match ty.inner {
crate::TypeInner::Scalar { kind, .. } => put_numeric_type(out, kind, &[]),
crate::TypeInner::Atomic { kind, .. } => {
write!(out, "{}::atomic_{}", NAMESPACE, kind.to_msl_name())
crate::TypeInner::Scalar(scalar) => put_numeric_type(out, scalar, &[]),
crate::TypeInner::Atomic(scalar) => {
write!(out, "{}::atomic_{}", NAMESPACE, scalar.to_msl_name())
}
crate::TypeInner::Vector { size, kind, .. } => put_numeric_type(out, kind, &[size]),
crate::TypeInner::Vector { size, scalar } => put_numeric_type(out, scalar, &[size]),
crate::TypeInner::Matrix { columns, rows, .. } => {
put_numeric_type(out, crate::ScalarKind::Float, &[rows, columns])
put_numeric_type(out, crate::Scalar::F32, &[rows, columns])
}
crate::TypeInner::Pointer { base, space } => {
let sub = Self {
@ -118,8 +118,7 @@ impl<'a> Display for TypeContext<'a> {
}
crate::TypeInner::ValuePointer {
size,
kind,
width: _,
scalar,
space,
} => {
match space.to_msl_name() {
@ -127,8 +126,8 @@ impl<'a> Display for TypeContext<'a> {
None => return Ok(()),
};
match size {
Some(rows) => put_numeric_type(out, kind, &[rows])?,
None => put_numeric_type(out, kind, &[])?,
Some(rows) => put_numeric_type(out, scalar, &[rows])?,
None => put_numeric_type(out, scalar, &[])?,
};
write!(out, "&")
@ -194,7 +193,7 @@ impl<'a> Display for TypeContext<'a> {
("texture", "", format.into(), access)
}
};
let base_name = kind.to_msl_name();
let base_name = crate::Scalar { kind, width: 4 }.to_msl_name();
let array_str = if arrayed { "_array" } else { "" };
write!(
out,
@ -319,13 +318,26 @@ pub struct Writer<W> {
struct_member_pads: FastHashSet<(Handle<crate::Type>, u32)>,
}
impl crate::ScalarKind {
impl crate::Scalar {
const fn to_msl_name(self) -> &'static str {
use crate::ScalarKind as Sk;
match self {
Self::Float => "float",
Self::Sint => "int",
Self::Uint => "uint",
Self::Bool => "bool",
Self {
kind: Sk::Float,
width: _,
} => "float",
Self {
kind: Sk::Sint,
width: _,
} => "int",
Self {
kind: Sk::Uint,
width: _,
} => "uint",
Self {
kind: Sk::Bool,
width: _,
} => "bool",
}
}
}
@ -343,7 +355,7 @@ fn should_pack_struct_member(
span: u32,
index: usize,
module: &crate::Module,
) -> Option<crate::ScalarKind> {
) -> Option<crate::Scalar> {
let member = &members[index];
//Note: this is imperfect - the same structure can be used for host-shared
// things, where packed float would matter.
@ -362,9 +374,8 @@ fn should_pack_struct_member(
match *ty_inner {
crate::TypeInner::Vector {
size: crate::VectorSize::Tri,
width: 4,
kind,
} if member.offset & 0xF != 0 || is_tight => Some(kind),
scalar: scalar @ crate::Scalar { width: 4, .. },
} if member.offset & 0xF != 0 || is_tight => Some(scalar),
_ => None,
}
}
@ -442,10 +453,10 @@ impl crate::Type {
match self.inner {
// value types are concise enough, we only alias them if they are named
Ti::Scalar { .. }
Ti::Scalar(_)
| Ti::Vector { .. }
| Ti::Matrix { .. }
| Ti::Atomic { .. }
| Ti::Atomic(_)
| Ti::Pointer { .. }
| Ti::ValuePointer { .. } => self.name.is_some(),
// composite types are better to be aliased, regardless of the name
@ -549,10 +560,7 @@ impl<'a> ExpressionContext<'a> {
index::access_needs_check(base, index, self.module, self.function, self.info)
}
fn get_packed_vec_kind(
&self,
expr_handle: Handle<crate::Expression>,
) -> Option<crate::ScalarKind> {
fn get_packed_vec_kind(&self, expr_handle: Handle<crate::Expression>) -> Option<crate::Scalar> {
match self.function.expressions[expr_handle] {
crate::Expression::AccessIndex { base, index } => {
let ty = match *self.resolve_type(base) {
@ -673,7 +681,8 @@ impl<W: Write> Writer<W> {
crate::TypeInner::Image { dim, .. } => dim,
ref other => unreachable!("Unexpected type {:?}", other),
};
let coordinate_type = kind.to_msl_name();
let scalar = crate::Scalar { kind, width: 4 };
let coordinate_type = scalar.to_msl_name();
match dim {
crate::ImageDimension::D1 => {
// Since 1D textures never have mipmaps, MSL requires that the
@ -721,11 +730,11 @@ impl<W: Write> Writer<W> {
) -> BackendResult {
// coordinates in IR are int, but Metal expects uint
match *context.resolve_type(expr) {
crate::TypeInner::Scalar { .. } => {
put_numeric_type(&mut self.out, crate::ScalarKind::Uint, &[])?
crate::TypeInner::Scalar(_) => {
put_numeric_type(&mut self.out, crate::Scalar::U32, &[])?
}
crate::TypeInner::Vector { size, .. } => {
put_numeric_type(&mut self.out, crate::ScalarKind::Uint, &[size])?
put_numeric_type(&mut self.out, crate::Scalar::U32, &[size])?
}
_ => return Err(Error::Validation),
};
@ -1299,7 +1308,7 @@ impl<W: Write> Writer<W> {
};
write!(self.out, "{ty_name}")?;
match module.types[ty].inner {
crate::TypeInner::Scalar { .. }
crate::TypeInner::Scalar(_)
| crate::TypeInner::Vector { .. }
| crate::TypeInner::Matrix { .. } => {
self.put_call_parameters_impl(
@ -1326,11 +1335,11 @@ impl<W: Write> Writer<W> {
}
}
crate::Expression::Splat { size, value } => {
let scalar_kind = match *get_expr_ty(ctx, value).inner_with(&module.types) {
crate::TypeInner::Scalar { kind, .. } => kind,
let scalar = match *get_expr_ty(ctx, value).inner_with(&module.types) {
crate::TypeInner::Scalar(scalar) => scalar,
_ => return Err(Error::Validation),
};
put_numeric_type(&mut self.out, scalar_kind, &[size])?;
put_numeric_type(&mut self.out, scalar, &[size])?;
write!(self.out, "(")?;
put_expression(self, ctx, value)?;
write!(self.out, ")")?;
@ -1626,10 +1635,10 @@ impl<W: Write> Writer<W> {
accept,
reject,
} => match *context.resolve_type(condition) {
crate::TypeInner::Scalar {
crate::TypeInner::Scalar(crate::Scalar {
kind: crate::ScalarKind::Bool,
..
} => {
}) => {
if !is_scoped {
write!(self.out, "(")?;
}
@ -1643,7 +1652,11 @@ impl<W: Write> Writer<W> {
}
}
crate::TypeInner::Vector {
kind: crate::ScalarKind::Bool,
scalar:
crate::Scalar {
kind: crate::ScalarKind::Bool,
..
},
..
} => {
write!(self.out, "{NAMESPACE}::select(")?;
@ -1687,7 +1700,7 @@ impl<W: Write> Writer<W> {
let arg_type = context.resolve_type(arg);
let scalar_argument = match arg_type {
&crate::TypeInner::Scalar { .. } => true,
&crate::TypeInner::Scalar(_) => true,
_ => false,
};
@ -1732,7 +1745,11 @@ impl<W: Write> Writer<W> {
// geometry
Mf::Dot => match *context.resolve_type(arg) {
crate::TypeInner::Vector {
kind: crate::ScalarKind::Float,
scalar:
crate::Scalar {
kind: crate::ScalarKind::Float,
..
},
..
} => "dot",
crate::TypeInner::Vector { size, .. } => {
@ -1838,16 +1855,16 @@ impl<W: Write> Writer<W> {
// or metal will complain that select is ambiguous
match *inner {
crate::TypeInner::Vector { size, kind, .. } => {
crate::TypeInner::Vector { size, scalar } => {
let size = back::vector_size_str(size);
if let crate::ScalarKind::Sint = kind {
if let crate::ScalarKind::Sint = scalar.kind {
write!(self.out, "int{size}")?;
} else {
write!(self.out, "uint{size}")?;
}
}
crate::TypeInner::Scalar { kind, .. } => {
if let crate::ScalarKind::Sint = kind {
crate::TypeInner::Scalar(scalar) => {
if let crate::ScalarKind::Sint = scalar.kind {
write!(self.out, "int")?;
} else {
write!(self.out, "uint")?;
@ -1893,19 +1910,15 @@ impl<W: Write> Writer<W> {
kind,
convert,
} => match *context.resolve_type(expr) {
crate::TypeInner::Scalar {
kind: src_kind,
width: src_width,
}
| crate::TypeInner::Vector {
kind: src_kind,
width: src_width,
..
} => {
crate::TypeInner::Scalar(src) | crate::TypeInner::Vector { scalar: src, .. } => {
let target_scalar = crate::Scalar {
kind,
width: convert.unwrap_or(src.width),
};
let is_bool_cast =
kind == crate::ScalarKind::Bool || src_kind == crate::ScalarKind::Bool;
kind == crate::ScalarKind::Bool || src.kind == crate::ScalarKind::Bool;
let op = match convert {
Some(w) if w == src_width || is_bool_cast => "static_cast",
Some(w) if w == src.width || is_bool_cast => "static_cast",
Some(8) if kind == crate::ScalarKind::Float => {
return Err(Error::CapabilityNotSupported(valid::Capabilities::FLOAT64))
}
@ -1915,16 +1928,24 @@ impl<W: Write> Writer<W> {
write!(self.out, "{op}<")?;
match *context.resolve_type(expr) {
crate::TypeInner::Vector { size, .. } => {
put_numeric_type(&mut self.out, kind, &[size])?
put_numeric_type(&mut self.out, target_scalar, &[size])?
}
_ => put_numeric_type(&mut self.out, kind, &[])?,
_ => put_numeric_type(&mut self.out, target_scalar, &[])?,
};
write!(self.out, ">(")?;
self.put_expression(expr, context, true)?;
write!(self.out, ")")?;
}
crate::TypeInner::Matrix { columns, rows, .. } => {
put_numeric_type(&mut self.out, kind, &[rows, columns])?;
crate::TypeInner::Matrix {
columns,
rows,
width,
} => {
let target_scalar = crate::Scalar {
kind,
width: convert.unwrap_or(width),
};
put_numeric_type(&mut self.out, target_scalar, &[rows, columns])?;
write!(self.out, "(")?;
self.put_expression(expr, context, true)?;
write!(self.out, ")")?;
@ -2008,8 +2029,8 @@ impl<W: Write> Writer<W> {
context: &ExpressionContext,
is_scoped: bool,
) -> BackendResult {
if let Some(scalar_kind) = context.get_packed_vec_kind(expr_handle) {
write!(self.out, "{}::{}3(", NAMESPACE, scalar_kind.to_msl_name())?;
if let Some(scalar) = context.get_packed_vec_kind(expr_handle) {
write!(self.out, "{}::{}3(", NAMESPACE, scalar.to_msl_name())?;
self.put_expression(expr_handle, context, is_scoped)?;
write!(self.out, ")")?;
} else {
@ -2475,8 +2496,8 @@ impl<W: Write> Writer<W> {
// check what kind of product this is depending
// on the resolve type of the Dot function itself
let inner = context.resolve_type(expr_handle);
if let crate::TypeInner::Scalar { kind, .. } = *inner {
match kind {
if let crate::TypeInner::Scalar(scalar) = *inner {
match scalar.kind {
crate::ScalarKind::Sint | crate::ScalarKind::Uint => {
self.need_bake_expressions.insert(arg);
self.need_bake_expressions.insert(arg1.unwrap());
@ -2522,14 +2543,19 @@ impl<W: Write> Writer<W> {
};
write!(self.out, "{ty_name}")?;
}
TypeResolution::Value(crate::TypeInner::Scalar { kind, .. }) => {
put_numeric_type(&mut self.out, kind, &[])?;
TypeResolution::Value(crate::TypeInner::Scalar(scalar)) => {
put_numeric_type(&mut self.out, scalar, &[])?;
}
TypeResolution::Value(crate::TypeInner::Vector { size, kind, .. }) => {
put_numeric_type(&mut self.out, kind, &[size])?;
TypeResolution::Value(crate::TypeInner::Vector { size, scalar }) => {
put_numeric_type(&mut self.out, scalar, &[size])?;
}
TypeResolution::Value(crate::TypeInner::Matrix { columns, rows, .. }) => {
put_numeric_type(&mut self.out, crate::ScalarKind::Float, &[rows, columns])?;
TypeResolution::Value(crate::TypeInner::Matrix {
columns,
rows,
width,
}) => {
let element = crate::Scalar::float(width);
put_numeric_type(&mut self.out, element, &[rows, columns])?;
}
TypeResolution::Value(ref other) => {
log::warn!("Type {:?} isn't a known local", other); //TEMP!
@ -3292,13 +3318,13 @@ impl<W: Write> Writer<W> {
// If the member should be packed (as is the case for a misaligned vec3) issue a packed vector
match should_pack_struct_member(members, span, index, module) {
Some(kind) => {
Some(scalar) => {
writeln!(
self.out,
"{}{}::packed_{}3 {};",
back::INDENT,
NAMESPACE,
kind.to_msl_name(),
scalar.to_msl_name(),
member_name
)?;
}
@ -3322,11 +3348,10 @@ impl<W: Write> Writer<W> {
// for 3-component vectors, add one component
if let crate::TypeInner::Vector {
size: crate::VectorSize::Tri,
kind: _,
width,
scalar,
} = *ty_inner
{
last_offset += width as u32;
last_offset += scalar.width as u32;
}
}
}

View File

@ -12,7 +12,7 @@ use spirv::Word;
fn get_dimension(type_inner: &crate::TypeInner) -> Dimension {
match *type_inner {
crate::TypeInner::Scalar { .. } => Dimension::Scalar,
crate::TypeInner::Scalar(_) => Dimension::Scalar,
crate::TypeInner::Vector { .. } => Dimension::Vector,
crate::TypeInner::Matrix { .. } => Dimension::Matrix,
_ => unreachable!(),
@ -78,8 +78,7 @@ impl Writer {
) -> Result<(), Error> {
let float_ptr_type_id = self.get_type_id(LookupType::Local(LocalType::Value {
vector_size: None,
kind: crate::ScalarKind::Float,
width: 4,
scalar: crate::Scalar::F32,
pointer_space: Some(spirv::StorageClass::Output),
}));
let index_y_id = self.get_index_constant(1);
@ -93,8 +92,7 @@ impl Writer {
let float_type_id = self.get_type_id(LookupType::Local(LocalType::Value {
vector_size: None,
kind: crate::ScalarKind::Float,
width: 4,
scalar: crate::Scalar::F32,
pointer_space: None,
}));
let load_id = self.id_gen.next();
@ -120,8 +118,7 @@ impl Writer {
) -> Result<(), Error> {
let float_type_id = self.get_type_id(LookupType::Local(LocalType::Value {
vector_size: None,
kind: crate::ScalarKind::Float,
width: 4,
scalar: crate::Scalar::F32,
pointer_space: None,
}));
let zero_scalar_id = self.get_constant_scalar(crate::Literal::F32(0.0));
@ -489,8 +486,8 @@ impl<'w> BlockContext<'w> {
let spirv_op = match op {
crate::BinaryOperator::Add => match *left_ty_inner {
crate::TypeInner::Scalar { kind, .. }
| crate::TypeInner::Vector { kind, .. } => match kind {
crate::TypeInner::Scalar(scalar)
| crate::TypeInner::Vector { scalar, .. } => match scalar.kind {
crate::ScalarKind::Float => spirv::Op::FAdd,
_ => spirv::Op::IAdd,
},
@ -517,8 +514,8 @@ impl<'w> BlockContext<'w> {
_ => unimplemented!(),
},
crate::BinaryOperator::Subtract => match *left_ty_inner {
crate::TypeInner::Scalar { kind, .. }
| crate::TypeInner::Vector { kind, .. } => match kind {
crate::TypeInner::Scalar(scalar)
| crate::TypeInner::Vector { scalar, .. } => match scalar.kind {
crate::ScalarKind::Float => spirv::Op::FSub,
_ => spirv::Op::ISub,
},
@ -741,20 +738,19 @@ impl<'w> BlockContext<'w> {
other => unimplemented!("Unexpected max({:?})", other),
}),
Mf::Saturate => {
let (maybe_size, width) = match *arg_ty {
crate::TypeInner::Vector { size, width, .. } => (Some(size), width),
crate::TypeInner::Scalar { width, .. } => (None, width),
let (maybe_size, scalar) = match *arg_ty {
crate::TypeInner::Vector { size, scalar } => (Some(size), scalar),
crate::TypeInner::Scalar(scalar) => (None, scalar),
ref other => unimplemented!("Unexpected saturate({:?})", other),
};
let kind = crate::ScalarKind::Float;
let mut arg1_id = self.writer.get_constant_scalar_with(0, kind, width)?;
let mut arg2_id = self.writer.get_constant_scalar_with(1, kind, width)?;
let scalar = crate::Scalar::float(scalar.width);
let mut arg1_id = self.writer.get_constant_scalar_with(0, scalar)?;
let mut arg2_id = self.writer.get_constant_scalar_with(1, scalar)?;
if let Some(size) = maybe_size {
let ty = LocalType::Value {
vector_size: Some(size),
kind,
width,
scalar,
pointer_space: None,
}
.into();
@ -805,7 +801,11 @@ impl<'w> BlockContext<'w> {
// geometry
Mf::Dot => match *self.fun_info[arg].ty.inner_with(&self.ir_module.types) {
crate::TypeInner::Vector {
kind: crate::ScalarKind::Float,
scalar:
crate::Scalar {
kind: crate::ScalarKind::Float,
..
},
..
} => MathOp::Custom(Instruction::binary(
spirv::Op::Dot,
@ -866,13 +866,12 @@ impl<'w> BlockContext<'w> {
// if the selector is a scalar, we need to splat it
(
&crate::TypeInner::Vector { size, .. },
&crate::TypeInner::Scalar { kind, width },
&crate::TypeInner::Scalar(scalar),
) => {
let selector_type_id =
self.get_type_id(LookupType::Local(LocalType::Value {
vector_size: Some(size),
kind,
width,
scalar,
pointer_space: None,
}));
self.temp_list.clear();
@ -915,14 +914,12 @@ impl<'w> BlockContext<'w> {
arg0_id,
)),
Mf::CountTrailingZeros => {
let kind = crate::ScalarKind::Uint;
let uint_id = match *arg_ty {
crate::TypeInner::Vector { size, width, .. } => {
crate::TypeInner::Vector { size, mut scalar } => {
scalar.kind = crate::ScalarKind::Uint;
let ty = LocalType::Value {
vector_size: Some(size),
kind,
width,
scalar,
pointer_space: None,
}
.into();
@ -930,13 +927,14 @@ impl<'w> BlockContext<'w> {
self.temp_list.clear();
self.temp_list.resize(
size as _,
self.writer.get_constant_scalar_with(32, kind, width)?,
self.writer.get_constant_scalar_with(32, scalar)?,
);
self.writer.get_constant_composite(ty, &self.temp_list)
}
crate::TypeInner::Scalar { width, .. } => {
self.writer.get_constant_scalar_with(32, kind, width)?
crate::TypeInner::Scalar(mut scalar) => {
scalar.kind = crate::ScalarKind::Uint;
self.writer.get_constant_scalar_with(32, scalar)?
}
_ => unreachable!(),
};
@ -959,14 +957,12 @@ impl<'w> BlockContext<'w> {
))
}
Mf::CountLeadingZeros => {
let kind = crate::ScalarKind::Sint;
let (int_type_id, int_id) = match *arg_ty {
crate::TypeInner::Vector { size, width, .. } => {
crate::TypeInner::Vector { size, mut scalar } => {
scalar.kind = crate::ScalarKind::Sint;
let ty = LocalType::Value {
vector_size: Some(size),
kind,
width,
scalar,
pointer_space: None,
}
.into();
@ -974,7 +970,7 @@ impl<'w> BlockContext<'w> {
self.temp_list.clear();
self.temp_list.resize(
size as _,
self.writer.get_constant_scalar_with(31, kind, width)?,
self.writer.get_constant_scalar_with(31, scalar)?,
);
(
@ -982,15 +978,17 @@ impl<'w> BlockContext<'w> {
self.writer.get_constant_composite(ty, &self.temp_list),
)
}
crate::TypeInner::Scalar { width, .. } => (
self.get_type_id(LookupType::Local(LocalType::Value {
vector_size: None,
kind,
width,
pointer_space: None,
})),
self.writer.get_constant_scalar_with(31, kind, width)?,
),
crate::TypeInner::Scalar(mut scalar) => {
scalar.kind = crate::ScalarKind::Sint;
(
self.get_type_id(LookupType::Local(LocalType::Value {
vector_size: None,
scalar,
pointer_space: None,
})),
self.writer.get_constant_scalar_with(31, scalar)?,
)
}
_ => unreachable!(),
};
@ -1139,13 +1137,13 @@ impl<'w> BlockContext<'w> {
use crate::ScalarKind as Sk;
let expr_id = self.cached[expr];
let (src_kind, src_size, src_width, is_matrix) =
let (src_scalar, src_size, is_matrix) =
match *self.fun_info[expr].ty.inner_with(&self.ir_module.types) {
crate::TypeInner::Scalar { kind, width } => (kind, None, width, false),
crate::TypeInner::Vector { kind, width, size } => {
(kind, Some(size), width, false)
crate::TypeInner::Scalar(scalar) => (scalar, None, false),
crate::TypeInner::Vector { scalar, size } => (scalar, Some(size), false),
crate::TypeInner::Matrix { width, .. } => {
(crate::Scalar::float(width), None, true)
}
crate::TypeInner::Matrix { width, .. } => (kind, None, width, true),
ref other => {
log::error!("As source {:?}", other);
return Err(Error::Validation("Unexpected Expression::As source"));
@ -1163,11 +1161,12 @@ impl<'w> BlockContext<'w> {
// we only support identity casts for matrices
Cast::Unary(spirv::Op::CopyObject)
} else {
match (src_kind, kind, convert) {
match (src_scalar.kind, kind, convert) {
// Filter out identity casts. Some Adreno drivers are
// confused by no-op OpBitCast instructions.
(src_kind, kind, convert)
if src_kind == kind && convert.unwrap_or(src_width) == src_width =>
if src_kind == kind
&& convert.filter(|&width| width != src_scalar.width).is_none() =>
{
Cast::Identity
}
@ -1175,20 +1174,18 @@ impl<'w> BlockContext<'w> {
(_, _, None) => Cast::Unary(spirv::Op::Bitcast),
// casting to a bool - generate `OpXxxNotEqual`
(_, Sk::Bool, Some(_)) => {
let op = match src_kind {
let op = match src_scalar.kind {
Sk::Sint | Sk::Uint => spirv::Op::INotEqual,
Sk::Float => spirv::Op::FUnordNotEqual,
Sk::Bool => unreachable!(),
};
let zero_scalar_id = self
.writer
.get_constant_scalar_with(0, src_kind, src_width)?;
let zero_scalar_id =
self.writer.get_constant_scalar_with(0, src_scalar)?;
let zero_id = match src_size {
Some(size) => {
let ty = LocalType::Value {
vector_size: Some(size),
kind: src_kind,
width: src_width,
scalar: src_scalar,
pointer_space: None,
}
.into();
@ -1205,16 +1202,19 @@ impl<'w> BlockContext<'w> {
}
// casting from a bool - generate `OpSelect`
(Sk::Bool, _, Some(dst_width)) => {
let dst_scalar = crate::Scalar {
kind,
width: dst_width,
};
let zero_scalar_id =
self.writer.get_constant_scalar_with(0, kind, dst_width)?;
self.writer.get_constant_scalar_with(0, dst_scalar)?;
let one_scalar_id =
self.writer.get_constant_scalar_with(1, kind, dst_width)?;
self.writer.get_constant_scalar_with(1, dst_scalar)?;
let (accept_id, reject_id) = match src_size {
Some(size) => {
let ty = LocalType::Value {
vector_size: Some(size),
kind,
width: dst_width,
scalar: dst_scalar,
pointer_space: None,
}
.into();
@ -1239,15 +1239,17 @@ impl<'w> BlockContext<'w> {
}
(Sk::Float, Sk::Uint, Some(_)) => Cast::Unary(spirv::Op::ConvertFToU),
(Sk::Float, Sk::Sint, Some(_)) => Cast::Unary(spirv::Op::ConvertFToS),
(Sk::Float, Sk::Float, Some(dst_width)) if src_width != dst_width => {
(Sk::Float, Sk::Float, Some(dst_width))
if src_scalar.width != dst_width =>
{
Cast::Unary(spirv::Op::FConvert)
}
(Sk::Sint, Sk::Float, Some(_)) => Cast::Unary(spirv::Op::ConvertSToF),
(Sk::Sint, Sk::Sint, Some(dst_width)) if src_width != dst_width => {
(Sk::Sint, Sk::Sint, Some(dst_width)) if src_scalar.width != dst_width => {
Cast::Unary(spirv::Op::SConvert)
}
(Sk::Uint, Sk::Float, Some(_)) => Cast::Unary(spirv::Op::ConvertUToF),
(Sk::Uint, Sk::Uint, Some(dst_width)) if src_width != dst_width => {
(Sk::Uint, Sk::Uint, Some(dst_width)) if src_scalar.width != dst_width => {
Cast::Unary(spirv::Op::UConvert)
}
// We assume it's either an identity cast, or int-uint.
@ -1334,10 +1336,12 @@ impl<'w> BlockContext<'w> {
let object_ty = self.fun_info[accept].ty.inner_with(&self.ir_module.types);
if let (
&crate::TypeInner::Scalar {
kind: crate::ScalarKind::Bool,
width,
},
&crate::TypeInner::Scalar(
condition_scalar @ crate::Scalar {
kind: crate::ScalarKind::Bool,
..
},
),
&crate::TypeInner::Vector { size, .. },
) = (condition_ty, object_ty)
{
@ -1347,8 +1351,7 @@ impl<'w> BlockContext<'w> {
let bool_vector_type_id =
self.get_type_id(LookupType::Local(LocalType::Value {
vector_size: Some(size),
kind: crate::ScalarKind::Bool,
width,
scalar: condition_scalar,
pointer_space: None,
}));
@ -1598,8 +1601,7 @@ impl<'w> BlockContext<'w> {
let vector_type_id = self.get_type_id(LookupType::Local(LocalType::Value {
vector_size: Some(rows),
kind: crate::ScalarKind::Float,
width,
scalar: crate::Scalar::float(width),
pointer_space: None,
}));
@ -1649,7 +1651,10 @@ impl<'w> BlockContext<'w> {
vector: &crate::TypeInner,
) {
let (size, kind) = match *vector {
crate::TypeInner::Vector { size, kind, .. } => (size, kind),
crate::TypeInner::Vector {
size,
scalar: crate::Scalar { kind, .. },
} => (size, kind),
_ => unreachable!(),
};
@ -2193,14 +2198,14 @@ impl<'w> BlockContext<'w> {
),
crate::AtomicFunction::Min => {
let spirv_op = match *value_inner {
crate::TypeInner::Scalar {
crate::TypeInner::Scalar(crate::Scalar {
kind: crate::ScalarKind::Sint,
width: _,
} => spirv::Op::AtomicSMin,
crate::TypeInner::Scalar {
}) => spirv::Op::AtomicSMin,
crate::TypeInner::Scalar(crate::Scalar {
kind: crate::ScalarKind::Uint,
width: _,
} => spirv::Op::AtomicUMin,
}) => spirv::Op::AtomicUMin,
_ => unimplemented!(),
};
Instruction::atomic_binary(
@ -2215,14 +2220,14 @@ impl<'w> BlockContext<'w> {
}
crate::AtomicFunction::Max => {
let spirv_op = match *value_inner {
crate::TypeInner::Scalar {
crate::TypeInner::Scalar(crate::Scalar {
kind: crate::ScalarKind::Sint,
width: _,
} => spirv::Op::AtomicSMax,
crate::TypeInner::Scalar {
}) => spirv::Op::AtomicSMax,
crate::TypeInner::Scalar(crate::Scalar {
kind: crate::ScalarKind::Uint,
width: _,
} => spirv::Op::AtomicUMax,
}) => spirv::Op::AtomicUMax,
_ => unimplemented!(),
};
Instruction::atomic_binary(
@ -2248,11 +2253,10 @@ impl<'w> BlockContext<'w> {
}
crate::AtomicFunction::Exchange { compare: Some(cmp) } => {
let scalar_type_id = match *value_inner {
crate::TypeInner::Scalar { kind, width } => {
crate::TypeInner::Scalar(scalar) => {
self.get_type_id(LookupType::Local(LocalType::Value {
vector_size: None,
kind,
width,
scalar,
pointer_space: None,
}))
}
@ -2261,8 +2265,7 @@ impl<'w> BlockContext<'w> {
let bool_type_id =
self.get_type_id(LookupType::Local(LocalType::Value {
vector_size: None,
kind: crate::ScalarKind::Bool,
width: crate::BOOL_WIDTH,
scalar: crate::Scalar::BOOL,
pointer_space: None,
}));

View File

@ -128,8 +128,7 @@ impl Load {
crate::ImageClass::Depth { .. } => {
ctx.get_type_id(LookupType::Local(LocalType::Value {
vector_size: Some(crate::VectorSize::Quad),
kind: crate::ScalarKind::Float,
width: 4,
scalar: crate::Scalar::F32,
pointer_space: None,
}))
}
@ -292,18 +291,16 @@ impl<'w> BlockContext<'w> {
// Find the component type of `coordinates`, and figure out the size the
// combined coordinate vector will have.
let (component_kind, size) = match *inner_ty {
Ti::Scalar { kind, width: 4 } => (kind, Some(Vs::Bi)),
let (component_scalar, size) = match *inner_ty {
Ti::Scalar(scalar @ crate::Scalar { width: 4, .. }) => (scalar, Some(Vs::Bi)),
Ti::Vector {
kind,
width: 4,
scalar: scalar @ crate::Scalar { width: 4, .. },
size: Vs::Bi,
} => (kind, Some(Vs::Tri)),
} => (scalar, Some(Vs::Tri)),
Ti::Vector {
kind,
width: 4,
scalar: scalar @ crate::Scalar { width: 4, .. },
size: Vs::Tri,
} => (kind, Some(Vs::Quad)),
} => (scalar, Some(Vs::Quad)),
Ti::Vector { size: Vs::Quad, .. } => {
return Err(Error::Validation("extending vec4 coordinate"));
}
@ -317,16 +314,16 @@ impl<'w> BlockContext<'w> {
let array_index_id = self.cached[array_index];
let ty = &self.fun_info[array_index].ty;
let inner_ty = ty.inner_with(&self.ir_module.types);
let array_index_kind = if let Ti::Scalar { kind, width: 4 } = *inner_ty {
debug_assert!(matches!(
kind,
crate::ScalarKind::Sint | crate::ScalarKind::Uint
));
kind
} else {
unreachable!("we only allow i32 and u32");
let array_index_scalar = match *inner_ty {
Ti::Scalar(
scalar @ crate::Scalar {
kind: crate::ScalarKind::Sint | crate::ScalarKind::Uint,
width: 4,
},
) => scalar,
_ => unreachable!("we only allow i32 and u32"),
};
let cast = match (component_kind, array_index_kind) {
let cast = match (component_scalar.kind, array_index_scalar.kind) {
(crate::ScalarKind::Sint, crate::ScalarKind::Sint)
| (crate::ScalarKind::Uint, crate::ScalarKind::Uint) => None,
(crate::ScalarKind::Sint, crate::ScalarKind::Uint)
@ -341,8 +338,7 @@ impl<'w> BlockContext<'w> {
let reconciled_array_index_id = if let Some(cast) = cast {
let component_ty_id = self.get_type_id(LookupType::Local(LocalType::Value {
vector_size: None,
kind: component_kind,
width: 4,
scalar: component_scalar,
pointer_space: None,
}));
let reconciled_id = self.gen_id();
@ -360,8 +356,7 @@ impl<'w> BlockContext<'w> {
// Find the SPIR-V type for the combined coordinates/index vector.
let type_id = self.get_type_id(LookupType::Local(LocalType::Value {
vector_size: size,
kind: component_kind,
width: 4,
scalar: component_scalar,
pointer_space: None,
}));
@ -532,8 +527,7 @@ impl<'w> BlockContext<'w> {
let i32_type_id = self.get_type_id(LookupType::Local(LocalType::Value {
vector_size: None,
kind: crate::ScalarKind::Sint,
width: 4,
scalar: crate::Scalar::I32,
pointer_space: None,
}));
@ -620,8 +614,7 @@ impl<'w> BlockContext<'w> {
let bool_type_id = self.writer.get_bool_type_id();
let i32_type_id = self.get_type_id(LookupType::Local(LocalType::Value {
vector_size: None,
kind: crate::ScalarKind::Sint,
width: 4,
scalar: crate::Scalar::I32,
pointer_space: None,
}));
@ -688,8 +681,7 @@ impl<'w> BlockContext<'w> {
// Compare the coordinates against the bounds.
let coords_bool_type_id = self.get_type_id(LookupType::Local(LocalType::Value {
vector_size: coordinates.size,
kind: crate::ScalarKind::Bool,
width: 1,
scalar: crate::Scalar::BOOL,
pointer_space: None,
}));
let coords_conds_id = self.gen_id();
@ -844,8 +836,7 @@ impl<'w> BlockContext<'w> {
let sample_result_type_id = if needs_sub_access {
self.get_type_id(LookupType::Local(LocalType::Value {
vector_size: Some(crate::VectorSize::Quad),
kind: crate::ScalarKind::Float,
width: 4,
scalar: crate::Scalar::F32,
pointer_space: None,
}))
} else {
@ -1045,8 +1036,7 @@ impl<'w> BlockContext<'w> {
};
let extended_size_type_id = self.get_type_id(LookupType::Local(LocalType::Value {
vector_size,
kind: crate::ScalarKind::Uint,
width: 4,
scalar: crate::Scalar::U32,
pointer_space: None,
}));
@ -1116,8 +1106,7 @@ impl<'w> BlockContext<'w> {
};
let extended_size_type_id = self.get_type_id(LookupType::Local(LocalType::Value {
vector_size: Some(vec_size),
kind: crate::ScalarKind::Uint,
width: 4,
scalar: crate::Scalar::U32,
pointer_space: None,
}));
let id_extended = self.gen_id();

View File

@ -276,8 +276,7 @@ enum LocalType {
/// If `None`, this represents a scalar type. If `Some`, this represents
/// a vector type of the given size.
vector_size: Option<crate::VectorSize>,
kind: crate::ScalarKind,
width: crate::Bytes,
scalar: crate::Scalar,
pointer_space: Option<spirv::StorageClass>,
},
/// A matrix of floating-point values.
@ -355,18 +354,14 @@ struct LookupFunctionType {
fn make_local(inner: &crate::TypeInner) -> Option<LocalType> {
Some(match *inner {
crate::TypeInner::Scalar { kind, width } | crate::TypeInner::Atomic { kind, width } => {
LocalType::Value {
vector_size: None,
kind,
width,
pointer_space: None,
}
}
crate::TypeInner::Vector { size, kind, width } => LocalType::Value {
crate::TypeInner::Scalar(scalar) | crate::TypeInner::Atomic(scalar) => LocalType::Value {
vector_size: None,
scalar,
pointer_space: None,
},
crate::TypeInner::Vector { size, scalar } => LocalType::Value {
vector_size: Some(size),
kind,
width,
scalar,
pointer_space: None,
},
crate::TypeInner::Matrix {
@ -384,13 +379,11 @@ fn make_local(inner: &crate::TypeInner) -> Option<LocalType> {
},
crate::TypeInner::ValuePointer {
size,
kind,
width,
scalar,
space,
} => LocalType::Value {
vector_size: size,
kind,
width,
scalar,
pointer_space: Some(helpers::map_storage_class(space)),
},
crate::TypeInner::Image {

View File

@ -21,12 +21,10 @@ impl<'w> BlockContext<'w> {
//Note: composite extract indices and types must match `generate_ray_desc_type`
let desc_id = self.cached[descriptor];
let acc_struct_id = self.get_handle_id(acceleration_structure);
let width = 4;
let flag_type_id = self.get_type_id(LookupType::Local(LocalType::Value {
vector_size: None,
kind: crate::ScalarKind::Uint,
width,
scalar: crate::Scalar::U32,
pointer_space: None,
}));
let ray_flags_id = self.gen_id();
@ -46,8 +44,7 @@ impl<'w> BlockContext<'w> {
let scalar_type_id = self.get_type_id(LookupType::Local(LocalType::Value {
vector_size: None,
kind: crate::ScalarKind::Float,
width,
scalar: crate::Scalar::F32,
pointer_space: None,
}));
let tmin_id = self.gen_id();
@ -67,8 +64,7 @@ impl<'w> BlockContext<'w> {
let vector_type_id = self.get_type_id(LookupType::Local(LocalType::Value {
vector_size: Some(crate::VectorSize::Tri),
kind: crate::ScalarKind::Float,
width,
scalar: crate::Scalar::F32,
pointer_space: None,
}));
let ray_origin_id = self.gen_id();
@ -115,7 +111,6 @@ impl<'w> BlockContext<'w> {
query: Handle<crate::Expression>,
block: &mut Block,
) -> spirv::Word {
let width = 4;
let query_id = self.cached[query];
let intersection_id = self.writer.get_constant_scalar(crate::Literal::U32(
spirv::RayQueryIntersection::RayQueryCommittedIntersectionKHR as _,
@ -123,8 +118,7 @@ impl<'w> BlockContext<'w> {
let flag_type_id = self.get_type_id(LookupType::Local(LocalType::Value {
vector_size: None,
kind: crate::ScalarKind::Uint,
width,
scalar: crate::Scalar::U32,
pointer_space: None,
}));
let kind_id = self.gen_id();
@ -178,8 +172,7 @@ impl<'w> BlockContext<'w> {
let scalar_type_id = self.get_type_id(LookupType::Local(LocalType::Value {
vector_size: None,
kind: crate::ScalarKind::Float,
width,
scalar: crate::Scalar::F32,
pointer_space: None,
}));
let t_id = self.gen_id();
@ -193,8 +186,7 @@ impl<'w> BlockContext<'w> {
let barycentrics_type_id = self.get_type_id(LookupType::Local(LocalType::Value {
vector_size: Some(crate::VectorSize::Bi),
kind: crate::ScalarKind::Float,
width,
scalar: crate::Scalar::F32,
pointer_space: None,
}));
let barycentrics_id = self.gen_id();
@ -208,8 +200,7 @@ impl<'w> BlockContext<'w> {
let bool_type_id = self.get_type_id(LookupType::Local(LocalType::Value {
vector_size: None,
kind: crate::ScalarKind::Bool,
width: crate::BOOL_WIDTH,
scalar: crate::Scalar::BOOL,
pointer_space: None,
}));
let front_face_id = self.gen_id();
@ -224,7 +215,7 @@ impl<'w> BlockContext<'w> {
let transform_type_id = self.get_type_id(LookupType::Local(LocalType::Matrix {
columns: crate::VectorSize::Quad,
rows: crate::VectorSize::Tri,
width,
width: 4,
}));
let object_to_world_id = self.gen_id();
block.body.push(Instruction::ray_query_get_intersection(

View File

@ -238,8 +238,7 @@ impl Writer {
pub(super) fn get_uint_type_id(&mut self) -> Word {
let local_type = LocalType::Value {
vector_size: None,
kind: crate::ScalarKind::Uint,
width: 4,
scalar: crate::Scalar::U32,
pointer_space: None,
};
self.get_type_id(local_type.into())
@ -248,8 +247,7 @@ impl Writer {
pub(super) fn get_float_type_id(&mut self) -> Word {
let local_type = LocalType::Value {
vector_size: None,
kind: crate::ScalarKind::Float,
width: 4,
scalar: crate::Scalar::F32,
pointer_space: None,
};
self.get_type_id(local_type.into())
@ -258,8 +256,7 @@ impl Writer {
pub(super) fn get_uint3_type_id(&mut self) -> Word {
let local_type = LocalType::Value {
vector_size: Some(crate::VectorSize::Tri),
kind: crate::ScalarKind::Uint,
width: 4,
scalar: crate::Scalar::U32,
pointer_space: None,
};
self.get_type_id(local_type.into())
@ -268,8 +265,7 @@ impl Writer {
pub(super) fn get_float_pointer_type_id(&mut self, class: spirv::StorageClass) -> Word {
let lookup_type = LookupType::Local(LocalType::Value {
vector_size: None,
kind: crate::ScalarKind::Float,
width: 4,
scalar: crate::Scalar::F32,
pointer_space: Some(class),
});
if let Some(&id) = self.lookup_type.get(&lookup_type) {
@ -287,8 +283,7 @@ impl Writer {
pub(super) fn get_uint3_pointer_type_id(&mut self, class: spirv::StorageClass) -> Word {
let lookup_type = LookupType::Local(LocalType::Value {
vector_size: Some(crate::VectorSize::Tri),
kind: crate::ScalarKind::Uint,
width: 4,
scalar: crate::Scalar::U32,
pointer_space: Some(class),
});
if let Some(&id) = self.lookup_type.get(&lookup_type) {
@ -306,8 +301,7 @@ impl Writer {
pub(super) fn get_bool_type_id(&mut self) -> Word {
let local_type = LocalType::Value {
vector_size: None,
kind: crate::ScalarKind::Bool,
width: 1,
scalar: crate::Scalar::BOOL,
pointer_space: None,
};
self.get_type_id(local_type.into())
@ -316,8 +310,7 @@ impl Writer {
pub(super) fn get_bool3_type_id(&mut self) -> Word {
let local_type = LocalType::Value {
vector_size: Some(crate::VectorSize::Tri),
kind: crate::ScalarKind::Bool,
width: 1,
scalar: crate::Scalar::BOOL,
pointer_space: None,
};
self.get_type_id(local_type.into())
@ -802,18 +795,13 @@ impl Writer {
))
}
fn make_scalar(
&mut self,
id: Word,
kind: crate::ScalarKind,
width: crate::Bytes,
) -> Instruction {
fn make_scalar(&mut self, id: Word, scalar: crate::Scalar) -> Instruction {
use crate::ScalarKind as Sk;
let bits = (width * BITS_PER_BYTE) as u32;
match kind {
let bits = (scalar.width * BITS_PER_BYTE) as u32;
match scalar.kind {
Sk::Sint | Sk::Uint => {
let signedness = if kind == Sk::Sint {
let signedness = if scalar.kind == Sk::Sint {
super::instructions::Signedness::Signed
} else {
super::instructions::Signedness::Unsigned
@ -894,20 +882,17 @@ impl Writer {
let instruction = match local_ty {
LocalType::Value {
vector_size: None,
kind,
width,
scalar,
pointer_space: None,
} => self.make_scalar(id, kind, width),
} => self.make_scalar(id, scalar),
LocalType::Value {
vector_size: Some(size),
kind,
width,
scalar,
pointer_space: None,
} => {
let scalar_id = self.get_type_id(LookupType::Local(LocalType::Value {
vector_size: None,
kind,
width,
scalar,
pointer_space: None,
}));
Instruction::type_vector(id, scalar_id, size)
@ -919,8 +904,7 @@ impl Writer {
} => {
let vector_id = self.get_type_id(LookupType::Local(LocalType::Value {
vector_size: Some(rows),
kind: crate::ScalarKind::Float,
width,
scalar: crate::Scalar::float(width),
pointer_space: None,
}));
Instruction::type_matrix(id, vector_id, columns)
@ -931,14 +915,12 @@ impl Writer {
}
LocalType::Value {
vector_size,
kind,
width,
scalar,
pointer_space: Some(class),
} => {
let type_id = self.get_type_id(LookupType::Local(LocalType::Value {
vector_size,
kind,
width,
scalar,
pointer_space: None,
}));
Instruction::type_pointer(id, class, type_id)
@ -946,8 +928,10 @@ impl Writer {
LocalType::Image(image) => {
let local_type = LocalType::Value {
vector_size: None,
kind: image.sampled_type,
width: 4,
scalar: crate::Scalar {
kind: image.sampled_type,
width: 4,
},
pointer_space: None,
};
let type_id = self.get_type_id(LookupType::Local(local_type));
@ -1060,8 +1044,8 @@ impl Writer {
// These all have TypeLocal representations, so they should have been
// handled by `write_type_declaration_local` above.
crate::TypeInner::Scalar { .. }
| crate::TypeInner::Atomic { .. }
crate::TypeInner::Scalar(_)
| crate::TypeInner::Atomic(_)
| crate::TypeInner::Vector { .. }
| crate::TypeInner::Matrix { .. }
| crate::TypeInner::Pointer { .. }
@ -1151,11 +1135,10 @@ impl Writer {
pub(super) fn get_constant_scalar_with(
&mut self,
value: u8,
kind: crate::ScalarKind,
width: crate::Bytes,
scalar: crate::Scalar,
) -> Result<Word, Error> {
Ok(
self.get_constant_scalar(crate::Literal::new(value, kind, width).ok_or(
self.get_constant_scalar(crate::Literal::new(value, scalar).ok_or(
Error::Validation("Unexpected kind and/or width for Literal"),
)?),
)
@ -1185,8 +1168,7 @@ impl Writer {
}
let type_id = self.get_type_id(LookupType::Local(LocalType::Value {
vector_size: None,
kind: value.scalar_kind(),
width: value.width(),
scalar: value.scalar(),
pointer_space: None,
}));
let instruction = match *value {
@ -1602,8 +1584,8 @@ impl Writer {
// > shader, must be decorated Flat
if class == spirv::StorageClass::Input && stage == crate::ShaderStage::Fragment {
let is_flat = match ir_module.types[ty].inner {
crate::TypeInner::Scalar { kind, .. }
| crate::TypeInner::Vector { kind, .. } => match kind {
crate::TypeInner::Scalar(scalar)
| crate::TypeInner::Vector { scalar, .. } => match scalar.kind {
Sk::Uint | Sk::Sint | Sk::Bool => true,
Sk::Float => false,
},

View File

@ -426,11 +426,11 @@ impl<W: Write> Writer<W> {
/// Adds no trailing or leading whitespace
fn write_value_type(&mut self, module: &Module, inner: &TypeInner) -> BackendResult {
match *inner {
TypeInner::Vector { size, kind, width } => write!(
TypeInner::Vector { size, scalar } => write!(
self.out,
"vec{}<{}>",
back::vector_size_str(size),
scalar_kind_str(kind, width),
scalar_kind_str(scalar),
)?,
TypeInner::Sampler { comparison: false } => {
write!(self.out, "sampler")?;
@ -452,7 +452,7 @@ impl<W: Write> Writer<W> {
Ic::Sampled { kind, multi } => (
"",
if multi { "multisampled_" } else { "" },
scalar_kind_str(kind, 4),
scalar_kind_str(crate::Scalar { kind, width: 4 }),
"",
),
Ic::Depth { multi } => {
@ -481,11 +481,11 @@ impl<W: Write> Writer<W> {
write!(self.out, "<{format_str}{storage_str}>")?;
}
}
TypeInner::Scalar { kind, width } => {
write!(self.out, "{}", scalar_kind_str(kind, width))?;
TypeInner::Scalar(scalar) => {
write!(self.out, "{}", scalar_kind_str(scalar))?;
}
TypeInner::Atomic { kind, width } => {
write!(self.out, "atomic<{}>", scalar_kind_str(kind, width))?;
TypeInner::Atomic(scalar) => {
write!(self.out, "atomic<{}>", scalar_kind_str(scalar))?;
}
TypeInner::Array {
base,
@ -524,14 +524,14 @@ impl<W: Write> Writer<W> {
TypeInner::Matrix {
columns,
rows,
width: _,
width,
} => {
write!(
self.out,
//TODO: Can matrix be other than f32?
"mat{}x{}<f32>",
"mat{}x{}<{}>",
back::vector_size_str(columns),
back::vector_size_str(rows),
scalar_kind_str(crate::Scalar::float(width))
)?;
}
TypeInner::Pointer { base, space } => {
@ -552,13 +552,12 @@ impl<W: Write> Writer<W> {
}
TypeInner::ValuePointer {
size: None,
kind,
width,
scalar,
space,
} => {
let (address, maybe_access) = address_space_str(space);
if let Some(space) = address {
write!(self.out, "ptr<{}, {}", space, scalar_kind_str(kind, width))?;
write!(self.out, "ptr<{}, {}", space, scalar_kind_str(scalar))?;
if let Some(access) = maybe_access {
write!(self.out, ", {access}")?;
}
@ -571,8 +570,7 @@ impl<W: Write> Writer<W> {
}
TypeInner::ValuePointer {
size: Some(size),
kind,
width,
scalar,
space,
} => {
let (address, maybe_access) = address_space_str(space);
@ -582,7 +580,7 @@ impl<W: Write> Writer<W> {
"ptr<{}, vec{}<{}>",
space,
back::vector_size_str(size),
scalar_kind_str(kind, width)
scalar_kind_str(scalar)
)?;
if let Some(access) = maybe_access {
write!(self.out, ", {access}")?;
@ -1414,7 +1412,11 @@ impl<W: Write> Writer<W> {
width,
..
} => {
let scalar_kind_str = scalar_kind_str(kind, convert.unwrap_or(width));
let scalar = crate::Scalar {
kind,
width: convert.unwrap_or(width),
};
let scalar_kind_str = scalar_kind_str(scalar);
write!(
self.out,
"mat{}x{}<{}>",
@ -1423,17 +1425,28 @@ impl<W: Write> Writer<W> {
scalar_kind_str
)?;
}
TypeInner::Vector { size, width, .. } => {
TypeInner::Vector {
size,
scalar: crate::Scalar { width, .. },
} => {
let scalar = crate::Scalar {
kind,
width: convert.unwrap_or(width),
};
let vector_size_str = back::vector_size_str(size);
let scalar_kind_str = scalar_kind_str(kind, convert.unwrap_or(width));
let scalar_kind_str = scalar_kind_str(scalar);
if convert.is_some() {
write!(self.out, "vec{vector_size_str}<{scalar_kind_str}>")?;
} else {
write!(self.out, "bitcast<vec{vector_size_str}<{scalar_kind_str}>>")?;
}
}
TypeInner::Scalar { width, .. } => {
let scalar_kind_str = scalar_kind_str(kind, convert.unwrap_or(width));
TypeInner::Scalar(crate::Scalar { width, .. }) => {
let scalar = crate::Scalar {
kind,
width: convert.unwrap_or(width),
};
let scalar_kind_str = scalar_kind_str(scalar);
if convert.is_some() {
write!(self.out, "{scalar_kind_str}")?
} else {
@ -1783,15 +1796,31 @@ const fn image_dimension_str(dim: crate::ImageDimension) -> &'static str {
}
}
const fn scalar_kind_str(kind: crate::ScalarKind, width: u8) -> &'static str {
const fn scalar_kind_str(scalar: crate::Scalar) -> &'static str {
use crate::Scalar;
use crate::ScalarKind as Sk;
match (kind, width) {
(Sk::Float, 8) => "f64",
(Sk::Float, 4) => "f32",
(Sk::Sint, 4) => "i32",
(Sk::Uint, 4) => "u32",
(Sk::Bool, 1) => "bool",
match scalar {
Scalar {
kind: Sk::Float,
width: 8,
} => "f64",
Scalar {
kind: Sk::Float,
width: 4,
} => "f32",
Scalar {
kind: Sk::Sint,
width: 4,
} => "i32",
Scalar {
kind: Sk::Uint,
width: 4,
} => "u32",
Scalar {
kind: Sk::Bool,
width: 1,
} => "bool",
_ => unreachable!(),
}
}

View File

@ -1,8 +1,7 @@
use super::{HandleMap, HandleSet, ModuleMap};
use crate::arena::{Arena, Handle, UniqueArena};
use crate::arena::{Arena, Handle};
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.
@ -21,34 +20,51 @@ pub struct ExpressionTracer<'tracer> {
/// 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>,
)>,
/// The used set for the module's `const_expressions` arena.
///
/// If `None`, we are already tracing the constant expressions,
/// and `expressions_used` already refers to their handle set.
pub const_expressions_used: Option<&'tracer mut HandleSet<crate::Expression>>,
}
impl<'tracer> ExpressionTracer<'tracer> {
pub fn trace_expression(&mut self, expr: Handle<crate::Expression>) {
/// Propagate usage through `self.expressions`, starting with `self.expressions_used`.
///
/// Treat `self.expressions_used` as the initial set of "known
/// live" expressions, and follow through to identify all
/// transitively used expressions.
///
/// Mark types, constants, and constant expressions used directly
/// by `self.expressions` as used. Items used indirectly are not
/// marked.
///
/// [fe]: crate::Function::expressions
/// [ce]: crate::Module::const_expressions
pub fn trace_expressions(&mut self) {
log::trace!(
"entering trace_expression of {}",
if self.const_expressions.is_some() {
if self.const_expressions_used.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) {
// We don't need recursion or a work list. Because an
// expression may only refer to other expressions that precede
// it in the arena, it suffices to make a single pass over the
// arena from back to front, marking the referents of used
// expressions as used themselves.
for (handle, expr) in self.expressions.iter().rev() {
// If this expression isn't used, it doesn't matter what it uses.
if !self.expressions_used.contains(handle) {
continue;
}
log::trace!("tracing new expression {:?}", expr);
use crate::Expression as Ex;
match self.expressions[expr] {
match *expr {
// Expressions that do not contain handles that need to be traced.
Ex::Literal(_)
| Ex::FunctionArgument(_)
@ -59,24 +75,34 @@ impl<'tracer> ExpressionTracer<'tracer> {
Ex::Constant(handle) => {
self.constants_used.insert(handle);
let constant = &self.constants[handle];
self.trace_type(constant.ty);
self.trace_const_expression(constant.init);
// Constants and expressions are mutually recursive, which
// complicates our nice one-pass algorithm. However, since
// constants don't refer to each other, we can get around
// this by looking *through* each constant and marking its
// initializer as used. Since `expr` refers to the constant,
// and the constant refers to the initializer, it must
// precede `expr` in the arena.
let init = self.constants[handle].init;
match self.const_expressions_used {
Some(ref mut used) => used.insert(init),
None => self.expressions_used.insert(init),
}
}
Ex::ZeroValue(ty) => self.trace_type(ty),
Ex::ZeroValue(ty) => self.types_used.insert(ty),
Ex::Compose { ty, ref components } => {
self.trace_type(ty);
work_list.extend(components);
self.types_used.insert(ty);
self.expressions_used
.insert_iter(components.iter().cloned());
}
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::Access { base, index } => self.expressions_used.insert_iter([base, index]),
Ex::AccessIndex { base, index: _ } => self.expressions_used.insert(base),
Ex::Splat { size: _, value } => self.expressions_used.insert(value),
Ex::Swizzle {
size: _,
vector,
pattern: _,
} => work_list.push(vector),
Ex::Load { pointer } => work_list.push(pointer),
} => self.expressions_used.insert(vector),
Ex::Load { pointer } => self.expressions_used.insert(pointer),
Ex::ImageSample {
image,
sampler,
@ -87,20 +113,20 @@ impl<'tracer> ExpressionTracer<'tracer> {
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);
self.expressions_used
.insert_iter([image, sampler, coordinate]);
self.expressions_used.insert_iter(array_index);
match self.const_expressions_used {
Some(ref mut used) => used.insert_iter(offset),
None => self.expressions_used.insert_iter(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]),
Sl::Exact(expr) | Sl::Bias(expr) => self.expressions_used.insert(expr),
Sl::Gradient { x, y } => self.expressions_used.insert_iter([x, y]),
}
work_list.extend(depth_ref);
self.expressions_used.insert_iter(depth_ref);
}
Ex::ImageLoad {
image,
@ -109,33 +135,37 @@ impl<'tracer> ExpressionTracer<'tracer> {
sample,
level,
} => {
work_list.push(image);
work_list.push(coordinate);
work_list.extend(array_index);
work_list.extend(sample);
work_list.extend(level);
self.expressions_used.insert(image);
self.expressions_used.insert(coordinate);
self.expressions_used.insert_iter(array_index);
self.expressions_used.insert_iter(sample);
self.expressions_used.insert_iter(level);
}
Ex::ImageQuery { image, ref query } => {
work_list.push(image);
self.expressions_used.insert(image);
use crate::ImageQuery as Iq;
match *query {
Iq::Size { level } => work_list.extend(level),
Iq::Size { level } => self.expressions_used.insert_iter(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::Unary { op: _, expr } => self.expressions_used.insert(expr),
Ex::Binary { op: _, left, right } => {
self.expressions_used.insert_iter([left, right]);
}
Ex::Select {
condition,
accept,
reject,
} => work_list.extend([condition, accept, reject]),
} => self
.expressions_used
.insert_iter([condition, accept, reject]),
Ex::Derivative {
axis: _,
ctrl: _,
expr,
} => work_list.push(expr),
Ex::Relational { fun: _, argument } => work_list.push(argument),
} => self.expressions_used.insert(expr),
Ex::Relational { fun: _, argument } => self.expressions_used.insert(argument),
Ex::Math {
fun: _,
arg,
@ -143,61 +173,26 @@ impl<'tracer> ExpressionTracer<'tracer> {
arg2,
arg3,
} => {
work_list.push(arg);
work_list.extend(arg1);
work_list.extend(arg2);
work_list.extend(arg3);
self.expressions_used.insert(arg);
self.expressions_used.insert_iter(arg1);
self.expressions_used.insert_iter(arg2);
self.expressions_used.insert_iter(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),
} => self.expressions_used.insert(expr),
Ex::AtomicResult { ty, comparison: _ } => self.types_used.insert(ty),
Ex::WorkGroupUniformLoadResult { ty } => self.types_used.insert(ty),
Ex::ArrayLength(expr) => self.expressions_used.insert(expr),
Ex::RayQueryGetIntersection {
query,
committed: _,
} => work_list.push(query),
} => self.expressions_used.insert(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 {

View File

@ -1,10 +1,9 @@
use super::handle_set_map::HandleSet;
use super::{FunctionMap, ModuleMap};
use crate::arena::Handle;
pub struct FunctionTracer<'a> {
pub module: &'a crate::Module,
pub function: &'a crate::Function,
pub constants: &'a crate::Arena<crate::Constant>,
pub types_used: &'a mut HandleSet<crate::Type>,
pub constants_used: &'a mut HandleSet<crate::Constant>,
@ -17,57 +16,43 @@ pub struct FunctionTracer<'a> {
impl<'a> FunctionTracer<'a> {
pub fn trace(&mut self) {
for argument in self.function.arguments.iter() {
self.trace_type(argument.ty);
self.types_used.insert(argument.ty);
}
if let Some(ref result) = self.function.result {
self.trace_type(result.ty);
self.types_used.insert(result.ty);
}
for (_, local) in self.function.local_variables.iter() {
self.trace_type(local.ty);
self.types_used.insert(local.ty);
if let Some(init) = local.init {
self.trace_expression(init);
self.expressions_used.insert(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);
for (&value, _name) in &self.function.named_expressions {
self.expressions_used.insert(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);
}
fn as_type(&mut self) -> super::types::TypeTracer {
super::types::TypeTracer {
types: &self.module.types,
types_used: self.types_used,
}
// Given that `trace_block` has marked the expressions used
// directly by statements, walk the arena to find all
// expressions used, directly or indirectly.
self.as_expression().trace_expressions();
}
fn as_expression(&mut self) -> super::expressions::ExpressionTracer {
super::expressions::ExpressionTracer {
types: &self.module.types,
constants: &self.module.constants,
constants: self.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,
)),
const_expressions_used: Some(&mut self.const_expressions_used),
}
}
}

View File

@ -26,13 +26,23 @@ impl<T> HandleSet<T> {
}
/// 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 {
pub fn insert(&mut self, handle: Handle<T>) {
// Note that, oddly, `Handle::index` does not return a 1-based
// `Index`, but rather a zero-based `usize`.
self.members.insert(handle.index())
self.members.insert(handle.index());
}
/// Add handles from `iter` to the set.
pub fn insert_iter(&mut self, iter: impl IntoIterator<Item = Handle<T>>) {
for handle in iter {
self.insert(handle);
}
}
pub fn contains(&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.contains(handle.index())
}
}
@ -148,6 +158,8 @@ impl<T: 'static> HandleMap<T> {
// Build a zero-based end-exclusive range, given one-based handle indices.
compacted = first1.get() - 1..last1.get();
} else {
// The range contains only a single live handle, which
// we identified with the first `find_map` call.
compacted = first1.get() - 1..first1.get();
}
} else {

View File

@ -36,9 +36,9 @@ pub fn compact(module: &mut crate::Module) {
{
for (_, global) in module.global_variables.iter() {
log::trace!("tracing global {:?}", global.name);
module_tracer.as_type().trace_type(global.ty);
module_tracer.types_used.insert(global.ty);
if let Some(init) = global.init {
module_tracer.as_const_expression().trace_expression(init);
module_tracer.const_expressions_used.insert(init);
}
}
}
@ -50,25 +50,23 @@ pub fn compact(module: &mut crate::Module) {
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);
module_tracer.const_expressions_used.insert(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.
// expressions each function uses, and produce maps for each
// function from pre-compaction to post-compaction expression
// 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);
let mut function_tracer = module_tracer.as_function(f);
function_tracer.trace();
FunctionMap::from(function_tracer)
})
@ -81,12 +79,30 @@ pub fn compact(module: &mut crate::Module) {
.iter()
.map(|e| {
log::trace!("tracing entry point {:?}", e.function.name);
let mut used = module_tracer.enter_function(&e.function);
let mut used = module_tracer.as_function(&e.function);
used.trace();
FunctionMap::from(used)
})
.collect();
// Given that the above steps have marked all the constant
// expressions used directly by globals, constants, functions, and
// entry points, walk the constant expression arena to find all
// constant expressions used, directly or indirectly.
module_tracer.as_const_expression().trace_expressions();
// Constants' initializers are taken care of already, because
// expression tracing sees through constants. But we still need to
// note type usage.
for (handle, constant) in module.constants.iter() {
if module_tracer.constants_used.contains(handle) {
module_tracer.types_used.insert(constant.ty);
}
}
// Propagate usage through types.
module_tracer.as_type().trace_types();
// 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
@ -189,15 +205,14 @@ impl<'module> ModuleTracer<'module> {
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);
self.types_used.insert(ray_desc);
}
if let Some(ray_intersection) = *ray_intersection {
type_tracer.trace_type(ray_intersection);
self.types_used.insert(ray_intersection);
}
for (_, &handle) in predeclared_types {
type_tracer.trace_type(handle);
self.types_used.insert(handle);
}
}
@ -210,24 +225,22 @@ impl<'module> ModuleTracer<'module> {
fn as_const_expression(&mut self) -> expressions::ExpressionTracer {
expressions::ExpressionTracer {
types: &self.module.types,
constants: &self.module.constants,
expressions: &self.module.const_expressions,
constants: &self.module.constants,
types_used: &mut self.types_used,
constants_used: &mut self.constants_used,
expressions_used: &mut self.const_expressions_used,
const_expressions: None,
const_expressions_used: None,
}
}
pub fn enter_function<'tracer>(
pub fn as_function<'tracer>(
&'tracer mut self,
function: &'tracer crate::Function,
) -> FunctionTracer<'tracer> {
FunctionTracer {
module: self.module,
function,
constants: &self.module.constants,
types_used: &mut self.types_used,
constants_used: &mut self.constants_used,
const_expressions_used: &mut self.const_expressions_used,

View File

@ -22,7 +22,7 @@ impl FunctionTracer<'_> {
ref accept,
ref reject,
} => {
self.trace_expression(condition);
self.expressions_used.insert(condition);
worklist.push(accept);
worklist.push(reject);
}
@ -30,7 +30,7 @@ impl FunctionTracer<'_> {
selector,
ref cases,
} => {
self.trace_expression(selector);
self.expressions_used.insert(selector);
for case in cases {
worklist.push(&case.body);
}
@ -41,15 +41,17 @@ impl FunctionTracer<'_> {
break_if,
} => {
if let Some(break_if) = break_if {
self.trace_expression(break_if);
self.expressions_used.insert(break_if);
}
worklist.push(body);
worklist.push(continuing);
}
St::Return { value: Some(value) } => self.trace_expression(value),
St::Return { value: Some(value) } => {
self.expressions_used.insert(value);
}
St::Store { pointer, value } => {
self.trace_expression(pointer);
self.trace_expression(value);
self.expressions_used.insert(pointer);
self.expressions_used.insert(value);
}
St::ImageStore {
image,
@ -57,12 +59,12 @@ impl FunctionTracer<'_> {
array_index,
value,
} => {
self.trace_expression(image);
self.trace_expression(coordinate);
self.expressions_used.insert(image);
self.expressions_used.insert(coordinate);
if let Some(array_index) = array_index {
self.trace_expression(array_index);
self.expressions_used.insert(array_index);
}
self.trace_expression(value);
self.expressions_used.insert(value);
}
St::Atomic {
pointer,
@ -70,14 +72,14 @@ impl FunctionTracer<'_> {
value,
result,
} => {
self.trace_expression(pointer);
self.expressions_used.insert(pointer);
self.trace_atomic_function(fun);
self.trace_expression(value);
self.trace_expression(result);
self.expressions_used.insert(value);
self.expressions_used.insert(result);
}
St::WorkGroupUniformLoad { pointer, result } => {
self.trace_expression(pointer);
self.trace_expression(result);
self.expressions_used.insert(pointer);
self.expressions_used.insert(result);
}
St::Call {
function: _,
@ -85,14 +87,14 @@ impl FunctionTracer<'_> {
result,
} => {
for expr in arguments {
self.trace_expression(*expr);
self.expressions_used.insert(*expr);
}
if let Some(result) = result {
self.trace_expression(result);
self.expressions_used.insert(result);
}
}
St::RayQuery { query, ref fun } => {
self.trace_expression(query);
self.expressions_used.insert(query);
self.trace_ray_query_function(fun);
}
@ -112,7 +114,9 @@ impl FunctionTracer<'_> {
match *fun {
Af::Exchange {
compare: Some(expr),
} => self.trace_expression(expr),
} => {
self.expressions_used.insert(expr);
}
Af::Exchange { compare: None }
| Af::Add
| Af::Subtract
@ -131,10 +135,12 @@ impl FunctionTracer<'_> {
acceleration_structure,
descriptor,
} => {
self.trace_expression(acceleration_structure);
self.trace_expression(descriptor);
self.expressions_used.insert(acceleration_structure);
self.expressions_used.insert(descriptor);
}
Qf::Proceed { result } => {
self.expressions_used.insert(result);
}
Qf::Proceed { result } => self.trace_expression(result),
Qf::Terminate => {}
}
}

View File

@ -7,16 +7,25 @@ pub struct TypeTracer<'a> {
}
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) {
/// Propagate usage through `self.types`, starting with `self.types_used`.
///
/// Treat `self.types_used` as the initial set of "known
/// live" types, and follow through to identify all
/// transitively used types.
pub fn trace_types(&mut self) {
// We don't need recursion or a work list. Because an
// expression may only refer to other expressions that precede
// it in the arena, it suffices to make a single pass over the
// arena from back to front, marking the referents of used
// expressions as used themselves.
for (handle, ty) in self.types.iter().rev() {
// If this type isn't used, it doesn't matter what it uses.
if !self.types_used.contains(handle) {
continue;
}
use crate::TypeInner as Ti;
match self.types[ty].inner {
match ty.inner {
// Types that do not contain handles.
Ti::Scalar { .. }
| Ti::Vector { .. }
@ -29,19 +38,19 @@ impl<'a> TypeTracer<'a> {
| Ti::RayQuery => {}
// Types that do contain handles.
Ti::Pointer { base, space: _ } => work_list.push(base),
Ti::Array {
Ti::Pointer { base, space: _ }
| Ti::Array {
base,
size: _,
stride: _,
} => work_list.push(base),
}
| Ti::BindingArray { base, size: _ } => self.types_used.insert(base),
Ti::Struct {
ref members,
span: _,
} => {
work_list.extend(members.iter().map(|m| m.ty));
self.types_used.insert_iter(members.iter().map(|m| m.ty));
}
Ti::BindingArray { base, size: _ } => work_list.push(base),
}
}
}
@ -54,10 +63,10 @@ impl ModuleMap {
use crate::TypeInner as Ti;
match ty.inner {
// Types that do not contain handles.
Ti::Scalar { .. }
Ti::Scalar(_)
| Ti::Vector { .. }
| Ti::Matrix { .. }
| Ti::Atomic { .. }
| Ti::Atomic(_)
| Ti::ValuePointer { .. }
| Ti::Image { .. }
| Ti::Sampler { .. }

View File

@ -9,7 +9,7 @@ use super::{
use crate::{
BinaryOperator, DerivativeAxis as Axis, DerivativeControl as Ctrl, Expression, Handle,
ImageClass, ImageDimension as Dim, ImageQuery, MathFunction, Module, RelationalFunction,
SampleLevel, ScalarKind as Sk, Span, Type, TypeInner, UnaryOperator, VectorSize,
SampleLevel, Scalar, ScalarKind as Sk, Span, Type, TypeInner, UnaryOperator, VectorSize,
};
impl crate::ScalarKind {
@ -54,18 +54,17 @@ impl Module {
}
const fn make_coords_arg(number_of_components: usize, kind: Sk) -> TypeInner {
let width = 4;
let scalar = Scalar { kind, width: 4 };
match number_of_components {
1 => TypeInner::Scalar { kind, width },
1 => TypeInner::Scalar(scalar),
_ => TypeInner::Vector {
size: match number_of_components {
2 => VectorSize::Bi,
3 => VectorSize::Tri,
_ => VectorSize::Quad,
},
kind,
width,
scalar,
},
}
}
@ -98,7 +97,6 @@ pub fn inject_builtin(
inject_double_builtin(declaration, module, name)
}
let width = 4;
match name {
"texture"
| "textureGrad"
@ -235,18 +233,12 @@ pub fn inject_builtin(
let mut args = vec![image, vector];
if num_coords == 5 {
args.push(TypeInner::Scalar {
kind: Sk::Float,
width,
});
args.push(TypeInner::Scalar(Scalar::F32));
}
match level_type {
TextureLevelType::Lod => {
args.push(TypeInner::Scalar {
kind: Sk::Float,
width,
});
args.push(TypeInner::Scalar(Scalar::F32));
}
TextureLevelType::Grad => {
args.push(make_coords_arg(num_coords_from_dim, Sk::Float));
@ -260,10 +252,7 @@ pub fn inject_builtin(
}
if bias {
args.push(TypeInner::Scalar {
kind: Sk::Float,
width,
});
args.push(TypeInner::Scalar(Scalar::F32));
}
declaration
@ -290,10 +279,7 @@ pub fn inject_builtin(
let mut args = vec![image];
if !multi {
args.push(TypeInner::Scalar {
kind: Sk::Sint,
width,
})
args.push(TypeInner::Scalar(Scalar::I32))
}
declaration
@ -323,14 +309,7 @@ pub fn inject_builtin(
let dim_value = image_dims_to_coords_size(dim);
let coordinates = make_coords_arg(dim_value + arrayed as usize, Sk::Sint);
let mut args = vec![
image,
coordinates,
TypeInner::Scalar {
kind: Sk::Sint,
width,
},
];
let mut args = vec![image, coordinates, TypeInner::Scalar(Scalar::I32)];
if offset {
args.push(make_coords_arg(dim_value, Sk::Sint));
@ -441,8 +420,7 @@ pub fn inject_builtin(
coordinates,
TypeInner::Vector {
size: VectorSize::Quad,
kind,
width,
scalar: Scalar { kind, width: 4 },
},
];
@ -464,7 +442,6 @@ fn inject_standard_builtins(
module: &mut Module,
name: &str,
) {
let width = 4;
match name {
"sampler1D" | "sampler1DArray" | "sampler2D" | "sampler2DArray" | "sampler2DMS"
| "sampler2DMSArray" | "sampler3D" | "samplerCube" | "samplerCubeArray" => {
@ -544,12 +521,12 @@ fn inject_standard_builtins(
0b10 => Some(VectorSize::Tri),
_ => Some(VectorSize::Quad),
};
let kind = Sk::Float;
let scalar = Scalar::F32;
declaration.overloads.push(module.add_builtin(
vec![match size {
Some(size) => TypeInner::Vector { size, kind, width },
None => TypeInner::Scalar { kind, width },
Some(size) => TypeInner::Vector { size, scalar },
None => TypeInner::Scalar(scalar),
}],
match name {
"sin" => MacroCall::MathFunction(MathFunction::Sin),
@ -595,15 +572,15 @@ fn inject_standard_builtins(
0b10 => Some(VectorSize::Tri),
_ => Some(VectorSize::Quad),
};
let kind = match name {
"intBitsToFloat" => Sk::Sint,
_ => Sk::Uint,
let scalar = match name {
"intBitsToFloat" => Scalar::I32,
_ => Scalar::U32,
};
declaration.overloads.push(module.add_builtin(
vec![match size {
Some(size) => TypeInner::Vector { size, kind, width },
None => TypeInner::Scalar { kind, width },
Some(size) => TypeInner::Vector { size, scalar },
None => TypeInner::Scalar(scalar),
}],
MacroCall::BitCast(Sk::Float),
))
@ -619,10 +596,10 @@ fn inject_standard_builtins(
0b10 => Some(VectorSize::Tri),
_ => Some(VectorSize::Quad),
};
let kind = Sk::Float;
let scalar = Scalar::F32;
let ty = || match size {
Some(size) => TypeInner::Vector { size, kind, width },
None => TypeInner::Scalar { kind, width },
Some(size) => TypeInner::Vector { size, scalar },
None => TypeInner::Scalar(scalar),
};
declaration.overloads.push(
@ -642,14 +619,14 @@ fn inject_standard_builtins(
0b10 => Some(VectorSize::Tri),
_ => Some(VectorSize::Quad),
};
let kind = match bits >> 2 {
0b0 => Sk::Float,
_ => Sk::Sint,
let scalar = match bits >> 2 {
0b0 => Scalar::F32,
_ => Scalar::I32,
};
let args = vec![match size {
Some(size) => TypeInner::Vector { size, kind, width },
None => TypeInner::Scalar { kind, width },
Some(size) => TypeInner::Vector { size, scalar },
None => TypeInner::Scalar(scalar),
}];
declaration.overloads.push(module.add_builtin(
@ -684,9 +661,9 @@ fn inject_standard_builtins(
// bit 0 - int/uint
// bit 1 through 2 - dims
for bits in 0..0b1000 {
let kind = match bits & 0b1 {
0b0 => Sk::Sint,
_ => Sk::Uint,
let scalar = match bits & 0b1 {
0b0 => Scalar::I32,
_ => Scalar::U32,
};
let size = match bits >> 1 {
0b00 => None,
@ -696,39 +673,27 @@ fn inject_standard_builtins(
};
let ty = || match size {
Some(size) => TypeInner::Vector { size, kind, width },
None => TypeInner::Scalar { kind, width },
Some(size) => TypeInner::Vector { size, scalar },
None => TypeInner::Scalar(scalar),
};
let mut args = vec![ty()];
match fun {
MathFunction::ExtractBits => {
args.push(TypeInner::Scalar {
kind: Sk::Sint,
width: 4,
});
args.push(TypeInner::Scalar {
kind: Sk::Sint,
width: 4,
});
args.push(TypeInner::Scalar(Scalar::I32));
args.push(TypeInner::Scalar(Scalar::I32));
}
MathFunction::InsertBits => {
args.push(ty());
args.push(TypeInner::Scalar {
kind: Sk::Sint,
width: 4,
});
args.push(TypeInner::Scalar {
kind: Sk::Sint,
width: 4,
});
args.push(TypeInner::Scalar(Scalar::I32));
args.push(TypeInner::Scalar(Scalar::I32));
}
_ => {}
}
// we need to cast the return type of findLsb / findMsb
let mc = if kind == Sk::Uint {
let mc = if scalar.kind == Sk::Uint {
match mc {
MacroCall::MathFunction(MathFunction::FindLsb) => MacroCall::FindLsbUint,
MacroCall::MathFunction(MathFunction::FindMsb) => MacroCall::FindMsbUint,
@ -754,15 +719,13 @@ fn inject_standard_builtins(
let ty = match fun {
MathFunction::Pack4x8snorm | MathFunction::Pack4x8unorm => TypeInner::Vector {
size: crate::VectorSize::Quad,
kind: Sk::Float,
width: 4,
scalar: Scalar::F32,
},
MathFunction::Pack2x16unorm
| MathFunction::Pack2x16snorm
| MathFunction::Pack2x16float => TypeInner::Vector {
size: crate::VectorSize::Bi,
kind: Sk::Float,
width: 4,
scalar: Scalar::F32,
},
_ => unreachable!(),
};
@ -784,10 +747,7 @@ fn inject_standard_builtins(
_ => unreachable!(),
};
let args = vec![TypeInner::Scalar {
kind: Sk::Uint,
width: 4,
}];
let args = vec![TypeInner::Scalar(Scalar::U32)];
declaration
.overloads
@ -808,10 +768,10 @@ fn inject_standard_builtins(
0b10 => Some(VectorSize::Tri),
_ => Some(VectorSize::Quad),
};
let kind = Sk::Float;
let scalar = Scalar::F32;
let ty = || match size {
Some(size) => TypeInner::Vector { size, kind, width },
None => TypeInner::Scalar { kind, width },
Some(size) => TypeInner::Vector { size, scalar },
None => TypeInner::Scalar(scalar),
};
let mut args = vec![ty()];
@ -837,8 +797,7 @@ fn inject_standard_builtins(
let args = vec![TypeInner::Vector {
size,
kind: Sk::Bool,
width: crate::BOOL_WIDTH,
scalar: Scalar::BOOL,
}];
let fun = match name {
@ -853,19 +812,19 @@ fn inject_standard_builtins(
}
"lessThan" | "greaterThan" | "lessThanEqual" | "greaterThanEqual" => {
for bits in 0..0b1001 {
let (size, kind) = match bits {
0b0000 => (VectorSize::Bi, Sk::Float),
0b0001 => (VectorSize::Tri, Sk::Float),
0b0010 => (VectorSize::Quad, Sk::Float),
0b0011 => (VectorSize::Bi, Sk::Sint),
0b0100 => (VectorSize::Tri, Sk::Sint),
0b0101 => (VectorSize::Quad, Sk::Sint),
0b0110 => (VectorSize::Bi, Sk::Uint),
0b0111 => (VectorSize::Tri, Sk::Uint),
_ => (VectorSize::Quad, Sk::Uint),
let (size, scalar) = match bits {
0b0000 => (VectorSize::Bi, Scalar::F32),
0b0001 => (VectorSize::Tri, Scalar::F32),
0b0010 => (VectorSize::Quad, Scalar::F32),
0b0011 => (VectorSize::Bi, Scalar::I32),
0b0100 => (VectorSize::Tri, Scalar::I32),
0b0101 => (VectorSize::Quad, Scalar::I32),
0b0110 => (VectorSize::Bi, Scalar::U32),
0b0111 => (VectorSize::Tri, Scalar::U32),
_ => (VectorSize::Quad, Scalar::U32),
};
let ty = || TypeInner::Vector { size, kind, width };
let ty = || TypeInner::Vector { size, scalar };
let args = vec![ty(), ty()];
let fun = MacroCall::Binary(match name {
@ -881,28 +840,22 @@ fn inject_standard_builtins(
}
"equal" | "notEqual" => {
for bits in 0..0b1100 {
let (size, kind) = match bits {
0b0000 => (VectorSize::Bi, Sk::Float),
0b0001 => (VectorSize::Tri, Sk::Float),
0b0010 => (VectorSize::Quad, Sk::Float),
0b0011 => (VectorSize::Bi, Sk::Sint),
0b0100 => (VectorSize::Tri, Sk::Sint),
0b0101 => (VectorSize::Quad, Sk::Sint),
0b0110 => (VectorSize::Bi, Sk::Uint),
0b0111 => (VectorSize::Tri, Sk::Uint),
0b1000 => (VectorSize::Quad, Sk::Uint),
0b1001 => (VectorSize::Bi, Sk::Bool),
0b1010 => (VectorSize::Tri, Sk::Bool),
_ => (VectorSize::Quad, Sk::Bool),
let (size, scalar) = match bits {
0b0000 => (VectorSize::Bi, Scalar::F32),
0b0001 => (VectorSize::Tri, Scalar::F32),
0b0010 => (VectorSize::Quad, Scalar::F32),
0b0011 => (VectorSize::Bi, Scalar::I32),
0b0100 => (VectorSize::Tri, Scalar::I32),
0b0101 => (VectorSize::Quad, Scalar::I32),
0b0110 => (VectorSize::Bi, Scalar::U32),
0b0111 => (VectorSize::Tri, Scalar::U32),
0b1000 => (VectorSize::Quad, Scalar::U32),
0b1001 => (VectorSize::Bi, Scalar::BOOL),
0b1010 => (VectorSize::Tri, Scalar::BOOL),
_ => (VectorSize::Quad, Scalar::BOOL),
};
let width = if let Sk::Bool = kind {
crate::BOOL_WIDTH
} else {
width
};
let ty = || TypeInner::Vector { size, kind, width };
let ty = || TypeInner::Vector { size, scalar };
let args = vec![ty(), ty()];
let fun = MacroCall::Binary(match name {
@ -919,10 +872,10 @@ fn inject_standard_builtins(
// bit 0 through 1 - scalar kind
// bit 2 through 4 - dims
for bits in 0..0b11100 {
let kind = match bits & 0b11 {
0b00 => Sk::Float,
0b01 => Sk::Sint,
0b10 => Sk::Uint,
let scalar = match bits & 0b11 {
0b00 => Scalar::F32,
0b01 => Scalar::I32,
0b10 => Scalar::U32,
_ => continue,
};
let (size, second_size) = match bits >> 2 {
@ -937,12 +890,12 @@ fn inject_standard_builtins(
let args = vec![
match size {
Some(size) => TypeInner::Vector { size, kind, width },
None => TypeInner::Scalar { kind, width },
Some(size) => TypeInner::Vector { size, scalar },
None => TypeInner::Scalar(scalar),
},
match second_size {
Some(size) => TypeInner::Vector { size, kind, width },
None => TypeInner::Scalar { kind, width },
Some(size) => TypeInner::Vector { size, scalar },
None => TypeInner::Scalar(scalar),
},
];
@ -969,25 +922,25 @@ fn inject_standard_builtins(
0b10 => Some(VectorSize::Quad),
_ => None,
};
let (kind, splatted, boolean) = match bits >> 2 {
0b000 => (Sk::Sint, false, true),
0b001 => (Sk::Uint, false, true),
0b010 => (Sk::Float, false, true),
0b011 => (Sk::Float, false, false),
_ => (Sk::Float, true, false),
let (scalar, splatted, boolean) = match bits >> 2 {
0b000 => (Scalar::I32, false, true),
0b001 => (Scalar::U32, false, true),
0b010 => (Scalar::F32, false, true),
0b011 => (Scalar::F32, false, false),
_ => (Scalar::F32, true, false),
};
let ty = |kind, width| match size {
Some(size) => TypeInner::Vector { size, kind, width },
None => TypeInner::Scalar { kind, width },
let ty = |scalar| match size {
Some(size) => TypeInner::Vector { size, scalar },
None => TypeInner::Scalar(scalar),
};
let args = vec![
ty(kind, width),
ty(kind, width),
ty(scalar),
ty(scalar),
match (boolean, splatted) {
(true, _) => ty(Sk::Bool, crate::BOOL_WIDTH),
(_, false) => TypeInner::Scalar { kind, width },
_ => ty(kind, width),
(true, _) => ty(Scalar::BOOL),
(_, false) => TypeInner::Scalar(scalar),
_ => ty(scalar),
},
];
@ -1009,10 +962,10 @@ fn inject_standard_builtins(
// 0b11010 is the last element since splatted single elements
// were already added
for bits in 0..0b11011 {
let kind = match bits & 0b11 {
0b00 => Sk::Float,
0b01 => Sk::Sint,
0b10 => Sk::Uint,
let scalar = match bits & 0b11 {
0b00 => Scalar::F32,
0b01 => Scalar::I32,
0b10 => Scalar::U32,
_ => continue,
};
let size = match (bits >> 2) & 0b11 {
@ -1024,11 +977,11 @@ fn inject_standard_builtins(
let splatted = bits & 0b10000 == 0b10000;
let base_ty = || match size {
Some(size) => TypeInner::Vector { size, kind, width },
None => TypeInner::Scalar { kind, width },
Some(size) => TypeInner::Vector { size, scalar },
None => TypeInner::Scalar(scalar),
};
let limit_ty = || match splatted {
true => TypeInner::Scalar { kind, width },
true => TypeInner::Scalar(scalar),
false => base_ty(),
};
@ -1049,7 +1002,6 @@ fn inject_standard_builtins(
/// Injects the builtins into declaration that need doubles
fn inject_double_builtin(declaration: &mut FunctionDeclaration, module: &mut Module, name: &str) {
let width = 8;
match name {
"abs" | "sign" => {
// bits layout
@ -1061,11 +1013,11 @@ fn inject_double_builtin(declaration: &mut FunctionDeclaration, module: &mut Mod
0b10 => Some(VectorSize::Tri),
_ => Some(VectorSize::Quad),
};
let kind = Sk::Float;
let scalar = Scalar::F64;
let args = vec![match size {
Some(size) => TypeInner::Vector { size, kind, width },
None => TypeInner::Scalar { kind, width },
Some(size) => TypeInner::Vector { size, scalar },
None => TypeInner::Scalar(scalar),
}];
declaration.overloads.push(module.add_builtin(
@ -1091,16 +1043,16 @@ fn inject_double_builtin(declaration: &mut FunctionDeclaration, module: &mut Mod
0b101 => (Some(VectorSize::Tri), Some(VectorSize::Tri)),
_ => (Some(VectorSize::Quad), Some(VectorSize::Quad)),
};
let kind = Sk::Float;
let scalar = Scalar::F64;
let args = vec![
match size {
Some(size) => TypeInner::Vector { size, kind, width },
None => TypeInner::Scalar { kind, width },
Some(size) => TypeInner::Vector { size, scalar },
None => TypeInner::Scalar(scalar),
},
match second_size {
Some(size) => TypeInner::Vector { size, kind, width },
None => TypeInner::Scalar { kind, width },
Some(size) => TypeInner::Vector { size, scalar },
None => TypeInner::Scalar(scalar),
},
];
@ -1127,24 +1079,24 @@ fn inject_double_builtin(declaration: &mut FunctionDeclaration, module: &mut Mod
0b10 => Some(VectorSize::Tri),
_ => None,
};
let kind = Sk::Float;
let scalar = Scalar::F64;
let (splatted, boolean) = match bits >> 2 {
0b00 => (false, false),
0b01 => (false, true),
_ => (true, false),
};
let ty = |kind, width| match size {
Some(size) => TypeInner::Vector { size, kind, width },
None => TypeInner::Scalar { kind, width },
let ty = |scalar| match size {
Some(size) => TypeInner::Vector { size, scalar },
None => TypeInner::Scalar(scalar),
};
let args = vec![
ty(kind, width),
ty(kind, width),
ty(scalar),
ty(scalar),
match (boolean, splatted) {
(true, _) => ty(Sk::Bool, crate::BOOL_WIDTH),
(_, false) => TypeInner::Scalar { kind, width },
_ => ty(kind, width),
(true, _) => ty(Scalar::BOOL),
(_, false) => TypeInner::Scalar(scalar),
_ => ty(scalar),
},
];
@ -1165,7 +1117,7 @@ fn inject_double_builtin(declaration: &mut FunctionDeclaration, module: &mut Mod
// 0b110 is the last element since splatted with single elements
// is equal to normal single elements
for bits in 0..0b111 {
let kind = Sk::Float;
let scalar = Scalar::F64;
let size = match bits & 0b11 {
0b00 => Some(VectorSize::Bi),
0b01 => Some(VectorSize::Tri),
@ -1175,11 +1127,11 @@ fn inject_double_builtin(declaration: &mut FunctionDeclaration, module: &mut Mod
let splatted = bits & 0b100 == 0b100;
let base_ty = || match size {
Some(size) => TypeInner::Vector { size, kind, width },
None => TypeInner::Scalar { kind, width },
Some(size) => TypeInner::Vector { size, scalar },
None => TypeInner::Scalar(scalar),
};
let limit_ty = || match splatted {
true => TypeInner::Scalar { kind, width },
true => TypeInner::Scalar(scalar),
false => base_ty(),
};
@ -1192,14 +1144,15 @@ fn inject_double_builtin(declaration: &mut FunctionDeclaration, module: &mut Mod
}
"lessThan" | "greaterThan" | "lessThanEqual" | "greaterThanEqual" | "equal"
| "notEqual" => {
let scalar = Scalar::F64;
for bits in 0..0b11 {
let (size, kind) = match bits {
0b00 => (VectorSize::Bi, Sk::Float),
0b01 => (VectorSize::Tri, Sk::Float),
_ => (VectorSize::Quad, Sk::Float),
let size = match bits {
0b00 => VectorSize::Bi,
0b01 => VectorSize::Tri,
_ => VectorSize::Quad,
};
let ty = || TypeInner::Vector { size, kind, width };
let ty = || TypeInner::Vector { size, scalar };
let args = vec![ty(), ty()];
let fun = MacroCall::Binary(match name {
@ -1227,6 +1180,10 @@ fn inject_common_builtin(
name: &str,
float_width: crate::Bytes,
) {
let float_scalar = Scalar {
kind: Sk::Float,
width: float_width,
};
match name {
"ceil" | "round" | "roundEven" | "floor" | "fract" | "trunc" | "sqrt" | "inversesqrt"
| "normalize" | "length" | "isinf" | "isnan" => {
@ -1243,13 +1200,9 @@ fn inject_common_builtin(
let args = vec![match size {
Some(size) => TypeInner::Vector {
size,
kind: Sk::Float,
width: float_width,
},
None => TypeInner::Scalar {
kind: Sk::Float,
width: float_width,
scalar: float_scalar,
},
None => TypeInner::Scalar(float_scalar),
}];
let fun = match name {
@ -1280,16 +1233,9 @@ fn inject_common_builtin(
0b10 => Some(VectorSize::Tri),
_ => Some(VectorSize::Quad),
};
let ty = |kind| match size {
Some(size) => TypeInner::Vector {
size,
kind,
width: float_width,
},
None => TypeInner::Scalar {
kind,
width: float_width,
},
let ty = |scalar| match size {
Some(size) => TypeInner::Vector { size, scalar },
None => TypeInner::Scalar(scalar),
};
let fun = match name {
@ -1300,15 +1246,14 @@ fn inject_common_builtin(
_ => unreachable!(),
};
let second_kind = if fun == MacroCall::MathFunction(MathFunction::Ldexp) {
Sk::Sint
} else {
Sk::Float
let second_scalar = match fun {
MacroCall::MathFunction(MathFunction::Ldexp) => Scalar::I32,
_ => float_scalar,
};
declaration
.overloads
.push(module.add_builtin(vec![ty(Sk::Float), ty(second_kind)], fun))
.push(module.add_builtin(vec![ty(float_scalar), ty(second_scalar)], fun))
}
}
"transpose" => {
@ -1389,13 +1334,9 @@ fn inject_common_builtin(
args.push(match maybe_size {
Some(size) => TypeInner::Vector {
size,
kind: Sk::Float,
width: float_width,
},
None => TypeInner::Scalar {
kind: Sk::Float,
width: float_width,
scalar: float_scalar,
},
None => TypeInner::Scalar(float_scalar),
})
}
@ -1414,13 +1355,11 @@ fn inject_common_builtin(
let args = vec![
TypeInner::Vector {
size: VectorSize::Tri,
kind: Sk::Float,
width: float_width,
scalar: float_scalar,
},
TypeInner::Vector {
size: VectorSize::Tri,
kind: Sk::Float,
width: float_width,
scalar: float_scalar,
},
];
@ -1447,13 +1386,11 @@ fn inject_common_builtin(
let args = vec![
TypeInner::Vector {
size: size1,
kind: Sk::Float,
width: float_width,
scalar: float_scalar,
},
TypeInner::Vector {
size: size2,
kind: Sk::Float,
width: float_width,
scalar: float_scalar,
},
];
@ -1476,13 +1413,9 @@ fn inject_common_builtin(
let ty = || match size {
Some(size) => TypeInner::Vector {
size,
kind: Sk::Float,
width: float_width,
},
None => TypeInner::Scalar {
kind: Sk::Float,
width: float_width,
scalar: float_scalar,
},
None => TypeInner::Scalar(float_scalar),
};
let args = vec![ty(), ty(), ty()];
@ -1509,22 +1442,11 @@ fn inject_common_builtin(
let ty = || match size {
Some(size) => TypeInner::Vector {
size,
kind: Sk::Float,
width: float_width,
},
None => TypeInner::Scalar {
kind: Sk::Float,
width: float_width,
scalar: float_scalar,
},
None => TypeInner::Scalar(float_scalar),
};
let args = vec![
ty(),
ty(),
TypeInner::Scalar {
kind: Sk::Float,
width: 4,
},
];
let args = vec![ty(), ty(), TypeInner::Scalar(Scalar::F32)];
declaration
.overloads
.push(module.add_builtin(args, MacroCall::MathFunction(MathFunction::Refract)))
@ -1549,19 +1471,12 @@ fn inject_common_builtin(
let base_ty = || match size {
Some(size) => TypeInner::Vector {
size,
kind: Sk::Float,
width: float_width,
},
None => TypeInner::Scalar {
kind: Sk::Float,
width: float_width,
scalar: float_scalar,
},
None => TypeInner::Scalar(float_scalar),
};
let ty = || match splatted {
true => TypeInner::Scalar {
kind: Sk::Float,
width: float_width,
},
true => TypeInner::Scalar(float_scalar),
false => base_ty(),
};
declaration.overloads.push(module.add_builtin(
@ -1810,8 +1725,7 @@ impl MacroCall {
name: None,
inner: TypeInner::Vector {
size,
kind: crate::ScalarKind::Uint,
width: 4,
scalar: Scalar::U32,
},
},
Span::default(),
@ -2100,7 +2014,7 @@ fn texture_call(
let mut array_index = comps.array_index;
if let Some(ref mut array_index_expr) = array_index {
ctx.conversion(array_index_expr, meta, Sk::Sint, 4)?;
ctx.conversion(array_index_expr, meta, Scalar::I32)?;
}
Ok(ctx.add_expression(

View File

@ -9,8 +9,8 @@ use super::{
};
use crate::{
front::Typifier, proc::Emitter, AddressSpace, Arena, BinaryOperator, Block, Expression,
FastHashMap, FunctionArgument, Handle, Literal, LocalVariable, RelationalFunction, ScalarKind,
Span, Statement, Type, TypeInner, VectorSize,
FastHashMap, FunctionArgument, Handle, Literal, LocalVariable, RelationalFunction, Scalar,
ScalarKind, Span, Statement, Type, TypeInner, VectorSize,
};
use std::ops::Index;
@ -602,7 +602,7 @@ impl<'a> Context<'a> {
match op {
BinaryOperator::ShiftLeft | BinaryOperator::ShiftRight => {
self.implicit_conversion(&mut right, right_meta, ScalarKind::Uint, 4)?
self.implicit_conversion(&mut right, right_meta, Scalar::U32)?
}
_ => self
.binary_implicit_conversion(&mut left, left_meta, &mut right, right_meta)?,
@ -824,9 +824,9 @@ impl<'a> Context<'a> {
_ => self.add_expression(Expression::Binary { left, op, right }, meta)?,
},
(
&TypeInner::Scalar {
&TypeInner::Scalar(Scalar {
width: left_width, ..
},
}),
&TypeInner::Matrix {
rows,
columns,
@ -911,9 +911,9 @@ impl<'a> Context<'a> {
columns,
width: left_width,
},
&TypeInner::Scalar {
&TypeInner::Scalar(Scalar {
width: right_width, ..
},
}),
) => {
// Check that the two arguments have the same width
if left_width != right_width {
@ -1100,37 +1100,24 @@ impl<'a> Context<'a> {
// We need to do some custom implicit conversions since the two target expressions
// are in different bodies
if let (
Some((accept_power, accept_width, accept_kind)),
Some((reject_power, reject_width, reject_kind)),
) = (
if let (Some((accept_power, accept_scalar)), Some((reject_power, reject_scalar))) = (
// Get the components of both branches and calculate the type power
self.expr_scalar_components(accept, accept_meta)?
.and_then(|(kind, width)| Some((type_power(kind, width)?, width, kind))),
.and_then(|scalar| Some((type_power(scalar)?, scalar))),
self.expr_scalar_components(reject, reject_meta)?
.and_then(|(kind, width)| Some((type_power(kind, width)?, width, kind))),
.and_then(|scalar| Some((type_power(scalar)?, scalar))),
) {
match accept_power.cmp(&reject_power) {
std::cmp::Ordering::Less => {
accept_body = self.with_body(accept_body, |ctx| {
ctx.conversion(
&mut accept,
accept_meta,
reject_kind,
reject_width,
)?;
ctx.conversion(&mut accept, accept_meta, reject_scalar)?;
Ok(())
})?;
}
std::cmp::Ordering::Equal => {}
std::cmp::Ordering::Greater => {
reject_body = self.with_body(reject_body, |ctx| {
ctx.conversion(
&mut reject,
reject_meta,
accept_kind,
accept_width,
)?;
ctx.conversion(&mut reject, reject_meta, accept_scalar)?;
Ok(())
})?;
}
@ -1201,8 +1188,8 @@ impl<'a> Context<'a> {
ref ty => ty,
};
if let Some((kind, width)) = scalar_components(ty) {
self.implicit_conversion(&mut value, value_meta, kind, width)?;
if let Some(scalar) = scalar_components(ty) {
self.implicit_conversion(&mut value, value_meta, scalar)?;
}
self.lower_store(pointer, value, meta)?;
@ -1218,13 +1205,13 @@ impl<'a> Context<'a> {
};
let res = match *self.resolve_type(left, meta)? {
TypeInner::Scalar { kind, width } => {
let ty = TypeInner::Scalar { kind, width };
Literal::one(kind, width).map(|i| (ty, i, None, None))
TypeInner::Scalar(scalar) => {
let ty = TypeInner::Scalar(scalar);
Literal::one(scalar).map(|i| (ty, i, None, None))
}
TypeInner::Vector { size, kind, width } => {
let ty = TypeInner::Vector { size, kind, width };
Literal::one(kind, width).map(|i| (ty, i, Some(size), None))
TypeInner::Vector { size, scalar } => {
let ty = TypeInner::Vector { size, scalar };
Literal::one(scalar).map(|i| (ty, i, Some(size), None))
}
TypeInner::Matrix {
columns,
@ -1236,8 +1223,11 @@ impl<'a> Context<'a> {
rows,
width,
};
Literal::one(ScalarKind::Float, width)
.map(|i| (ty, i, Some(rows), Some(columns)))
Literal::one(Scalar {
kind: ScalarKind::Float,
width,
})
.map(|i| (ty, i, Some(rows), Some(columns)))
}
_ => None,
};
@ -1323,19 +1313,14 @@ impl<'a> Context<'a> {
Expression::Literal(Literal::U32(size.get())),
meta,
)?;
self.forced_conversion(
&mut array_length,
meta,
ScalarKind::Sint,
4,
)?;
self.forced_conversion(&mut array_length, meta, Scalar::I32)?;
array_length
}
// let the error be handled in type checking if it's not a dynamic array
_ => {
let mut array_length = self
.add_expression(Expression::ArrayLength(lowered_array), meta)?;
self.conversion(&mut array_length, meta, ScalarKind::Sint, 4)?;
self.conversion(&mut array_length, meta, Scalar::I32)?;
array_length
}
}
@ -1376,7 +1361,7 @@ impl<'a> Context<'a> {
&mut self,
expr: Handle<Expression>,
meta: Span,
) -> Result<Option<(ScalarKind, crate::Bytes)>> {
) -> Result<Option<Scalar>> {
let ty = self.resolve_type(expr, meta)?;
Ok(scalar_components(ty))
}
@ -1384,21 +1369,20 @@ impl<'a> Context<'a> {
pub fn expr_power(&mut self, expr: Handle<Expression>, meta: Span) -> Result<Option<u32>> {
Ok(self
.expr_scalar_components(expr, meta)?
.and_then(|(kind, width)| type_power(kind, width)))
.and_then(type_power))
}
pub fn conversion(
&mut self,
expr: &mut Handle<Expression>,
meta: Span,
kind: ScalarKind,
width: crate::Bytes,
scalar: Scalar,
) -> Result<()> {
*expr = self.add_expression(
Expression::As {
expr: *expr,
kind,
convert: Some(width),
kind: scalar.kind,
convert: Some(scalar.width),
},
meta,
)?;
@ -1410,14 +1394,13 @@ impl<'a> Context<'a> {
&mut self,
expr: &mut Handle<Expression>,
meta: Span,
kind: ScalarKind,
width: crate::Bytes,
scalar: Scalar,
) -> Result<()> {
if let (Some(tgt_power), Some(expr_power)) =
(type_power(kind, width), self.expr_power(*expr, meta)?)
(type_power(scalar), self.expr_power(*expr, meta)?)
{
if tgt_power > expr_power {
self.conversion(expr, meta, kind, width)?;
self.conversion(expr, meta, scalar)?;
}
}
@ -1428,12 +1411,11 @@ impl<'a> Context<'a> {
&mut self,
expr: &mut Handle<Expression>,
meta: Span,
kind: ScalarKind,
width: crate::Bytes,
scalar: Scalar,
) -> Result<()> {
if let Some((expr_scalar_kind, expr_width)) = self.expr_scalar_components(*expr, meta)? {
if expr_scalar_kind != kind || expr_width != width {
self.conversion(expr, meta, kind, width)?;
if let Some(expr_scalar) = self.expr_scalar_components(*expr, meta)? {
if expr_scalar != scalar {
self.conversion(expr, meta, scalar)?;
}
}
@ -1450,21 +1432,17 @@ impl<'a> Context<'a> {
let left_components = self.expr_scalar_components(*left, left_meta)?;
let right_components = self.expr_scalar_components(*right, right_meta)?;
if let (
Some((left_power, left_width, left_kind)),
Some((right_power, right_width, right_kind)),
) = (
left_components.and_then(|(kind, width)| Some((type_power(kind, width)?, width, kind))),
right_components
.and_then(|(kind, width)| Some((type_power(kind, width)?, width, kind))),
if let (Some((left_power, left_scalar)), Some((right_power, right_scalar))) = (
left_components.and_then(|scalar| Some((type_power(scalar)?, scalar))),
right_components.and_then(|scalar| Some((type_power(scalar)?, scalar))),
) {
match left_power.cmp(&right_power) {
std::cmp::Ordering::Less => {
self.conversion(left, left_meta, right_kind, right_width)?;
self.conversion(left, left_meta, right_scalar)?;
}
std::cmp::Ordering::Equal => {}
std::cmp::Ordering::Greater => {
self.conversion(right, right_meta, left_kind, left_width)?;
self.conversion(right, right_meta, left_scalar)?;
}
}
}

View File

@ -8,7 +8,7 @@ use super::{
};
use crate::{
front::glsl::types::type_power, proc::ensure_block_returns, AddressSpace, Block, EntryPoint,
Expression, Function, FunctionArgument, FunctionResult, Handle, Literal, LocalVariable,
Expression, Function, FunctionArgument, FunctionResult, Handle, Literal, LocalVariable, Scalar,
ScalarKind, Span, Statement, StructMember, Type, TypeInner,
};
use std::iter;
@ -20,7 +20,7 @@ struct ProxyWrite {
/// A pointer to read the value of the store
value: Handle<Expression>,
/// An optional conversion to be applied
convert: Option<(ScalarKind, crate::Bytes)>,
convert: Option<Scalar>,
}
impl Frontend {
@ -68,10 +68,14 @@ impl Frontend {
let expr_is_bool = expr_type.scalar_kind() == Some(ScalarKind::Bool);
// Special case: if casting from a bool, we need to use Select and not As.
match ctx.module.types[ty].inner.scalar_kind() {
Some(result_scalar_kind) if expr_is_bool && result_scalar_kind != ScalarKind::Bool => {
let l0 = Literal::zero(result_scalar_kind, 4).unwrap();
let l1 = Literal::one(result_scalar_kind, 4).unwrap();
match ctx.module.types[ty].inner.scalar() {
Some(result_scalar) if expr_is_bool && result_scalar.kind != ScalarKind::Bool => {
let result_scalar = Scalar {
width: 4,
..result_scalar
};
let l0 = Literal::zero(result_scalar).unwrap();
let l1 = Literal::one(result_scalar).unwrap();
let mut reject = ctx.add_expression(Expression::Literal(l0), expr_meta)?;
let mut accept = ctx.add_expression(Expression::Literal(l1), expr_meta)?;
@ -93,24 +97,16 @@ impl Frontend {
}
Ok(match ctx.module.types[ty].inner {
TypeInner::Vector { size, kind, width } if vector_size.is_none() => {
ctx.forced_conversion(&mut value, expr_meta, kind, width)?;
TypeInner::Vector { size, scalar } if vector_size.is_none() => {
ctx.forced_conversion(&mut value, expr_meta, scalar)?;
if let TypeInner::Scalar { .. } = *ctx.resolve_type(value, expr_meta)? {
ctx.add_expression(Expression::Splat { size, value }, meta)?
} else {
self.vector_constructor(
ctx,
ty,
size,
kind,
width,
&[(value, expr_meta)],
meta,
)?
self.vector_constructor(ctx, ty, size, scalar, &[(value, expr_meta)], meta)?
}
}
TypeInner::Scalar { kind, width } => {
TypeInner::Scalar(scalar) => {
let mut expr = value;
if let TypeInner::Vector { .. } | TypeInner::Matrix { .. } =
*ctx.resolve_type(value, expr_meta)?
@ -136,23 +132,23 @@ impl Frontend {
ctx.add_expression(
Expression::As {
kind,
kind: scalar.kind,
expr,
convert: Some(width),
convert: Some(scalar.width),
},
meta,
)?
}
TypeInner::Vector { size, kind, width } => {
TypeInner::Vector { size, scalar } => {
if vector_size.map_or(true, |s| s != size) {
value = ctx.vector_resize(size, value, expr_meta)?;
}
ctx.add_expression(
Expression::As {
kind,
kind: scalar.kind,
expr: value,
convert: Some(width),
convert: Some(scalar.width),
},
meta,
)?
@ -166,8 +162,8 @@ impl Frontend {
let scalar_components = members
.get(0)
.and_then(|member| scalar_components(&ctx.module.types[member.ty].inner));
if let Some((kind, width)) = scalar_components {
ctx.implicit_conversion(&mut value, expr_meta, kind, width)?;
if let Some(scalar) = scalar_components {
ctx.implicit_conversion(&mut value, expr_meta, scalar)?;
}
ctx.add_expression(
@ -181,8 +177,8 @@ impl Frontend {
TypeInner::Array { base, .. } => {
let scalar_components = scalar_components(&ctx.module.types[base].inner);
if let Some((kind, width)) = scalar_components {
ctx.implicit_conversion(&mut value, expr_meta, kind, width)?;
if let Some(scalar) = scalar_components {
ctx.implicit_conversion(&mut value, expr_meta, scalar)?;
}
ctx.add_expression(
@ -220,9 +216,13 @@ impl Frontend {
// `Expression::As` doesn't support matrix width
// casts so we need to do some extra work for casts
ctx.forced_conversion(&mut value, expr_meta, ScalarKind::Float, width)?;
let element_scalar = Scalar {
kind: ScalarKind::Float,
width,
};
ctx.forced_conversion(&mut value, expr_meta, element_scalar)?;
match *ctx.resolve_type(value, expr_meta)? {
TypeInner::Scalar { .. } => {
TypeInner::Scalar(_) => {
// If a matrix is constructed with a single scalar value, then that
// value is used to initialize all the values along the diagonal of
// the matrix; the rest are given zeros.
@ -231,14 +231,13 @@ impl Frontend {
name: None,
inner: TypeInner::Vector {
size: rows,
kind: ScalarKind::Float,
width,
scalar: element_scalar,
},
},
meta,
);
let zero_literal = Literal::zero(ScalarKind::Float, width).unwrap();
let zero_literal = Literal::zero(element_scalar).unwrap();
let zero = ctx.add_expression(Expression::Literal(zero_literal), meta)?;
for i in 0..columns as u32 {
@ -268,8 +267,8 @@ impl Frontend {
// (column i, row j) in the argument will be initialized from there. All
// other components will be initialized to the identity matrix.
let zero_literal = Literal::zero(ScalarKind::Float, width).unwrap();
let one_literal = Literal::one(ScalarKind::Float, width).unwrap();
let zero_literal = Literal::zero(element_scalar).unwrap();
let one_literal = Literal::one(element_scalar).unwrap();
let zero = ctx.add_expression(Expression::Literal(zero_literal), meta)?;
let one = ctx.add_expression(Expression::Literal(one_literal), meta)?;
@ -279,8 +278,7 @@ impl Frontend {
name: None,
inner: TypeInner::Vector {
size: rows,
kind: ScalarKind::Float,
width,
scalar: element_scalar,
},
},
meta,
@ -360,15 +358,14 @@ impl Frontend {
ctx: &mut Context,
ty: Handle<Type>,
size: crate::VectorSize,
kind: ScalarKind,
width: crate::Bytes,
scalar: Scalar,
args: &[(Handle<Expression>, Span)],
meta: Span,
) -> Result<Handle<Expression>> {
let mut components = Vec::with_capacity(size as usize);
for (mut arg, expr_meta) in args.iter().copied() {
ctx.forced_conversion(&mut arg, expr_meta, kind, width)?;
ctx.forced_conversion(&mut arg, expr_meta, scalar)?;
if components.len() >= size as usize {
break;
@ -429,8 +426,12 @@ impl Frontend {
} => {
let mut flattened = Vec::with_capacity(columns as usize * rows as usize);
let element_scalar = Scalar {
kind: ScalarKind::Float,
width,
};
for (mut arg, meta) in args.iter().copied() {
ctx.forced_conversion(&mut arg, meta, ScalarKind::Float, width)?;
ctx.forced_conversion(&mut arg, meta, element_scalar)?;
match *ctx.resolve_type(arg, meta)? {
TypeInner::Vector { size, .. } => {
@ -453,8 +454,7 @@ impl Frontend {
name: None,
inner: TypeInner::Vector {
size: rows,
kind: ScalarKind::Float,
width,
scalar: element_scalar,
},
},
meta,
@ -471,14 +471,14 @@ impl Frontend {
}
None
}
TypeInner::Vector { size, kind, width } => {
return self.vector_constructor(ctx, ty, size, kind, width, &args, meta)
TypeInner::Vector { size, scalar } => {
return self.vector_constructor(ctx, ty, size, scalar, &args, meta)
}
TypeInner::Array { base, .. } => {
for (mut arg, meta) in args.iter().copied() {
let scalar_components = scalar_components(&ctx.module.types[base].inner);
if let Some((kind, width)) = scalar_components {
ctx.implicit_conversion(&mut arg, meta, kind, width)?;
if let Some(scalar) = scalar_components {
ctx.implicit_conversion(&mut arg, meta, scalar)?;
}
components.push(arg)
@ -503,8 +503,8 @@ impl Frontend {
for ((mut arg, meta), scalar_components) in
args.iter().copied().zip(struct_member_data.iter().copied())
{
if let Some((kind, width)) = scalar_components {
ctx.implicit_conversion(&mut arg, meta, kind, width)?;
if let Some(scalar) = scalar_components {
ctx.implicit_conversion(&mut arg, meta, scalar)?;
}
components.push(arg)
@ -813,8 +813,8 @@ impl Frontend {
let scalar_comps = scalar_components(&ctx.module.types[*parameter].inner);
// Apply implicit conversions as needed
if let Some((kind, width)) = scalar_comps {
ctx.implicit_conversion(&mut handle, meta, kind, width)?;
if let Some(scalar) = scalar_comps {
ctx.implicit_conversion(&mut handle, meta, scalar)?;
}
arguments.push(handle)
@ -850,8 +850,8 @@ impl Frontend {
meta,
)?;
if let Some((kind, width)) = proxy_write.convert {
ctx.conversion(&mut value, meta, kind, width)?;
if let Some(scalar) = proxy_write.convert {
ctx.conversion(&mut value, meta, scalar)?;
}
ctx.emit_restart();
@ -893,10 +893,10 @@ impl Frontend {
// If the argument is to be passed as a pointer but the type of the
// expression returns a vector it must mean that it was for example
// swizzled and it must be spilled into a local before calling
TypeInner::Vector { size, kind, width } => Some(ctx.module.types.insert(
TypeInner::Vector { size, scalar } => Some(ctx.module.types.insert(
Type {
name: None,
inner: TypeInner::Vector { size, kind, width },
inner: TypeInner::Vector { size, scalar },
},
Span::default(),
)),
@ -906,13 +906,12 @@ impl Frontend {
TypeInner::Pointer { base, space } if space != AddressSpace::Function => Some(base),
TypeInner::ValuePointer {
size,
kind,
width,
scalar,
space,
} if space != AddressSpace::Function => {
let inner = match size {
Some(size) => TypeInner::Vector { size, kind, width },
None => TypeInner::Scalar { kind, width },
Some(size) => TypeInner::Vector { size, scalar },
None => TypeInner::Scalar(scalar),
};
Some(
@ -1512,31 +1511,22 @@ fn conversion(target: &TypeInner, source: &TypeInner) -> Option<Conversion> {
use ScalarKind::*;
// Gather the `ScalarKind` and scalar width from both the target and the source
let (target_kind, target_width, source_kind, source_width) = match (target, source) {
let (target_scalar, source_scalar) = match (target, source) {
// Conversions between scalars are allowed
(
&TypeInner::Scalar {
kind: tgt_kind,
width: tgt_width,
},
&TypeInner::Scalar {
kind: src_kind,
width: src_width,
},
) => (tgt_kind, tgt_width, src_kind, src_width),
(&TypeInner::Scalar(tgt_scalar), &TypeInner::Scalar(src_scalar)) => {
(tgt_scalar, src_scalar)
}
// Conversions between vectors of the same size are allowed
(
&TypeInner::Vector {
kind: tgt_kind,
size: tgt_size,
width: tgt_width,
scalar: tgt_scalar,
},
&TypeInner::Vector {
kind: src_kind,
size: src_size,
width: src_width,
scalar: src_scalar,
},
) if tgt_size == src_size => (tgt_kind, tgt_width, src_kind, src_width),
) if tgt_size == src_size => (tgt_scalar, src_scalar),
// Conversions between matrices of the same size are allowed
(
&TypeInner::Matrix {
@ -1549,29 +1539,41 @@ fn conversion(target: &TypeInner, source: &TypeInner) -> Option<Conversion> {
columns: src_cols,
width: src_width,
},
) if tgt_cols == src_cols && tgt_rows == src_rows => (Float, tgt_width, Float, src_width),
) if tgt_cols == src_cols && tgt_rows == src_rows => {
(Scalar::float(tgt_width), Scalar::float(src_width))
}
_ => return None,
};
// Check if source can be converted into target, if this is the case then the type
// power of target must be higher than that of source
let target_power = type_power(target_kind, target_width);
let source_power = type_power(source_kind, source_width);
let target_power = type_power(target_scalar);
let source_power = type_power(source_scalar);
if target_power < source_power {
return None;
}
Some(
match ((target_kind, target_width), (source_kind, source_width)) {
// A conversion from a float to a double is special
((Float, 8), (Float, 4)) => Conversion::FloatToDouble,
// A conversion from an integer to a float is special
((Float, 4), (Sint | Uint, _)) => Conversion::IntToFloat,
// A conversion from an integer to a double is special
((Float, 8), (Sint | Uint, _)) => Conversion::IntToDouble,
_ => Conversion::Other,
},
)
Some(match (target_scalar, source_scalar) {
// A conversion from a float to a double is special
(Scalar::F64, Scalar::F32) => Conversion::FloatToDouble,
// A conversion from an integer to a float is special
(
Scalar::F32,
Scalar {
kind: Sint | Uint,
width: _,
},
) => Conversion::IntToFloat,
// A conversion from an integer to a double is special
(
Scalar::F64,
Scalar {
kind: Sint | Uint,
width: _,
},
) => Conversion::IntToDouble,
_ => Conversion::Other,
})
}
/// Helper method returning all the non standard builtin variations needed
@ -1581,10 +1583,10 @@ fn builtin_required_variations<'a>(args: impl Iterator<Item = &'a TypeInner>) ->
for ty in args {
match *ty {
TypeInner::ValuePointer { kind, width, .. }
| TypeInner::Scalar { kind, width }
| TypeInner::Vector { kind, width, .. } => {
if kind == ScalarKind::Float && width == 8 {
TypeInner::ValuePointer { scalar, .. }
| TypeInner::Scalar(scalar)
| TypeInner::Vector { scalar, .. } => {
if scalar == Scalar::F64 {
variations |= BuiltinVariations::DOUBLE
}
}

View File

@ -16,7 +16,7 @@ use super::{
error::{Error, ErrorKind},
Span,
};
use crate::{proc::Alignment, Handle, Type, TypeInner, UniqueArena};
use crate::{proc::Alignment, Handle, Scalar, Type, TypeInner, UniqueArena};
/// Struct with information needed for defining a struct member.
///
@ -53,12 +53,15 @@ pub fn calculate_offset(
let (align, span) = match types[ty].inner {
// 1. If the member is a scalar consuming N basic machine units,
// the base alignment is N.
TypeInner::Scalar { width, .. } => (Alignment::from_width(width), width as u32),
TypeInner::Scalar(Scalar { width, .. }) => (Alignment::from_width(width), width as u32),
// 2. If the member is a two- or four-component vector with components
// consuming N basic machine units, the base alignment is 2N or 4N, respectively.
// 3. If the member is a three-component vector with components consuming N
// basic machine units, the base alignment is 4N.
TypeInner::Vector { size, width, .. } => (
TypeInner::Vector {
size,
scalar: Scalar { width, .. },
} => (
Alignment::from(size) * Alignment::from_width(width),
size as u32 * width as u32,
),

View File

@ -13,8 +13,8 @@ use crate::{
Error, ErrorKind, Frontend, Span,
},
proc::Alignment,
AddressSpace, Expression, FunctionResult, Handle, ScalarKind, Statement, StructMember, Type,
TypeInner,
AddressSpace, Expression, FunctionResult, Handle, Scalar, ScalarKind, Statement, StructMember,
Type, TypeInner,
};
use super::{DeclarationContext, ParsingContext, Result};
@ -34,10 +34,10 @@ fn element_or_member_type(
) -> Handle<Type> {
match types[ty].inner {
// The child type of a vector is a scalar of the same kind and width
TypeInner::Vector { kind, width, .. } => types.insert(
TypeInner::Vector { scalar, .. } => types.insert(
Type {
name: None,
inner: TypeInner::Scalar { kind, width },
inner: TypeInner::Scalar(scalar),
},
Default::default(),
),
@ -48,8 +48,7 @@ fn element_or_member_type(
name: None,
inner: TypeInner::Vector {
size: rows,
kind: ScalarKind::Float,
width,
scalar: Scalar::float(width),
},
},
Default::default(),
@ -156,8 +155,8 @@ impl<'source> ParsingContext<'source> {
let (mut init, init_meta) = ctx.lower_expect(stmt, frontend, expr, ExprPos::Rhs)?;
let scalar_components = scalar_components(&ctx.module.types[ty].inner);
if let Some((kind, width)) = scalar_components {
ctx.implicit_conversion(&mut init, init_meta, kind, width)?;
if let Some(scalar) = scalar_components {
ctx.implicit_conversion(&mut init, init_meta, scalar)?;
}
Ok((init, init_meta))
@ -233,9 +232,8 @@ impl<'source> ParsingContext<'source> {
let (mut expr, init_meta) = self.parse_initializer(frontend, ty, ctx.ctx)?;
let scalar_components = scalar_components(&ctx.ctx.module.types[ty].inner);
if let Some((kind, width)) = scalar_components {
ctx.ctx
.implicit_conversion(&mut expr, init_meta, kind, width)?;
if let Some(scalar) = scalar_components {
ctx.ctx.implicit_conversion(&mut expr, init_meta, scalar)?;
}
ctx.ctx.is_const = prev_const;
@ -509,10 +507,10 @@ impl<'source> ParsingContext<'source> {
let (ty, meta) = self.parse_type_non_void(frontend, ctx)?;
match ctx.module.types[ty].inner {
TypeInner::Scalar {
TypeInner::Scalar(Scalar {
kind: ScalarKind::Float | ScalarKind::Sint,
..
} => {}
}) => {}
_ => frontend.errors.push(Error {
kind: ErrorKind::SemanticError(
"Precision statement can only work on floats and ints".into(),

View File

@ -509,7 +509,7 @@ fn functions() {
#[test]
fn constants() {
use crate::{Constant, Expression, ScalarKind, Type, TypeInner};
use crate::{Constant, Expression, Type, TypeInner};
let mut frontend = Frontend::default();
@ -536,10 +536,7 @@ fn constants() {
ty,
&Type {
name: None,
inner: TypeInner::Scalar {
kind: ScalarKind::Float,
width: 4
}
inner: TypeInner::Scalar(crate::Scalar::F32)
}
);

View File

@ -1,6 +1,6 @@
use super::{context::Context, Error, ErrorKind, Result, Span};
use crate::{
proc::ResolveContext, Bytes, Expression, Handle, ImageClass, ImageDimension, ScalarKind, Type,
proc::ResolveContext, Expression, Handle, ImageClass, ImageDimension, Scalar, ScalarKind, Type,
TypeInner, VectorSize,
};
@ -8,38 +8,23 @@ pub fn parse_type(type_name: &str) -> Option<Type> {
match type_name {
"bool" => Some(Type {
name: None,
inner: TypeInner::Scalar {
kind: ScalarKind::Bool,
width: crate::BOOL_WIDTH,
},
inner: TypeInner::Scalar(Scalar::BOOL),
}),
"float" => Some(Type {
name: None,
inner: TypeInner::Scalar {
kind: ScalarKind::Float,
width: 4,
},
inner: TypeInner::Scalar(Scalar::F32),
}),
"double" => Some(Type {
name: None,
inner: TypeInner::Scalar {
kind: ScalarKind::Float,
width: 8,
},
inner: TypeInner::Scalar(Scalar::F64),
}),
"int" => Some(Type {
name: None,
inner: TypeInner::Scalar {
kind: ScalarKind::Sint,
width: 4,
},
inner: TypeInner::Scalar(Scalar::I32),
}),
"uint" => Some(Type {
name: None,
inner: TypeInner::Scalar {
kind: ScalarKind::Uint,
width: 4,
},
inner: TypeInner::Scalar(Scalar::U32),
}),
"sampler" | "samplerShadow" => Some(Type {
name: None,
@ -48,13 +33,13 @@ pub fn parse_type(type_name: &str) -> Option<Type> {
},
}),
word => {
fn kind_width_parse(ty: &str) -> Option<(ScalarKind, u8)> {
fn kind_width_parse(ty: &str) -> Option<Scalar> {
Some(match ty {
"" => (ScalarKind::Float, 4),
"b" => (ScalarKind::Bool, crate::BOOL_WIDTH),
"i" => (ScalarKind::Sint, 4),
"u" => (ScalarKind::Uint, 4),
"d" => (ScalarKind::Float, 8),
"" => Scalar::F32,
"b" => Scalar::BOOL,
"i" => Scalar::I32,
"u" => Scalar::U32,
"d" => Scalar::F64,
_ => return None,
})
}
@ -73,12 +58,12 @@ pub fn parse_type(type_name: &str) -> Option<Type> {
let kind = iter.next()?;
let size = iter.next()?;
let (kind, width) = kind_width_parse(kind)?;
let scalar = kind_width_parse(kind)?;
let size = size_parse(size)?;
Some(Type {
name: None,
inner: TypeInner::Vector { size, kind, width },
inner: TypeInner::Vector { size, scalar },
})
};
@ -87,7 +72,7 @@ pub fn parse_type(type_name: &str) -> Option<Type> {
let kind = iter.next()?;
let size = iter.next()?;
let (_, width) = kind_width_parse(kind)?;
let Scalar { width, .. } = kind_width_parse(kind)?;
let (columns, rows) = if let Some(size) = size_parse(size) {
(size, size)
@ -204,21 +189,21 @@ pub fn parse_type(type_name: &str) -> Option<Type> {
}
}
pub const fn scalar_components(ty: &TypeInner) -> Option<(ScalarKind, Bytes)> {
pub const fn scalar_components(ty: &TypeInner) -> Option<Scalar> {
match *ty {
TypeInner::Scalar { kind, width } => Some((kind, width)),
TypeInner::Vector { kind, width, .. } => Some((kind, width)),
TypeInner::Matrix { width, .. } => Some((ScalarKind::Float, width)),
TypeInner::ValuePointer { kind, width, .. } => Some((kind, width)),
TypeInner::Scalar(scalar)
| TypeInner::Vector { scalar, .. }
| TypeInner::ValuePointer { scalar, .. } => Some(scalar),
TypeInner::Matrix { width, .. } => Some(Scalar::float(width)),
_ => None,
}
}
pub const fn type_power(kind: ScalarKind, width: Bytes) -> Option<u32> {
Some(match kind {
pub const fn type_power(scalar: Scalar) -> Option<u32> {
Some(match scalar.kind {
ScalarKind::Sint => 0,
ScalarKind::Uint => 1,
ScalarKind::Float if width == 4 => 2,
ScalarKind::Float if scalar.width == 4 => 2,
ScalarKind::Float => 3,
ScalarKind::Bool => return None,
})

View File

@ -6,8 +6,8 @@ use super::{
};
use crate::{
AddressSpace, Binding, BuiltIn, Constant, Expression, GlobalVariable, Handle, Interpolation,
LocalVariable, ResourceBinding, ScalarKind, ShaderStage, SwizzleComponent, Type, TypeInner,
VectorSize,
LocalVariable, ResourceBinding, Scalar, ScalarKind, ShaderStage, SwizzleComponent, Type,
TypeInner, VectorSize,
};
pub struct VarDeclaration<'a, 'key> {
@ -109,8 +109,7 @@ impl Frontend {
"gl_Position" => BuiltInData {
inner: TypeInner::Vector {
size: VectorSize::Quad,
kind: ScalarKind::Float,
width: 4,
scalar: Scalar::F32,
},
builtin: BuiltIn::Position { invariant: false },
mutable: true,
@ -119,8 +118,7 @@ impl Frontend {
"gl_FragCoord" => BuiltInData {
inner: TypeInner::Vector {
size: VectorSize::Quad,
kind: ScalarKind::Float,
width: 4,
scalar: Scalar::F32,
},
builtin: BuiltIn::Position { invariant: false },
mutable: false,
@ -129,8 +127,7 @@ impl Frontend {
"gl_PointCoord" => BuiltInData {
inner: TypeInner::Vector {
size: VectorSize::Bi,
kind: ScalarKind::Float,
width: 4,
scalar: Scalar::F32,
},
builtin: BuiltIn::PointCoord,
mutable: false,
@ -143,8 +140,7 @@ impl Frontend {
| "gl_LocalInvocationID" => BuiltInData {
inner: TypeInner::Vector {
size: VectorSize::Tri,
kind: ScalarKind::Uint,
width: 4,
scalar: Scalar::U32,
},
builtin: match name {
"gl_GlobalInvocationID" => BuiltIn::GlobalInvocationId,
@ -158,19 +154,13 @@ impl Frontend {
storage: StorageQualifier::Input,
},
"gl_FrontFacing" => BuiltInData {
inner: TypeInner::Scalar {
kind: ScalarKind::Bool,
width: crate::BOOL_WIDTH,
},
inner: TypeInner::Scalar(Scalar::BOOL),
builtin: BuiltIn::FrontFacing,
mutable: false,
storage: StorageQualifier::Input,
},
"gl_PointSize" | "gl_FragDepth" => BuiltInData {
inner: TypeInner::Scalar {
kind: ScalarKind::Float,
width: 4,
},
inner: TypeInner::Scalar(Scalar::F32),
builtin: match name {
"gl_PointSize" => BuiltIn::PointSize,
"gl_FragDepth" => BuiltIn::FragDepth,
@ -183,10 +173,7 @@ impl Frontend {
let base = ctx.module.types.insert(
Type {
name: None,
inner: TypeInner::Scalar {
kind: ScalarKind::Float,
width: 4,
},
inner: TypeInner::Scalar(Scalar::F32),
},
meta,
);
@ -219,10 +206,7 @@ impl Frontend {
};
BuiltInData {
inner: TypeInner::Scalar {
kind: ScalarKind::Uint,
width: 4,
},
inner: TypeInner::Scalar(Scalar::U32),
builtin,
mutable: false,
storage: StorageQualifier::Input,

View File

@ -1,4 +1,7 @@
use crate::arena::{Handle, UniqueArena};
use crate::{
arena::{Handle, UniqueArena},
Scalar,
};
use super::{Error, LookupExpression, LookupHelper as _};
@ -61,8 +64,11 @@ fn extract_image_coordinates(
ctx: &mut super::BlockContext,
) -> (Handle<crate::Expression>, Option<Handle<crate::Expression>>) {
let (given_size, kind) = match ctx.type_arena[coordinate_ty].inner {
crate::TypeInner::Scalar { kind, .. } => (None, kind),
crate::TypeInner::Vector { size, kind, .. } => (Some(size), kind),
crate::TypeInner::Scalar(Scalar { kind, .. }) => (None, kind),
crate::TypeInner::Vector {
size,
scalar: Scalar { kind, .. },
} => (Some(size), kind),
ref other => unreachable!("Unexpected texture coordinate {:?}", other),
};
@ -73,8 +79,7 @@ fn extract_image_coordinates(
name: None,
inner: crate::TypeInner::Vector {
size,
kind,
width: 4,
scalar: Scalar { kind, width: 4 },
},
})
.expect("Required coordinate type should have been set up by `parse_type_image`!")

View File

@ -2829,22 +2829,22 @@ impl<I: Iterator<Item = u32>> Frontend<I> {
let value_lexp = self.lookup_expression.lookup(value_id)?;
let ty_lookup = self.lookup_type.lookup(result_type_id)?;
let (kind, width) = match ctx.type_arena[ty_lookup.handle].inner {
crate::TypeInner::Scalar { kind, width }
| crate::TypeInner::Vector { kind, width, .. } => (kind, width),
crate::TypeInner::Matrix { width, .. } => (crate::ScalarKind::Float, width),
let scalar = match ctx.type_arena[ty_lookup.handle].inner {
crate::TypeInner::Scalar(scalar)
| crate::TypeInner::Vector { scalar, .. } => scalar,
crate::TypeInner::Matrix { width, .. } => crate::Scalar::float(width),
_ => return Err(Error::InvalidAsType(ty_lookup.handle)),
};
let expr = crate::Expression::As {
expr: get_expr_handle!(value_id, value_lexp),
kind,
convert: if kind == crate::ScalarKind::Bool {
kind: scalar.kind,
convert: if scalar.kind == crate::ScalarKind::Bool {
Some(crate::BOOL_WIDTH)
} else if inst.op == Op::Bitcast {
None
} else {
Some(width)
Some(scalar.width)
},
};
self.lookup_expression.insert(
@ -3356,10 +3356,10 @@ impl<I: Iterator<Item = u32>> Frontend<I> {
let selector_lty = self.lookup_type.lookup(selector_lexp.type_id)?;
let selector_handle = get_expr_handle!(selector, selector_lexp);
let selector = match ctx.type_arena[selector_lty.handle].inner {
crate::TypeInner::Scalar {
crate::TypeInner::Scalar(crate::Scalar {
kind: crate::ScalarKind::Uint,
width: _,
} => {
}) => {
// IR expects a signed integer, so do a bitcast
ctx.expressions.append(
crate::Expression::As {
@ -3370,10 +3370,10 @@ impl<I: Iterator<Item = u32>> Frontend<I> {
span,
)
}
crate::TypeInner::Scalar {
crate::TypeInner::Scalar(crate::Scalar {
kind: crate::ScalarKind::Sint,
width: _,
} => selector_handle,
}) => selector_handle,
ref other => unimplemented!("Unexpected selector {:?}", other),
};
@ -4244,10 +4244,7 @@ impl<I: Iterator<Item = u32>> Frontend<I> {
self.switch(ModuleState::Type, inst.op)?;
inst.expect(2)?;
let id = self.next()?;
let inner = crate::TypeInner::Scalar {
kind: crate::ScalarKind::Bool,
width: crate::BOOL_WIDTH,
};
let inner = crate::TypeInner::Scalar(crate::Scalar::BOOL);
self.lookup_type.insert(
id,
LookupType {
@ -4275,14 +4272,14 @@ impl<I: Iterator<Item = u32>> Frontend<I> {
let id = self.next()?;
let width = self.next()?;
let sign = self.next()?;
let inner = crate::TypeInner::Scalar {
let inner = crate::TypeInner::Scalar(crate::Scalar {
kind: match sign {
0 => crate::ScalarKind::Uint,
1 => crate::ScalarKind::Sint,
_ => return Err(Error::InvalidSign(sign)),
},
width: map_width(width)?,
};
});
self.lookup_type.insert(
id,
LookupType {
@ -4309,10 +4306,7 @@ impl<I: Iterator<Item = u32>> Frontend<I> {
inst.expect(3)?;
let id = self.next()?;
let width = self.next()?;
let inner = crate::TypeInner::Scalar {
kind: crate::ScalarKind::Float,
width: map_width(width)?,
};
let inner = crate::TypeInner::Scalar(crate::Scalar::float(map_width(width)?));
self.lookup_type.insert(
id,
LookupType {
@ -4340,15 +4334,14 @@ impl<I: Iterator<Item = u32>> Frontend<I> {
let id = self.next()?;
let type_id = self.next()?;
let type_lookup = self.lookup_type.lookup(type_id)?;
let (kind, width) = match module.types[type_lookup.handle].inner {
crate::TypeInner::Scalar { kind, width } => (kind, width),
let scalar = match module.types[type_lookup.handle].inner {
crate::TypeInner::Scalar(scalar) => scalar,
_ => return Err(Error::InvalidInnerType(type_id)),
};
let component_count = self.next()?;
let inner = crate::TypeInner::Vector {
size: map_vector_size(component_count)?,
kind,
width,
scalar,
};
self.lookup_type.insert(
id,
@ -4381,10 +4374,10 @@ impl<I: Iterator<Item = u32>> Frontend<I> {
let vector_type_lookup = self.lookup_type.lookup(vector_type_id)?;
let inner = match module.types[vector_type_lookup.handle].inner {
crate::TypeInner::Vector { size, width, .. } => crate::TypeInner::Matrix {
crate::TypeInner::Vector { size, scalar } => crate::TypeInner::Matrix {
columns: map_vector_size(num_columns)?,
rows: size,
width,
width: scalar.width,
},
_ => return Err(Error::InvalidInnerType(vector_type_id)),
};
@ -4761,11 +4754,10 @@ impl<I: Iterator<Item = u32>> Frontend<I> {
crate::Type {
name: None,
inner: {
let kind = crate::ScalarKind::Float;
let width = 4;
let scalar = crate::Scalar::F32;
match dim.required_coordinate_size() {
None => crate::TypeInner::Scalar { kind, width },
Some(size) => crate::TypeInner::Vector { size, kind, width },
None => crate::TypeInner::Scalar(scalar),
Some(size) => crate::TypeInner::Vector { size, scalar },
}
},
},
@ -4870,30 +4862,30 @@ impl<I: Iterator<Item = u32>> Frontend<I> {
let ty = type_lookup.handle;
let literal = match module.types[ty].inner {
crate::TypeInner::Scalar {
crate::TypeInner::Scalar(crate::Scalar {
kind: crate::ScalarKind::Uint,
width,
} => {
}) => {
let low = self.next()?;
match width {
4 => crate::Literal::U32(low),
_ => return Err(Error::InvalidTypeWidth(width as u32)),
}
}
crate::TypeInner::Scalar {
crate::TypeInner::Scalar(crate::Scalar {
kind: crate::ScalarKind::Sint,
width,
} => {
}) => {
let low = self.next()?;
match width {
4 => crate::Literal::I32(low as i32),
_ => return Err(Error::InvalidTypeWidth(width as u32)),
}
}
crate::TypeInner::Scalar {
crate::TypeInner::Scalar(crate::Scalar {
kind: crate::ScalarKind::Float,
width,
} => {
}) => {
let low = self.next()?;
match width {
4 => crate::Literal::F32(f32::from_bits(low)),
@ -5167,17 +5159,15 @@ impl<I: Iterator<Item = u32>> Frontend<I> {
| crate::BuiltIn::SampleIndex
| crate::BuiltIn::VertexIndex
| crate::BuiltIn::PrimitiveIndex
| crate::BuiltIn::LocalInvocationIndex => Some(crate::TypeInner::Scalar {
kind: crate::ScalarKind::Uint,
width: 4,
}),
| crate::BuiltIn::LocalInvocationIndex => {
Some(crate::TypeInner::Scalar(crate::Scalar::U32))
}
crate::BuiltIn::GlobalInvocationId
| crate::BuiltIn::LocalInvocationId
| crate::BuiltIn::WorkGroupId
| crate::BuiltIn::WorkGroupSize => Some(crate::TypeInner::Vector {
size: crate::VectorSize::Tri,
kind: crate::ScalarKind::Uint,
width: 4,
scalar: crate::Scalar::U32,
}),
_ => None,
};

View File

@ -25,24 +25,17 @@ impl crate::Module {
return handle;
}
let width = 4;
let ty_flag = self.types.insert(
crate::Type {
name: None,
inner: crate::TypeInner::Scalar {
width,
kind: crate::ScalarKind::Uint,
},
inner: crate::TypeInner::Scalar(crate::Scalar::U32),
},
Span::UNDEFINED,
);
let ty_scalar = self.types.insert(
crate::Type {
name: None,
inner: crate::TypeInner::Scalar {
width,
kind: crate::ScalarKind::Float,
},
inner: crate::TypeInner::Scalar(crate::Scalar::F32),
},
Span::UNDEFINED,
);
@ -51,8 +44,7 @@ impl crate::Module {
name: None,
inner: crate::TypeInner::Vector {
size: crate::VectorSize::Tri,
kind: crate::ScalarKind::Float,
width,
scalar: crate::Scalar::F32,
},
},
Span::UNDEFINED,
@ -127,24 +119,17 @@ impl crate::Module {
return handle;
}
let width = 4;
let ty_flag = self.types.insert(
crate::Type {
name: None,
inner: crate::TypeInner::Scalar {
width,
kind: crate::ScalarKind::Uint,
},
inner: crate::TypeInner::Scalar(crate::Scalar::U32),
},
Span::UNDEFINED,
);
let ty_scalar = self.types.insert(
crate::Type {
name: None,
inner: crate::TypeInner::Scalar {
width,
kind: crate::ScalarKind::Float,
},
inner: crate::TypeInner::Scalar(crate::Scalar::F32),
},
Span::UNDEFINED,
);
@ -152,9 +137,8 @@ impl crate::Module {
crate::Type {
name: None,
inner: crate::TypeInner::Vector {
width,
size: crate::VectorSize::Bi,
kind: crate::ScalarKind::Float,
scalar: crate::Scalar::F32,
},
},
Span::UNDEFINED,
@ -162,10 +146,7 @@ impl crate::Module {
let ty_bool = self.types.insert(
crate::Type {
name: None,
inner: crate::TypeInner::Scalar {
width: crate::BOOL_WIDTH,
kind: crate::ScalarKind::Bool,
},
inner: crate::TypeInner::Scalar(crate::Scalar::BOOL),
},
Span::UNDEFINED,
);
@ -175,7 +156,7 @@ impl crate::Module {
inner: crate::TypeInner::Matrix {
columns: crate::VectorSize::Quad,
rows: crate::VectorSize::Tri,
width,
width: 4,
},
},
Span::UNDEFINED,
@ -277,28 +258,26 @@ impl crate::Module {
}
let ty = match special_type {
crate::PredeclaredType::AtomicCompareExchangeWeakResult { kind, width } => {
crate::PredeclaredType::AtomicCompareExchangeWeakResult(scalar) => {
let bool_ty = self.types.insert(
crate::Type {
name: None,
inner: crate::TypeInner::Scalar {
kind: crate::ScalarKind::Bool,
width: crate::BOOL_WIDTH,
},
inner: crate::TypeInner::Scalar(crate::Scalar::BOOL),
},
Span::UNDEFINED,
);
let scalar_ty = self.types.insert(
crate::Type {
name: None,
inner: crate::TypeInner::Scalar { kind, width },
inner: crate::TypeInner::Scalar(scalar),
},
Span::UNDEFINED,
);
crate::Type {
name: Some(format!(
"__atomic_compare_exchange_result<{kind:?},{width}>"
"__atomic_compare_exchange_result<{:?},{}>",
scalar.kind, scalar.width,
)),
inner: crate::TypeInner::Struct {
members: vec![
@ -323,10 +302,7 @@ impl crate::Module {
let float_ty = self.types.insert(
crate::Type {
name: None,
inner: crate::TypeInner::Scalar {
kind: crate::ScalarKind::Float,
width,
},
inner: crate::TypeInner::Scalar(crate::Scalar::float(width)),
},
Span::UNDEFINED,
);
@ -337,8 +313,7 @@ impl crate::Module {
name: None,
inner: crate::TypeInner::Vector {
size,
kind: crate::ScalarKind::Float,
width,
scalar: crate::Scalar::float(width),
},
},
Span::UNDEFINED,
@ -379,10 +354,7 @@ impl crate::Module {
let float_ty = self.types.insert(
crate::Type {
name: None,
inner: crate::TypeInner::Scalar {
kind: crate::ScalarKind::Float,
width,
},
inner: crate::TypeInner::Scalar(crate::Scalar::float(width)),
},
Span::UNDEFINED,
);
@ -390,10 +362,10 @@ impl crate::Module {
let int_ty = self.types.insert(
crate::Type {
name: None,
inner: crate::TypeInner::Scalar {
inner: crate::TypeInner::Scalar(crate::Scalar {
kind: crate::ScalarKind::Sint,
width,
},
}),
},
Span::UNDEFINED,
);
@ -404,8 +376,7 @@ impl crate::Module {
name: None,
inner: crate::TypeInner::Vector {
size,
kind: crate::ScalarKind::Float,
width,
scalar: crate::Scalar::float(width),
},
},
Span::UNDEFINED,
@ -415,8 +386,10 @@ impl crate::Module {
name: None,
inner: crate::TypeInner::Vector {
size,
kind: crate::ScalarKind::Sint,
width,
scalar: crate::Scalar {
kind: crate::ScalarKind::Sint,
width,
},
},
},
Span::UNDEFINED,

View File

@ -65,7 +65,7 @@ impl Constructor<(Handle<crate::Type>, &crate::TypeInner)> {
format!("mat{}x{}<?>", columns as u32, rows as u32,)
}
Self::PartialArray => "array<?, ?>".to_string(),
Self::Type((handle, _inner)) => ctx.format_type(handle),
Self::Type((handle, _inner)) => handle.to_wgsl(&ctx.module.to_ctx()),
}
}
}
@ -185,11 +185,11 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
ty_inner: &crate::TypeInner::Scalar { .. },
..
},
Constructor::Type((_, &crate::TypeInner::Scalar { kind, width })),
Constructor::Type((_, &crate::TypeInner::Scalar(scalar))),
) => crate::Expression::As {
expr: component,
kind,
convert: Some(width),
kind: scalar.kind,
convert: Some(scalar.width),
},
// Vector conversion (vector -> vector)
@ -203,14 +203,13 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
_,
&crate::TypeInner::Vector {
size: dst_size,
kind: dst_kind,
width: dst_width,
scalar: dst_scalar,
},
)),
) if dst_size == src_size => crate::Expression::As {
expr: component,
kind: dst_kind,
convert: Some(dst_width),
kind: dst_scalar.kind,
convert: Some(dst_scalar.width),
},
// Vector conversion (vector -> vector) - partial
@ -294,23 +293,17 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
(
Components::One {
component,
ty_inner:
&crate::TypeInner::Scalar {
kind: src_kind,
width: src_width,
..
},
ty_inner: &crate::TypeInner::Scalar(src_scalar),
..
},
Constructor::Type((
_,
&crate::TypeInner::Vector {
size,
kind: dst_kind,
width: dst_width,
scalar: dst_scalar,
},
)),
) if dst_kind == src_kind || dst_width == src_width => crate::Expression::Splat {
) if dst_scalar == src_scalar => crate::Expression::Splat {
size,
value: component,
},
@ -320,8 +313,7 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
Components::Many {
components,
first_component_ty_inner:
&crate::TypeInner::Scalar { kind, width }
| &crate::TypeInner::Vector { kind, width, .. },
&crate::TypeInner::Scalar(scalar) | &crate::TypeInner::Vector { scalar, .. },
..
},
Constructor::PartialVector { size },
@ -333,9 +325,9 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
&crate::TypeInner::Scalar { .. } | &crate::TypeInner::Vector { .. },
..
},
Constructor::Type((_, &crate::TypeInner::Vector { size, width, kind })),
Constructor::Type((_, &crate::TypeInner::Vector { size, scalar })),
) => {
let inner = crate::TypeInner::Vector { size, kind, width };
let inner = crate::TypeInner::Vector { size, scalar };
let ty = ctx.ensure_type_exists(inner);
crate::Expression::Compose { ty, components }
}
@ -344,7 +336,7 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
(
Components::Many {
components,
first_component_ty_inner: &crate::TypeInner::Scalar { width, .. },
first_component_ty_inner: &crate::TypeInner::Scalar(crate::Scalar { width, .. }),
..
},
Constructor::PartialMatrix { columns, rows },
@ -365,8 +357,7 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
)),
) => {
let vec_ty = ctx.ensure_type_exists(crate::TypeInner::Vector {
width,
kind: crate::ScalarKind::Float,
scalar: crate::Scalar::float(width),
size: rows,
});
@ -395,7 +386,11 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
(
Components::Many {
components,
first_component_ty_inner: &crate::TypeInner::Vector { width, .. },
first_component_ty_inner:
&crate::TypeInner::Vector {
scalar: crate::Scalar { width, .. },
..
},
..
},
Constructor::PartialMatrix { columns, rows },
@ -460,7 +455,7 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
// Bad conversion (type cast)
(Components::One { span, ty_inner, .. }, constructor) => {
let from_type = ctx.format_typeinner(ty_inner);
let from_type = ty_inner.to_wgsl(&ctx.module.to_ctx());
return Err(Error::BadTypeCast {
span,
from_type,

View File

@ -7,7 +7,6 @@ use crate::front::wgsl::parse::{ast, conv};
use crate::front::Typifier;
use crate::proc::{
ensure_block_returns, Alignment, ConstantEvaluator, Emitter, Layouter, ResolveContext,
TypeResolution,
};
use crate::{Arena, FastHashMap, FastIndexMap, Handle, Span};
@ -59,6 +58,8 @@ macro_rules! resolve_inner_binary {
/// Returns a &[`TypeResolution`].
///
/// See the documentation of [`resolve_inner!`] for why this macro is necessary.
///
/// [`TypeResolution`]: crate::proc::TypeResolution
macro_rules! resolve {
($ctx:ident, $expr:expr) => {{
$ctx.grow_types($expr)?;
@ -486,6 +487,7 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> {
/// [`resolve_inner!`] or [`resolve_inner_binary!`].
///
/// [`self.typifier`]: ExpressionContext::typifier
/// [`TypeResolution`]: crate::proc::TypeResolution
/// [`register_type`]: Self::register_type
/// [`Typifier`]: Typifier
fn grow_types(
@ -632,25 +634,6 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> {
}
}
fn format_typeinner(&self, inner: &crate::TypeInner) -> String {
inner.to_wgsl(self.module.to_ctx())
}
fn format_type(&self, handle: Handle<crate::Type>) -> String {
let ty = &self.module.types[handle];
match ty.name {
Some(ref name) => name.clone(),
None => self.format_typeinner(&ty.inner),
}
}
fn format_type_resolution(&self, resolution: &TypeResolution) -> String {
match *resolution {
TypeResolution::Handle(handle) => self.format_type(handle),
TypeResolution::Value(ref inner) => self.format_typeinner(inner),
}
}
fn ensure_type_exists(&mut self, inner: crate::TypeInner) -> Handle<crate::Type> {
self.as_global().ensure_type_exists(inner)
}
@ -925,22 +908,11 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
if let Some(explicit) = explicit_ty {
if explicit != inferred_type {
let ty = &ctx.module.types[explicit];
let expected = ty
.name
.clone()
.unwrap_or_else(|| ty.inner.to_wgsl(ctx.module.to_ctx()));
let ty = &ctx.module.types[inferred_type];
let got = ty
.name
.clone()
.unwrap_or_else(|| ty.inner.to_wgsl(ctx.module.to_ctx()));
let gctx = ctx.module.to_ctx();
return Err(Error::InitializationTypeMismatch {
name: c.name.span,
expected,
got,
expected: explicit.to_wgsl(&gctx),
got: inferred_type.to_wgsl(&gctx),
});
}
}
@ -1128,10 +1100,11 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
.inner
.equivalent(&ctx.module.types[init_ty].inner, &ctx.module.types)
{
let gctx = &ctx.module.to_ctx();
return Err(Error::InitializationTypeMismatch {
name: l.name.span,
expected: ctx.format_type(ty),
got: ctx.format_type(init_ty),
expected: ty.to_wgsl(gctx),
got: init_ty.to_wgsl(gctx),
});
}
}
@ -1166,10 +1139,11 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
.inner
.equivalent(initializer_ty, &ctx.module.types)
{
let gctx = &ctx.module.to_ctx();
return Err(Error::InitializationTypeMismatch {
name: v.name.span,
expected: ctx.format_type(explicit),
got: ctx.format_typeinner(initializer_ty),
expected: explicit.to_wgsl(gctx),
got: initializer_ty.to_wgsl(gctx),
});
}
explicit
@ -1413,22 +1387,19 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
};
let mut ectx = ctx.as_expression(block, &mut emitter);
let (kind, width) = match *resolve_inner!(ectx, target_handle) {
let scalar = match *resolve_inner!(ectx, target_handle) {
crate::TypeInner::ValuePointer {
size: None,
kind,
width,
..
} => (kind, width),
size: None, scalar, ..
} => scalar,
crate::TypeInner::Pointer { base, .. } => match ectx.module.types[base].inner {
crate::TypeInner::Scalar { kind, width } => (kind, width),
crate::TypeInner::Scalar(scalar) => scalar,
_ => return Err(Error::BadIncrDecrReferenceType(value_span)),
},
_ => return Err(Error::BadIncrDecrReferenceType(value_span)),
};
let literal = match kind {
let literal = match scalar.kind {
crate::ScalarKind::Sint | crate::ScalarKind::Uint => {
crate::Literal::one(kind, width)
crate::Literal::one(scalar)
.ok_or(Error::BadIncrDecrReferenceType(value_span))?
}
_ => return Err(Error::BadIncrDecrReferenceType(value_span)),
@ -1608,21 +1579,17 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
match *inner {
crate::TypeInner::Pointer { base, .. } => &ctx.module.types[base].inner,
crate::TypeInner::ValuePointer {
size: None,
kind,
width,
..
size: None, scalar, ..
} => {
temp_inner = crate::TypeInner::Scalar { kind, width };
temp_inner = crate::TypeInner::Scalar(scalar);
&temp_inner
}
crate::TypeInner::ValuePointer {
size: Some(size),
kind,
width,
scalar,
..
} => {
temp_inner = crate::TypeInner::Vector { size, kind, width };
temp_inner = crate::TypeInner::Vector { size, scalar };
&temp_inner
}
_ => unreachable!(
@ -1679,22 +1646,23 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
let expr = self.expression(expr, ctx)?;
let to_resolved = self.resolve_ast_type(to, &mut ctx.as_global())?;
let kind = match ctx.module.types[to_resolved].inner {
crate::TypeInner::Scalar { kind, .. } => kind,
crate::TypeInner::Vector { kind, .. } => kind,
let element_scalar = match ctx.module.types[to_resolved].inner {
crate::TypeInner::Scalar(scalar) => scalar,
crate::TypeInner::Vector { scalar, .. } => scalar,
_ => {
let ty = resolve!(ctx, expr);
let gctx = &ctx.module.to_ctx();
return Err(Error::BadTypeCast {
from_type: ctx.format_type_resolution(ty),
from_type: ty.to_wgsl(gctx),
span: ty_span,
to_type: ctx.format_type(to_resolved),
to_type: to_resolved.to_wgsl(gctx),
});
}
};
Typed::Plain(crate::Expression::As {
expr,
kind,
kind: element_scalar.kind,
convert: None,
})
}
@ -1785,10 +1753,10 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
) && {
matches!(
resolve_inner!(ctx, argument),
&crate::TypeInner::Scalar {
&crate::TypeInner::Scalar(crate::Scalar {
kind: crate::ScalarKind::Bool,
..
}
})
)
};
@ -1828,10 +1796,14 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
if fun == crate::MathFunction::Modf || fun == crate::MathFunction::Frexp {
if let Some((size, width)) = match *resolve_inner!(ctx, arg) {
crate::TypeInner::Scalar { width, .. } => Some((None, width)),
crate::TypeInner::Vector { size, width, .. } => {
Some((Some(size), width))
crate::TypeInner::Scalar(crate::Scalar { width, .. }) => {
Some((None, width))
}
crate::TypeInner::Vector {
size,
scalar: crate::Scalar { width, .. },
..
} => Some((Some(size), width)),
_ => None,
} {
ctx.module.generate_predeclared_type(
@ -1976,13 +1948,12 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
args.finish()?;
let expression = match *resolve_inner!(ctx, value) {
crate::TypeInner::Scalar { kind, width } => {
crate::TypeInner::Scalar(scalar) => {
crate::Expression::AtomicResult {
ty: ctx.module.generate_predeclared_type(
crate::PredeclaredType::AtomicCompareExchangeWeakResult {
kind,
width,
},
crate::PredeclaredType::AtomicCompareExchangeWeakResult(
scalar,
),
),
comparison: true,
}

View File

@ -10,6 +10,7 @@ mod lower;
mod parse;
#[cfg(test)]
mod tests;
mod to_wgsl;
use crate::front::wgsl::error::Error;
use crate::front::wgsl::parse::Parser;
@ -17,6 +18,7 @@ use thiserror::Error;
pub use crate::front::wgsl::error::ParseError;
use crate::front::wgsl::lower::Lowerer;
use crate::Scalar;
pub struct Frontend {
parser: Parser,
@ -45,296 +47,3 @@ impl Frontend {
pub fn parse_str(source: &str) -> Result<crate::Module, ParseError> {
Frontend::new().parse(source)
}
impl crate::StorageFormat {
const fn to_wgsl(self) -> &'static str {
use crate::StorageFormat as Sf;
match self {
Sf::R8Unorm => "r8unorm",
Sf::R8Snorm => "r8snorm",
Sf::R8Uint => "r8uint",
Sf::R8Sint => "r8sint",
Sf::R16Uint => "r16uint",
Sf::R16Sint => "r16sint",
Sf::R16Float => "r16float",
Sf::Rg8Unorm => "rg8unorm",
Sf::Rg8Snorm => "rg8snorm",
Sf::Rg8Uint => "rg8uint",
Sf::Rg8Sint => "rg8sint",
Sf::R32Uint => "r32uint",
Sf::R32Sint => "r32sint",
Sf::R32Float => "r32float",
Sf::Rg16Uint => "rg16uint",
Sf::Rg16Sint => "rg16sint",
Sf::Rg16Float => "rg16float",
Sf::Rgba8Unorm => "rgba8unorm",
Sf::Rgba8Snorm => "rgba8snorm",
Sf::Rgba8Uint => "rgba8uint",
Sf::Rgba8Sint => "rgba8sint",
Sf::Bgra8Unorm => "bgra8unorm",
Sf::Rgb10a2Uint => "rgb10a2uint",
Sf::Rgb10a2Unorm => "rgb10a2unorm",
Sf::Rg11b10Float => "rg11b10float",
Sf::Rg32Uint => "rg32uint",
Sf::Rg32Sint => "rg32sint",
Sf::Rg32Float => "rg32float",
Sf::Rgba16Uint => "rgba16uint",
Sf::Rgba16Sint => "rgba16sint",
Sf::Rgba16Float => "rgba16float",
Sf::Rgba32Uint => "rgba32uint",
Sf::Rgba32Sint => "rgba32sint",
Sf::Rgba32Float => "rgba32float",
Sf::R16Unorm => "r16unorm",
Sf::R16Snorm => "r16snorm",
Sf::Rg16Unorm => "rg16unorm",
Sf::Rg16Snorm => "rg16snorm",
Sf::Rgba16Unorm => "rgba16unorm",
Sf::Rgba16Snorm => "rgba16snorm",
}
}
}
impl crate::TypeInner {
/// Formats the type as it is written in wgsl.
///
/// For example `vec3<f32>`.
///
/// Note: The names of a `TypeInner::Struct` is not known. Therefore this method will simply return "struct" for them.
fn to_wgsl(&self, gctx: crate::proc::GlobalCtx) -> String {
use crate::TypeInner as Ti;
match *self {
Ti::Scalar { kind, width } => Scalar { kind, width }.to_wgsl(),
Ti::Vector { size, kind, width } => {
let scalar = Scalar { kind, width };
format!("vec{}<{}>", size as u32, scalar.to_wgsl())
}
Ti::Matrix {
columns,
rows,
width,
} => {
format!(
"mat{}x{}<{}>",
columns as u32,
rows as u32,
Scalar {
kind: crate::ScalarKind::Float,
width
}
.to_wgsl(),
)
}
Ti::Atomic { kind, width } => {
format!("atomic<{}>", Scalar { kind, width }.to_wgsl())
}
Ti::Pointer { base, .. } => {
let base = &gctx.types[base];
let name = base.name.as_deref().unwrap_or("unknown");
format!("ptr<{name}>")
}
Ti::ValuePointer { kind, width, .. } => {
format!("ptr<{}>", Scalar { kind, width }.to_wgsl())
}
Ti::Array { base, size, .. } => {
let member_type = &gctx.types[base];
let base = member_type.name.as_deref().unwrap_or("unknown");
match size {
crate::ArraySize::Constant(size) => format!("array<{base}, {size}>"),
crate::ArraySize::Dynamic => format!("array<{base}>"),
}
}
Ti::Struct { .. } => {
// TODO: Actually output the struct?
"struct".to_string()
}
Ti::Image {
dim,
arrayed,
class,
} => {
let dim_suffix = match dim {
crate::ImageDimension::D1 => "_1d",
crate::ImageDimension::D2 => "_2d",
crate::ImageDimension::D3 => "_3d",
crate::ImageDimension::Cube => "_cube",
};
let array_suffix = if arrayed { "_array" } else { "" };
let class_suffix = match class {
crate::ImageClass::Sampled { multi: true, .. } => "_multisampled",
crate::ImageClass::Depth { multi: false } => "_depth",
crate::ImageClass::Depth { multi: true } => "_depth_multisampled",
crate::ImageClass::Sampled { multi: false, .. }
| crate::ImageClass::Storage { .. } => "",
};
let type_in_brackets = match class {
crate::ImageClass::Sampled { kind, .. } => {
// Note: The only valid widths are 4 bytes wide.
// The lexer has already verified this, so we can safely assume it here.
// https://gpuweb.github.io/gpuweb/wgsl/#sampled-texture-type
let element_type = Scalar { kind, width: 4 }.to_wgsl();
format!("<{element_type}>")
}
crate::ImageClass::Depth { multi: _ } => String::new(),
crate::ImageClass::Storage { format, access } => {
if access.contains(crate::StorageAccess::STORE) {
format!("<{},write>", format.to_wgsl())
} else {
format!("<{}>", format.to_wgsl())
}
}
};
format!("texture{class_suffix}{dim_suffix}{array_suffix}{type_in_brackets}")
}
Ti::Sampler { .. } => "sampler".to_string(),
Ti::AccelerationStructure => "acceleration_structure".to_string(),
Ti::RayQuery => "ray_query".to_string(),
Ti::BindingArray { base, size, .. } => {
let member_type = &gctx.types[base];
let base = member_type.name.as_deref().unwrap_or("unknown");
match size {
crate::ArraySize::Constant(size) => format!("binding_array<{base}, {size}>"),
crate::ArraySize::Dynamic => format!("binding_array<{base}>"),
}
}
}
}
}
mod type_inner_tests {
#[test]
fn to_wgsl() {
use std::num::NonZeroU32;
let mut types = crate::UniqueArena::new();
let mytype1 = types.insert(
crate::Type {
name: Some("MyType1".to_string()),
inner: crate::TypeInner::Struct {
members: vec![],
span: 0,
},
},
Default::default(),
);
let mytype2 = types.insert(
crate::Type {
name: Some("MyType2".to_string()),
inner: crate::TypeInner::Struct {
members: vec![],
span: 0,
},
},
Default::default(),
);
let gctx = crate::proc::GlobalCtx {
types: &types,
constants: &crate::Arena::new(),
const_expressions: &crate::Arena::new(),
};
let array = crate::TypeInner::Array {
base: mytype1,
stride: 4,
size: crate::ArraySize::Constant(unsafe { NonZeroU32::new_unchecked(32) }),
};
assert_eq!(array.to_wgsl(gctx), "array<MyType1, 32>");
let mat = crate::TypeInner::Matrix {
rows: crate::VectorSize::Quad,
columns: crate::VectorSize::Bi,
width: 8,
};
assert_eq!(mat.to_wgsl(gctx), "mat2x4<f64>");
let ptr = crate::TypeInner::Pointer {
base: mytype2,
space: crate::AddressSpace::Storage {
access: crate::StorageAccess::default(),
},
};
assert_eq!(ptr.to_wgsl(gctx), "ptr<MyType2>");
let img1 = crate::TypeInner::Image {
dim: crate::ImageDimension::D2,
arrayed: false,
class: crate::ImageClass::Sampled {
kind: crate::ScalarKind::Float,
multi: true,
},
};
assert_eq!(img1.to_wgsl(gctx), "texture_multisampled_2d<f32>");
let img2 = crate::TypeInner::Image {
dim: crate::ImageDimension::Cube,
arrayed: true,
class: crate::ImageClass::Depth { multi: false },
};
assert_eq!(img2.to_wgsl(gctx), "texture_depth_cube_array");
let img3 = crate::TypeInner::Image {
dim: crate::ImageDimension::D2,
arrayed: false,
class: crate::ImageClass::Depth { multi: true },
};
assert_eq!(img3.to_wgsl(gctx), "texture_depth_multisampled_2d");
let array = crate::TypeInner::BindingArray {
base: mytype1,
size: crate::ArraySize::Constant(unsafe { NonZeroU32::new_unchecked(32) }),
};
assert_eq!(array.to_wgsl(gctx), "binding_array<MyType1, 32>");
}
}
/// Characteristics of a scalar type.
#[derive(Clone, Copy, Debug)]
pub struct Scalar {
/// How the value's bits are to be interpreted.
pub kind: crate::ScalarKind,
/// The size of the value in bytes.
pub width: crate::Bytes,
}
impl Scalar {
/// Format a scalar kind+width as a type is written in wgsl.
///
/// Examples: `f32`, `u64`, `bool`.
fn to_wgsl(self) -> String {
let prefix = match self.kind {
crate::ScalarKind::Sint => "i",
crate::ScalarKind::Uint => "u",
crate::ScalarKind::Float => "f",
crate::ScalarKind::Bool => return "bool".to_string(),
};
format!("{}{}", prefix, self.width * 8)
}
const fn to_inner_scalar(self) -> crate::TypeInner {
crate::TypeInner::Scalar {
kind: self.kind,
width: self.width,
}
}
const fn to_inner_vector(self, size: crate::VectorSize) -> crate::TypeInner {
crate::TypeInner::Vector {
size,
kind: self.kind,
width: self.width,
}
}
const fn to_inner_atomic(self) -> crate::TypeInner {
crate::TypeInner::Atomic {
kind: self.kind,
width: self.width,
}
}
}

View File

@ -307,10 +307,7 @@ impl Parser {
"vec2f" => {
return Ok(Some(ast::ConstructorType::Vector {
size: crate::VectorSize::Bi,
scalar: Scalar {
kind: crate::ScalarKind::Float,
width: 4,
},
scalar: Scalar::F32,
}))
}
"vec3" => ast::ConstructorType::PartialVector {
@ -319,28 +316,19 @@ impl Parser {
"vec3i" => {
return Ok(Some(ast::ConstructorType::Vector {
size: crate::VectorSize::Tri,
scalar: Scalar {
kind: crate::ScalarKind::Sint,
width: 4,
},
scalar: Scalar::I32,
}))
}
"vec3u" => {
return Ok(Some(ast::ConstructorType::Vector {
size: crate::VectorSize::Tri,
scalar: Scalar {
kind: crate::ScalarKind::Uint,
width: 4,
},
scalar: Scalar::U32,
}))
}
"vec3f" => {
return Ok(Some(ast::ConstructorType::Vector {
size: crate::VectorSize::Tri,
scalar: Scalar {
kind: crate::ScalarKind::Float,
width: 4,
},
scalar: Scalar::F32,
}))
}
"vec4" => ast::ConstructorType::PartialVector {
@ -349,28 +337,19 @@ impl Parser {
"vec4i" => {
return Ok(Some(ast::ConstructorType::Vector {
size: crate::VectorSize::Quad,
scalar: Scalar {
kind: crate::ScalarKind::Sint,
width: 4,
},
scalar: Scalar::I32,
}))
}
"vec4u" => {
return Ok(Some(ast::ConstructorType::Vector {
size: crate::VectorSize::Quad,
scalar: Scalar {
kind: crate::ScalarKind::Uint,
width: 4,
},
scalar: Scalar::U32,
}))
}
"vec4f" => {
return Ok(Some(ast::ConstructorType::Vector {
size: crate::VectorSize::Quad,
scalar: Scalar {
kind: crate::ScalarKind::Float,
width: 4,
},
scalar: Scalar::F32,
}))
}
"mat2x2" => ast::ConstructorType::PartialMatrix {
@ -1109,10 +1088,7 @@ impl Parser {
},
"vec2f" => ast::Type::Vector {
size: crate::VectorSize::Bi,
scalar: Scalar {
kind: crate::ScalarKind::Float,
width: 4,
},
scalar: Scalar::F32,
},
"vec3" => {
let scalar = lexer.next_scalar_generic()?;
@ -1137,10 +1113,7 @@ impl Parser {
},
"vec3f" => ast::Type::Vector {
size: crate::VectorSize::Tri,
scalar: Scalar {
kind: crate::ScalarKind::Float,
width: 4,
},
scalar: Scalar::F32,
},
"vec4" => {
let scalar = lexer.next_scalar_generic()?;
@ -1165,10 +1138,7 @@ impl Parser {
},
"vec4f" => ast::Type::Vector {
size: crate::VectorSize::Quad,
scalar: Scalar {
kind: crate::ScalarKind::Float,
width: 4,
},
scalar: Scalar::F32,
},
"mat2x2" => {
self.matrix_scalar_type(lexer, crate::VectorSize::Bi, crate::VectorSize::Bi)?

View File

@ -0,0 +1,283 @@
//! Producing the WGSL forms of types, for use in error messages.
use crate::proc::GlobalCtx;
use crate::Handle;
impl crate::proc::TypeResolution {
pub fn to_wgsl(&self, gctx: &GlobalCtx) -> String {
match *self {
crate::proc::TypeResolution::Handle(handle) => handle.to_wgsl(gctx),
crate::proc::TypeResolution::Value(ref inner) => inner.to_wgsl(gctx),
}
}
}
impl Handle<crate::Type> {
/// Formats the type as it is written in wgsl.
///
/// For example `vec3<f32>`.
pub fn to_wgsl(self, gctx: &GlobalCtx) -> String {
let ty = &gctx.types[self];
match ty.name {
Some(ref name) => name.clone(),
None => ty.inner.to_wgsl(gctx),
}
}
}
impl crate::TypeInner {
/// Formats the type as it is written in wgsl.
///
/// For example `vec3<f32>`.
///
/// Note: `TypeInner::Struct` doesn't include the name of the
/// struct type. Therefore this method will simply return "struct"
/// for them.
pub fn to_wgsl(&self, gctx: &GlobalCtx) -> String {
use crate::TypeInner as Ti;
match *self {
Ti::Scalar(scalar) => scalar.to_wgsl(),
Ti::Vector { size, scalar } => {
format!("vec{}<{}>", size as u32, scalar.to_wgsl())
}
Ti::Matrix {
columns,
rows,
width,
} => {
format!(
"mat{}x{}<{}>",
columns as u32,
rows as u32,
crate::Scalar::float(width).to_wgsl(),
)
}
Ti::Atomic(scalar) => {
format!("atomic<{}>", scalar.to_wgsl())
}
Ti::Pointer { base, .. } => {
let base = &gctx.types[base];
let name = base.name.as_deref().unwrap_or("unknown");
format!("ptr<{name}>")
}
Ti::ValuePointer { scalar, .. } => {
format!("ptr<{}>", scalar.to_wgsl())
}
Ti::Array { base, size, .. } => {
let member_type = &gctx.types[base];
let base = member_type.name.as_deref().unwrap_or("unknown");
match size {
crate::ArraySize::Constant(size) => format!("array<{base}, {size}>"),
crate::ArraySize::Dynamic => format!("array<{base}>"),
}
}
Ti::Struct { .. } => {
// TODO: Actually output the struct?
"struct".to_string()
}
Ti::Image {
dim,
arrayed,
class,
} => {
let dim_suffix = match dim {
crate::ImageDimension::D1 => "_1d",
crate::ImageDimension::D2 => "_2d",
crate::ImageDimension::D3 => "_3d",
crate::ImageDimension::Cube => "_cube",
};
let array_suffix = if arrayed { "_array" } else { "" };
let class_suffix = match class {
crate::ImageClass::Sampled { multi: true, .. } => "_multisampled",
crate::ImageClass::Depth { multi: false } => "_depth",
crate::ImageClass::Depth { multi: true } => "_depth_multisampled",
crate::ImageClass::Sampled { multi: false, .. }
| crate::ImageClass::Storage { .. } => "",
};
let type_in_brackets = match class {
crate::ImageClass::Sampled { kind, .. } => {
// Note: The only valid widths are 4 bytes wide.
// The lexer has already verified this, so we can safely assume it here.
// https://gpuweb.github.io/gpuweb/wgsl/#sampled-texture-type
let element_type = crate::Scalar { kind, width: 4 }.to_wgsl();
format!("<{element_type}>")
}
crate::ImageClass::Depth { multi: _ } => String::new(),
crate::ImageClass::Storage { format, access } => {
if access.contains(crate::StorageAccess::STORE) {
format!("<{},write>", format.to_wgsl())
} else {
format!("<{}>", format.to_wgsl())
}
}
};
format!("texture{class_suffix}{dim_suffix}{array_suffix}{type_in_brackets}")
}
Ti::Sampler { .. } => "sampler".to_string(),
Ti::AccelerationStructure => "acceleration_structure".to_string(),
Ti::RayQuery => "ray_query".to_string(),
Ti::BindingArray { base, size, .. } => {
let member_type = &gctx.types[base];
let base = member_type.name.as_deref().unwrap_or("unknown");
match size {
crate::ArraySize::Constant(size) => format!("binding_array<{base}, {size}>"),
crate::ArraySize::Dynamic => format!("binding_array<{base}>"),
}
}
}
}
}
impl crate::Scalar {
/// Format a scalar kind+width as a type is written in wgsl.
///
/// Examples: `f32`, `u64`, `bool`.
pub fn to_wgsl(self) -> String {
let prefix = match self.kind {
crate::ScalarKind::Sint => "i",
crate::ScalarKind::Uint => "u",
crate::ScalarKind::Float => "f",
crate::ScalarKind::Bool => return "bool".to_string(),
};
format!("{}{}", prefix, self.width * 8)
}
}
impl crate::StorageFormat {
pub const fn to_wgsl(self) -> &'static str {
use crate::StorageFormat as Sf;
match self {
Sf::R8Unorm => "r8unorm",
Sf::R8Snorm => "r8snorm",
Sf::R8Uint => "r8uint",
Sf::R8Sint => "r8sint",
Sf::R16Uint => "r16uint",
Sf::R16Sint => "r16sint",
Sf::R16Float => "r16float",
Sf::Rg8Unorm => "rg8unorm",
Sf::Rg8Snorm => "rg8snorm",
Sf::Rg8Uint => "rg8uint",
Sf::Rg8Sint => "rg8sint",
Sf::R32Uint => "r32uint",
Sf::R32Sint => "r32sint",
Sf::R32Float => "r32float",
Sf::Rg16Uint => "rg16uint",
Sf::Rg16Sint => "rg16sint",
Sf::Rg16Float => "rg16float",
Sf::Rgba8Unorm => "rgba8unorm",
Sf::Rgba8Snorm => "rgba8snorm",
Sf::Rgba8Uint => "rgba8uint",
Sf::Rgba8Sint => "rgba8sint",
Sf::Bgra8Unorm => "bgra8unorm",
Sf::Rgb10a2Uint => "rgb10a2uint",
Sf::Rgb10a2Unorm => "rgb10a2unorm",
Sf::Rg11b10Float => "rg11b10float",
Sf::Rg32Uint => "rg32uint",
Sf::Rg32Sint => "rg32sint",
Sf::Rg32Float => "rg32float",
Sf::Rgba16Uint => "rgba16uint",
Sf::Rgba16Sint => "rgba16sint",
Sf::Rgba16Float => "rgba16float",
Sf::Rgba32Uint => "rgba32uint",
Sf::Rgba32Sint => "rgba32sint",
Sf::Rgba32Float => "rgba32float",
Sf::R16Unorm => "r16unorm",
Sf::R16Snorm => "r16snorm",
Sf::Rg16Unorm => "rg16unorm",
Sf::Rg16Snorm => "rg16snorm",
Sf::Rgba16Unorm => "rgba16unorm",
Sf::Rgba16Snorm => "rgba16snorm",
}
}
}
mod tests {
#[test]
fn to_wgsl() {
use std::num::NonZeroU32;
let mut types = crate::UniqueArena::new();
let mytype1 = types.insert(
crate::Type {
name: Some("MyType1".to_string()),
inner: crate::TypeInner::Struct {
members: vec![],
span: 0,
},
},
Default::default(),
);
let mytype2 = types.insert(
crate::Type {
name: Some("MyType2".to_string()),
inner: crate::TypeInner::Struct {
members: vec![],
span: 0,
},
},
Default::default(),
);
let gctx = crate::proc::GlobalCtx {
types: &types,
constants: &crate::Arena::new(),
const_expressions: &crate::Arena::new(),
};
let array = crate::TypeInner::Array {
base: mytype1,
stride: 4,
size: crate::ArraySize::Constant(unsafe { NonZeroU32::new_unchecked(32) }),
};
assert_eq!(array.to_wgsl(&gctx), "array<MyType1, 32>");
let mat = crate::TypeInner::Matrix {
rows: crate::VectorSize::Quad,
columns: crate::VectorSize::Bi,
width: 8,
};
assert_eq!(mat.to_wgsl(&gctx), "mat2x4<f64>");
let ptr = crate::TypeInner::Pointer {
base: mytype2,
space: crate::AddressSpace::Storage {
access: crate::StorageAccess::default(),
},
};
assert_eq!(ptr.to_wgsl(&gctx), "ptr<MyType2>");
let img1 = crate::TypeInner::Image {
dim: crate::ImageDimension::D2,
arrayed: false,
class: crate::ImageClass::Sampled {
kind: crate::ScalarKind::Float,
multi: true,
},
};
assert_eq!(img1.to_wgsl(&gctx), "texture_multisampled_2d<f32>");
let img2 = crate::TypeInner::Image {
dim: crate::ImageDimension::Cube,
arrayed: true,
class: crate::ImageClass::Depth { multi: false },
};
assert_eq!(img2.to_wgsl(&gctx), "texture_depth_cube_array");
let img3 = crate::TypeInner::Image {
dim: crate::ImageDimension::D2,
arrayed: false,
class: crate::ImageClass::Depth { multi: true },
};
assert_eq!(img3.to_wgsl(&gctx), "texture_depth_multisampled_2d");
let array = crate::TypeInner::BindingArray {
base: mytype1,
size: crate::ArraySize::Constant(unsafe { NonZeroU32::new_unchecked(32) }),
};
assert_eq!(array.to_wgsl(&gctx), "binding_array<MyType1, 32>");
}
}

View File

@ -472,6 +472,19 @@ pub enum ScalarKind {
Bool,
}
/// Characteristics of a scalar type.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
pub struct Scalar {
/// How the value's bits are to be interpreted.
pub kind: ScalarKind,
/// This size of the value in bytes.
pub width: Bytes,
}
/// Size of an array.
#[repr(u8)]
#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
@ -677,13 +690,9 @@ pub struct Type {
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
pub enum TypeInner {
/// Number of integral or floating-point kind.
Scalar { kind: ScalarKind, width: Bytes },
Scalar(Scalar),
/// Vector of numbers.
Vector {
size: VectorSize,
kind: ScalarKind,
width: Bytes,
},
Vector { size: VectorSize, scalar: Scalar },
/// Matrix of floats.
Matrix {
columns: VectorSize,
@ -691,7 +700,7 @@ pub enum TypeInner {
width: Bytes,
},
/// Atomic scalar.
Atomic { kind: ScalarKind, width: Bytes },
Atomic(Scalar),
/// Pointer to another type.
///
/// Pointers to scalars and vectors should be treated as equivalent to
@ -737,8 +746,7 @@ pub enum TypeInner {
/// [`TypeResolution::Value`]: proc::TypeResolution::Value
ValuePointer {
size: Option<VectorSize>,
kind: ScalarKind,
width: Bytes,
scalar: Scalar,
space: AddressSpace,
},
@ -1966,10 +1974,7 @@ pub struct EntryPoint {
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
pub enum PredeclaredType {
AtomicCompareExchangeWeakResult {
kind: ScalarKind,
width: Bytes,
},
AtomicCompareExchangeWeakResult(Scalar),
ModfResult {
size: Option<VectorSize>,
width: Bytes,

View File

@ -404,7 +404,7 @@ impl<'a> ConstantEvaluator<'a> {
let expr = self.check_and_get(expr)?;
match convert {
Some(width) => self.cast(expr, kind, width, span),
Some(width) => self.cast(expr, crate::Scalar { kind, width }, span),
None => Err(ConstantEvaluatorError::NotImplemented(
"bitcast built-in function".into(),
)),
@ -462,12 +462,11 @@ impl<'a> ConstantEvaluator<'a> {
) -> Result<Handle<Expression>, ConstantEvaluatorError> {
match self.expressions[value] {
Expression::Literal(literal) => {
let kind = literal.scalar_kind();
let width = literal.width();
let scalar = literal.scalar();
let ty = self.types.insert(
Type {
name: None,
inner: TypeInner::Vector { size, kind, width },
inner: TypeInner::Vector { size, scalar },
},
span,
);
@ -479,7 +478,7 @@ impl<'a> ConstantEvaluator<'a> {
}
Expression::ZeroValue(ty) => {
let inner = match self.types[ty].inner {
TypeInner::Scalar { kind, width } => TypeInner::Vector { size, kind, width },
TypeInner::Scalar(scalar) => TypeInner::Vector { size, scalar },
_ => return Err(ConstantEvaluatorError::SplatScalarOnly),
};
let res_ty = self.types.insert(Type { name: None, inner }, span);
@ -498,14 +497,10 @@ impl<'a> ConstantEvaluator<'a> {
pattern: [crate::SwizzleComponent; 4],
) -> Result<Handle<Expression>, ConstantEvaluatorError> {
let mut get_dst_ty = |ty| match self.types[ty].inner {
crate::TypeInner::Vector {
size: _,
kind,
width,
} => Ok(self.types.insert(
crate::TypeInner::Vector { size: _, scalar } => Ok(self.types.insert(
Type {
name: None,
inner: crate::TypeInner::Vector { size, kind, width },
inner: crate::TypeInner::Vector { size, scalar },
},
span,
)),
@ -611,7 +606,10 @@ impl<'a> ConstantEvaluator<'a> {
&& matches!(
self.types[ty0].inner,
crate::TypeInner::Vector {
kind: crate::ScalarKind::Float,
scalar: crate::Scalar {
kind: ScalarKind::Float,
..
},
..
}
) =>
@ -709,7 +707,10 @@ impl<'a> ConstantEvaluator<'a> {
&& matches!(
self.types[ty0].inner,
crate::TypeInner::Vector {
kind: crate::ScalarKind::Float,
scalar: crate::Scalar {
kind: ScalarKind::Float,
..
},
..
}
) =>
@ -831,10 +832,10 @@ impl<'a> ConstantEvaluator<'a> {
Expression::ZeroValue(ty)
if matches!(
self.types[ty].inner,
crate::TypeInner::Scalar {
kind: crate::ScalarKind::Uint,
crate::TypeInner::Scalar(crate::Scalar {
kind: ScalarKind::Uint,
..
}
})
) =>
{
Ok(0)
@ -873,18 +874,17 @@ impl<'a> ConstantEvaluator<'a> {
span: Span,
) -> Result<Handle<Expression>, ConstantEvaluatorError> {
match self.types[ty].inner {
TypeInner::Scalar { kind, width } => {
TypeInner::Scalar(scalar) => {
let expr = Expression::Literal(
Literal::zero(kind, width)
.ok_or(ConstantEvaluatorError::TypeNotConstructible)?,
Literal::zero(scalar).ok_or(ConstantEvaluatorError::TypeNotConstructible)?,
);
self.register_evaluated_expr(expr, span)
}
TypeInner::Vector { size, kind, width } => {
TypeInner::Vector { size, scalar } => {
let scalar_ty = self.types.insert(
Type {
name: None,
inner: TypeInner::Scalar { kind, width },
inner: TypeInner::Scalar(scalar),
},
span,
);
@ -905,8 +905,7 @@ impl<'a> ConstantEvaluator<'a> {
name: None,
inner: TypeInner::Vector {
size: rows,
kind: ScalarKind::Float,
width,
scalar: crate::Scalar::float(width),
},
},
span,
@ -943,43 +942,44 @@ impl<'a> ConstantEvaluator<'a> {
}
}
/// Convert the scalar components of `expr` to `kind` and `target_width`.
/// Convert the scalar components of `expr` to `target`.
///
/// Treat `span` as the location of the resulting expression.
pub fn cast(
&mut self,
expr: Handle<Expression>,
kind: ScalarKind,
target_width: crate::Bytes,
target: crate::Scalar,
span: Span,
) -> Result<Handle<Expression>, ConstantEvaluatorError> {
use crate::Scalar as Sc;
let expr = self.eval_zero_value_and_splat(expr, span)?;
let expr = match self.expressions[expr] {
Expression::Literal(literal) => {
let literal = match (kind, target_width) {
(ScalarKind::Sint, 4) => Literal::I32(match literal {
let literal = match target {
Sc::I32 => Literal::I32(match literal {
Literal::I32(v) => v,
Literal::U32(v) => v as i32,
Literal::F32(v) => v as i32,
Literal::Bool(v) => v as i32,
Literal::F64(_) => return Err(ConstantEvaluatorError::InvalidCastArg),
}),
(ScalarKind::Uint, 4) => Literal::U32(match literal {
Sc::U32 => Literal::U32(match literal {
Literal::I32(v) => v as u32,
Literal::U32(v) => v,
Literal::F32(v) => v as u32,
Literal::Bool(v) => v as u32,
Literal::F64(_) => return Err(ConstantEvaluatorError::InvalidCastArg),
}),
(ScalarKind::Float, 4) => Literal::F32(match literal {
Sc::F32 => Literal::F32(match literal {
Literal::I32(v) => v as f32,
Literal::U32(v) => v as f32,
Literal::F32(v) => v,
Literal::Bool(v) => v as u32 as f32,
Literal::F64(_) => return Err(ConstantEvaluatorError::InvalidCastArg),
}),
(ScalarKind::Bool, crate::BOOL_WIDTH) => Literal::Bool(match literal {
Sc::BOOL => Literal::Bool(match literal {
Literal::I32(v) => v != 0,
Literal::U32(v) => v != 0,
Literal::F32(v) => v != 0.0,
@ -997,20 +997,19 @@ impl<'a> ConstantEvaluator<'a> {
let ty_inner = match self.types[ty].inner {
TypeInner::Vector { size, .. } => TypeInner::Vector {
size,
kind,
width: target_width,
scalar: target,
},
TypeInner::Matrix { columns, rows, .. } => TypeInner::Matrix {
columns,
rows,
width: target_width,
width: target.width,
},
_ => return Err(ConstantEvaluatorError::InvalidCastArg),
};
let mut components = src_components.clone();
for component in &mut components {
*component = self.cast(*component, kind, target_width, span)?;
*component = self.cast(*component, target, span)?;
}
let ty = self.types.insert(
@ -1305,10 +1304,7 @@ mod tests {
let scalar_ty = types.insert(
Type {
name: None,
inner: TypeInner::Scalar {
kind: ScalarKind::Sint,
width: 4,
},
inner: TypeInner::Scalar(crate::Scalar::I32),
},
Default::default(),
);
@ -1318,8 +1314,7 @@ mod tests {
name: None,
inner: TypeInner::Vector {
size: VectorSize::Bi,
kind: ScalarKind::Sint,
width: 4,
scalar: crate::Scalar::I32,
},
},
Default::default(),
@ -1441,10 +1436,7 @@ mod tests {
let scalar_ty = types.insert(
Type {
name: None,
inner: TypeInner::Scalar {
kind: ScalarKind::Sint,
width: 4,
},
inner: TypeInner::Scalar(crate::Scalar::I32),
},
Default::default(),
);
@ -1509,8 +1501,7 @@ mod tests {
name: None,
inner: TypeInner::Vector {
size: VectorSize::Tri,
kind: ScalarKind::Float,
width: 4,
scalar: crate::Scalar::F32,
},
},
Default::default(),
@ -1649,10 +1640,7 @@ mod tests {
let i32_ty = types.insert(
Type {
name: None,
inner: TypeInner::Scalar {
kind: ScalarKind::Sint,
width: 4,
},
inner: TypeInner::Scalar(crate::Scalar::I32),
},
Default::default(),
);
@ -1662,8 +1650,7 @@ mod tests {
name: None,
inner: TypeInner::Vector {
size: VectorSize::Bi,
kind: ScalarKind::Sint,
width: 4,
scalar: crate::Scalar::I32,
},
},
Default::default(),
@ -1733,10 +1720,7 @@ mod tests {
let i32_ty = types.insert(
Type {
name: None,
inner: TypeInner::Scalar {
kind: ScalarKind::Sint,
width: 4,
},
inner: TypeInner::Scalar(crate::Scalar::I32),
},
Default::default(),
);
@ -1746,8 +1730,7 @@ mod tests {
name: None,
inner: TypeInner::Vector {
size: VectorSize::Bi,
kind: ScalarKind::Sint,
width: 4,
scalar: crate::Scalar::I32,
},
},
Default::default(),

View File

@ -171,17 +171,16 @@ impl Layouter {
for (ty_handle, ty) in gctx.types.iter().skip(self.layouts.len()) {
let size = ty.inner.size(gctx);
let layout = match ty.inner {
Ti::Scalar { width, .. } | Ti::Atomic { width, .. } => {
let alignment = Alignment::new(width as u32)
Ti::Scalar(scalar) | Ti::Atomic(scalar) => {
let alignment = Alignment::new(scalar.width as u32)
.ok_or(LayoutErrorInner::NonPowerOfTwoWidth.with(ty_handle))?;
TypeLayout { size, alignment }
}
Ti::Vector {
size: vec_size,
width,
..
scalar,
} => {
let alignment = Alignment::new(width as u32)
let alignment = Alignment::new(scalar.width as u32)
.ok_or(LayoutErrorInner::NonPowerOfTwoWidth.with(ty_handle))?;
TypeLayout {
size,

View File

@ -77,6 +77,52 @@ impl super::ScalarKind {
}
}
impl super::Scalar {
pub const I32: Self = Self {
kind: crate::ScalarKind::Sint,
width: 4,
};
pub const U32: Self = Self {
kind: crate::ScalarKind::Uint,
width: 4,
};
pub const F32: Self = Self {
kind: crate::ScalarKind::Float,
width: 4,
};
pub const F64: Self = Self {
kind: crate::ScalarKind::Float,
width: 8,
};
pub const BOOL: Self = Self {
kind: crate::ScalarKind::Bool,
width: crate::BOOL_WIDTH,
};
/// Construct a float `Scalar` with the given width.
///
/// This is especially common when dealing with
/// `TypeInner::Matrix`, where the scalar kind is implicit.
pub const fn float(width: crate::Bytes) -> Self {
Self {
kind: crate::ScalarKind::Float,
width,
}
}
pub const fn to_inner_scalar(self) -> crate::TypeInner {
crate::TypeInner::Scalar(self)
}
pub const fn to_inner_vector(self, size: crate::VectorSize) -> crate::TypeInner {
crate::TypeInner::Vector { size, scalar: self }
}
pub const fn to_inner_atomic(self) -> crate::TypeInner {
crate::TypeInner::Atomic(self)
}
}
impl PartialEq for crate::Literal {
fn eq(&self, other: &Self) -> bool {
match (*self, *other) {
@ -118,8 +164,8 @@ impl std::hash::Hash for crate::Literal {
}
impl crate::Literal {
pub const fn new(value: u8, kind: crate::ScalarKind, width: crate::Bytes) -> Option<Self> {
match (value, kind, width) {
pub const fn new(value: u8, scalar: crate::Scalar) -> Option<Self> {
match (value, scalar.kind, scalar.width) {
(value, crate::ScalarKind::Float, 8) => Some(Self::F64(value as _)),
(value, crate::ScalarKind::Float, 4) => Some(Self::F32(value as _)),
(value, crate::ScalarKind::Uint, 4) => Some(Self::U32(value as _)),
@ -130,12 +176,12 @@ impl crate::Literal {
}
}
pub const fn zero(kind: crate::ScalarKind, width: crate::Bytes) -> Option<Self> {
Self::new(0, kind, width)
pub const fn zero(scalar: crate::Scalar) -> Option<Self> {
Self::new(0, scalar)
}
pub const fn one(kind: crate::ScalarKind, width: crate::Bytes) -> Option<Self> {
Self::new(1, kind, width)
pub const fn one(scalar: crate::Scalar) -> Option<Self> {
Self::new(1, scalar)
}
pub const fn width(&self) -> crate::Bytes {
@ -145,44 +191,41 @@ impl crate::Literal {
Self::Bool(_) => 1,
}
}
pub const fn scalar_kind(&self) -> crate::ScalarKind {
pub const fn scalar(&self) -> crate::Scalar {
match *self {
Self::F64(_) | Self::F32(_) => crate::ScalarKind::Float,
Self::U32(_) => crate::ScalarKind::Uint,
Self::I32(_) => crate::ScalarKind::Sint,
Self::Bool(_) => crate::ScalarKind::Bool,
Self::F64(_) => crate::Scalar::F64,
Self::F32(_) => crate::Scalar::F32,
Self::U32(_) => crate::Scalar::U32,
Self::I32(_) => crate::Scalar::I32,
Self::Bool(_) => crate::Scalar::BOOL,
}
}
pub const fn scalar_kind(&self) -> crate::ScalarKind {
self.scalar().kind
}
pub const fn ty_inner(&self) -> crate::TypeInner {
crate::TypeInner::Scalar {
kind: self.scalar_kind(),
width: self.width(),
}
crate::TypeInner::Scalar(self.scalar())
}
}
pub const POINTER_SPAN: u32 = 4;
impl super::TypeInner {
pub const fn scalar_kind(&self) -> Option<super::ScalarKind> {
pub const fn scalar(&self) -> Option<super::Scalar> {
use crate::TypeInner as Ti;
match *self {
super::TypeInner::Scalar { kind, .. } | super::TypeInner::Vector { kind, .. } => {
Some(kind)
}
super::TypeInner::Matrix { .. } => Some(super::ScalarKind::Float),
Ti::Scalar(scalar) | Ti::Vector { scalar, .. } => Some(scalar),
Ti::Matrix { width, .. } => Some(super::Scalar::float(width)),
_ => None,
}
}
pub const fn scalar_width(&self) -> Option<u8> {
// Multiply by 8 to get the bit width
match *self {
super::TypeInner::Scalar { width, .. } | super::TypeInner::Vector { width, .. } => {
Some(width * 8)
}
super::TypeInner::Matrix { width, .. } => Some(width * 8),
_ => None,
}
pub fn scalar_kind(&self) -> Option<super::ScalarKind> {
self.scalar().map(|scalar| scalar.kind)
}
pub fn scalar_width(&self) -> Option<u8> {
self.scalar().map(|scalar| scalar.width * 8)
}
pub const fn pointer_space(&self) -> Option<crate::AddressSpace> {
@ -206,12 +249,8 @@ impl super::TypeInner {
/// Get the size of this type.
pub fn size(&self, _gctx: GlobalCtx) -> u32 {
match *self {
Self::Scalar { kind: _, width } | Self::Atomic { kind: _, width } => width as u32,
Self::Vector {
size,
kind: _,
width,
} => size as u32 * width as u32,
Self::Scalar(scalar) | Self::Atomic(scalar) => scalar.width as u32,
Self::Vector { size, scalar } => size as u32 * scalar.width as u32,
// matrices are treated as arrays of aligned columns
Self::Matrix {
columns,
@ -255,16 +294,14 @@ impl super::TypeInner {
use crate::TypeInner as Ti;
match *self {
Ti::Pointer { base, space } => match types[base].inner {
Ti::Scalar { kind, width } => Some(Ti::ValuePointer {
Ti::Scalar(scalar) => Some(Ti::ValuePointer {
size: None,
kind,
width,
scalar,
space,
}),
Ti::Vector { size, kind, width } => Some(Ti::ValuePointer {
Ti::Vector { size, scalar } => Some(Ti::ValuePointer {
size: Some(size),
kind,
width,
scalar,
space,
}),
_ => None,
@ -318,13 +355,10 @@ impl super::TypeInner {
pub fn component_type(&self, index: usize) -> Option<TypeResolution> {
Some(match *self {
Self::Vector { kind, width, .. } => {
TypeResolution::Value(crate::TypeInner::Scalar { kind, width })
}
Self::Vector { scalar, .. } => TypeResolution::Value(crate::TypeInner::Scalar(scalar)),
Self::Matrix { rows, width, .. } => TypeResolution::Value(crate::TypeInner::Vector {
size: rows,
kind: crate::ScalarKind::Float,
width,
scalar: crate::Scalar::float(width),
}),
Self::Array {
base,
@ -628,7 +662,7 @@ impl GlobalCtx<'_> {
match arena[handle] {
crate::Expression::Literal(literal) => Some(literal),
crate::Expression::ZeroValue(ty) => match gctx.types[ty].inner {
crate::TypeInner::Scalar { kind, width } => crate::Literal::zero(kind, width),
crate::TypeInner::Scalar(scalar) => crate::Literal::zero(scalar),
_ => None,
},
_ => None,
@ -661,17 +695,19 @@ pub fn flatten_compose<'arenas>(
expressions: &'arenas crate::Arena<crate::Expression>,
types: &'arenas crate::UniqueArena<crate::Type>,
) -> impl Iterator<Item = crate::Handle<crate::Expression>> + 'arenas {
// Returning `impl Iterator` is a bit tricky. We may or may not want to
// flatten the components, but we have to settle on a single concrete
// type to return. The below is a single iterator chain that handles
// both the flattening and non-flattening cases.
// Returning `impl Iterator` is a bit tricky. We may or may not
// want to flatten the components, but we have to settle on a
// single concrete type to return. This function returns a single
// iterator chain that handles both the flattening and
// non-flattening cases.
let (size, is_vector) = if let crate::TypeInner::Vector { size, .. } = types[ty].inner {
(size as usize, true)
} else {
(components.len(), false)
};
fn flattener<'c>(
/// Flatten `Compose` expressions if `is_vector` is true.
fn flatten_compose<'c>(
component: &'c crate::Handle<crate::Expression>,
is_vector: bool,
expressions: &'c crate::Arena<crate::Expression>,
@ -688,14 +724,35 @@ pub fn flatten_compose<'arenas>(
std::slice::from_ref(component)
}
// Expressions like `vec4(vec3(vec2(6, 7), 8), 9)` require us to flatten
// two levels.
/// Flatten `Splat` expressions if `is_vector` is true.
fn flatten_splat<'c>(
component: &'c crate::Handle<crate::Expression>,
is_vector: bool,
expressions: &'c crate::Arena<crate::Expression>,
) -> impl Iterator<Item = crate::Handle<crate::Expression>> {
let mut expr = *component;
let mut count = 1;
if is_vector {
if let crate::Expression::Splat { size, value } = expressions[expr] {
expr = value;
count = size as usize;
}
}
std::iter::repeat(expr).take(count)
}
// Expressions like `vec4(vec3(vec2(6, 7), 8), 9)` require us to
// flatten up to two levels of `Compose` expressions.
//
// Expressions like `vec4(vec3(1.0), 1.0)` require us to flatten
// `Splat` expressions. Fortunately, the operand of a `Splat` must
// be a scalar, so we can stop there.
components
.iter()
.flat_map(move |component| flattener(component, is_vector, expressions))
.flat_map(move |component| flattener(component, is_vector, expressions))
.flat_map(move |component| flatten_compose(component, is_vector, expressions))
.flat_map(move |component| flatten_compose(component, is_vector, expressions))
.flat_map(move |component| flatten_splat(component, is_vector, expressions))
.take(size)
.cloned()
}
#[test]

View File

@ -119,8 +119,8 @@ impl Clone for TypeResolution {
match *self {
Self::Handle(handle) => Self::Handle(handle),
Self::Value(ref v) => Self::Value(match *v {
Ti::Scalar { kind, width } => Ti::Scalar { kind, width },
Ti::Vector { size, kind, width } => Ti::Vector { size, kind, width },
Ti::Scalar(scalar) => Ti::Scalar(scalar),
Ti::Vector { size, scalar } => Ti::Vector { size, scalar },
Ti::Matrix {
rows,
columns,
@ -133,13 +133,11 @@ impl Clone for TypeResolution {
Ti::Pointer { base, space } => Ti::Pointer { base, space },
Ti::ValuePointer {
size,
kind,
width,
scalar,
space,
} => Ti::ValuePointer {
size,
kind,
width,
scalar,
space,
},
_ => unreachable!("Unexpected clone type: {:?}", v),
@ -243,36 +241,24 @@ impl<'a> ResolveContext<'a> {
Ti::Array { base, .. } => TypeResolution::Handle(base),
Ti::Matrix { rows, width, .. } => TypeResolution::Value(Ti::Vector {
size: rows,
kind: crate::ScalarKind::Float,
width,
scalar: crate::Scalar::float(width),
}),
Ti::Vector {
size: _,
kind,
width,
} => TypeResolution::Value(Ti::Scalar { kind, width }),
Ti::Vector { size: _, scalar } => TypeResolution::Value(Ti::Scalar(scalar)),
Ti::ValuePointer {
size: Some(_),
kind,
width,
scalar,
space,
} => TypeResolution::Value(Ti::ValuePointer {
size: None,
kind,
width,
scalar,
space,
}),
Ti::Pointer { base, space } => {
TypeResolution::Value(match types[base].inner {
Ti::Array { base, .. } => Ti::Pointer { base, space },
Ti::Vector {
size: _,
kind,
width,
} => Ti::ValuePointer {
Ti::Vector { size: _, scalar } => Ti::ValuePointer {
size: None,
kind,
width,
scalar,
space,
},
// Matrices are only dynamically indexed behind a pointer
@ -281,9 +267,8 @@ impl<'a> ResolveContext<'a> {
rows,
width,
} => Ti::ValuePointer {
kind: crate::ScalarKind::Float,
size: Some(rows),
width,
scalar: crate::Scalar::float(width),
space,
},
Ti::BindingArray { base, .. } => Ti::Pointer { base, space },
@ -307,11 +292,11 @@ impl<'a> ResolveContext<'a> {
},
crate::Expression::AccessIndex { base, index } => {
match *past(base)?.inner_with(types) {
Ti::Vector { size, kind, width } => {
Ti::Vector { size, scalar } => {
if index >= size as u32 {
return Err(ResolveError::OutOfBoundsIndex { expr: base, index });
}
TypeResolution::Value(Ti::Scalar { kind, width })
TypeResolution::Value(Ti::Scalar(scalar))
}
Ti::Matrix {
columns,
@ -323,8 +308,7 @@ impl<'a> ResolveContext<'a> {
}
TypeResolution::Value(crate::TypeInner::Vector {
size: rows,
kind: crate::ScalarKind::Float,
width,
scalar: crate::Scalar::float(width),
})
}
Ti::Array { base, .. } => TypeResolution::Handle(base),
@ -336,8 +320,7 @@ impl<'a> ResolveContext<'a> {
}
Ti::ValuePointer {
size: Some(size),
kind,
width,
scalar,
space,
} => {
if index >= size as u32 {
@ -345,8 +328,7 @@ impl<'a> ResolveContext<'a> {
}
TypeResolution::Value(Ti::ValuePointer {
size: None,
kind,
width,
scalar,
space,
})
}
@ -355,14 +337,13 @@ impl<'a> ResolveContext<'a> {
space,
} => TypeResolution::Value(match types[ty_base].inner {
Ti::Array { base, .. } => Ti::Pointer { base, space },
Ti::Vector { size, kind, width } => {
Ti::Vector { size, scalar } => {
if index >= size as u32 {
return Err(ResolveError::OutOfBoundsIndex { expr: base, index });
}
Ti::ValuePointer {
size: None,
kind,
width,
scalar,
space,
}
}
@ -376,8 +357,7 @@ impl<'a> ResolveContext<'a> {
}
Ti::ValuePointer {
size: Some(rows),
kind: crate::ScalarKind::Float,
width,
scalar: crate::Scalar::float(width),
space,
}
}
@ -410,9 +390,7 @@ impl<'a> ResolveContext<'a> {
}
}
crate::Expression::Splat { size, value } => match *past(value)?.inner_with(types) {
Ti::Scalar { kind, width } => {
TypeResolution::Value(Ti::Vector { size, kind, width })
}
Ti::Scalar(scalar) => TypeResolution::Value(Ti::Vector { size, scalar }),
ref other => {
log::error!("Scalar type {:?}", other);
return Err(ResolveError::InvalidScalar(value));
@ -423,11 +401,9 @@ impl<'a> ResolveContext<'a> {
vector,
pattern: _,
} => match *past(vector)?.inner_with(types) {
Ti::Vector {
size: _,
kind,
width,
} => TypeResolution::Value(Ti::Vector { size, kind, width }),
Ti::Vector { size: _, scalar } => {
TypeResolution::Value(Ti::Vector { size, scalar })
}
ref other => {
log::error!("Vector type {:?}", other);
return Err(ResolveError::InvalidVector(vector));
@ -464,20 +440,19 @@ impl<'a> ResolveContext<'a> {
}
crate::Expression::Load { pointer } => match *past(pointer)?.inner_with(types) {
Ti::Pointer { base, space: _ } => {
if let Ti::Atomic { kind, width } = types[base].inner {
TypeResolution::Value(Ti::Scalar { kind, width })
if let Ti::Atomic(scalar) = types[base].inner {
TypeResolution::Value(Ti::Scalar(scalar))
} else {
TypeResolution::Handle(base)
}
}
Ti::ValuePointer {
size,
kind,
width,
scalar,
space: _,
} => TypeResolution::Value(match size {
Some(size) => Ti::Vector { size, kind, width },
None => Ti::Scalar { kind, width },
Some(size) => Ti::Vector { size, scalar },
None => Ti::Scalar(scalar),
}),
ref other => {
log::error!("Pointer type {:?}", other);
@ -490,11 +465,13 @@ impl<'a> ResolveContext<'a> {
..
} => match *past(image)?.inner_with(types) {
Ti::Image { class, .. } => TypeResolution::Value(Ti::Vector {
kind: match class {
crate::ImageClass::Sampled { kind, multi: _ } => kind,
_ => crate::ScalarKind::Float,
scalar: crate::Scalar {
kind: match class {
crate::ImageClass::Sampled { kind, multi: _ } => kind,
_ => crate::ScalarKind::Float,
},
width: 4,
},
width: 4,
size: crate::VectorSize::Quad,
}),
ref other => {
@ -505,18 +482,16 @@ impl<'a> ResolveContext<'a> {
crate::Expression::ImageSample { image, .. }
| crate::Expression::ImageLoad { image, .. } => match *past(image)?.inner_with(types) {
Ti::Image { class, .. } => TypeResolution::Value(match class {
crate::ImageClass::Depth { multi: _ } => Ti::Scalar {
kind: crate::ScalarKind::Float,
width: 4,
},
crate::ImageClass::Depth { multi: _ } => Ti::Scalar(crate::Scalar::F32),
crate::ImageClass::Sampled { kind, multi: _ } => Ti::Vector {
kind,
width: 4,
scalar: crate::Scalar { kind, width: 4 },
size: crate::VectorSize::Quad,
},
crate::ImageClass::Storage { format, .. } => Ti::Vector {
kind: format.into(),
width: 4,
scalar: crate::Scalar {
kind: format.into(),
width: 4,
},
size: crate::VectorSize::Quad,
},
}),
@ -528,19 +503,14 @@ impl<'a> ResolveContext<'a> {
crate::Expression::ImageQuery { image, query } => TypeResolution::Value(match query {
crate::ImageQuery::Size { level: _ } => match *past(image)?.inner_with(types) {
Ti::Image { dim, .. } => match dim {
crate::ImageDimension::D1 => Ti::Scalar {
kind: crate::ScalarKind::Uint,
width: 4,
},
crate::ImageDimension::D1 => Ti::Scalar(crate::Scalar::U32),
crate::ImageDimension::D2 | crate::ImageDimension::Cube => Ti::Vector {
size: crate::VectorSize::Bi,
kind: crate::ScalarKind::Uint,
width: 4,
scalar: crate::Scalar::U32,
},
crate::ImageDimension::D3 => Ti::Vector {
size: crate::VectorSize::Tri,
kind: crate::ScalarKind::Uint,
width: 4,
scalar: crate::Scalar::U32,
},
},
ref other => {
@ -550,10 +520,7 @@ impl<'a> ResolveContext<'a> {
},
crate::ImageQuery::NumLevels
| crate::ImageQuery::NumLayers
| crate::ImageQuery::NumSamples => Ti::Scalar {
kind: crate::ScalarKind::Uint,
width: 4,
},
| crate::ImageQuery::NumSamples => Ti::Scalar(crate::Scalar::U32),
}),
crate::Expression::Unary { expr, .. } => past(expr)?.clone(),
crate::Expression::Binary { op, left, right } => match op {
@ -585,8 +552,7 @@ impl<'a> ResolveContext<'a> {
&Ti::Vector { .. },
) => TypeResolution::Value(Ti::Vector {
size: rows,
kind: crate::ScalarKind::Float,
width,
scalar: crate::Scalar::float(width),
}),
(
&Ti::Vector { .. },
@ -597,8 +563,7 @@ impl<'a> ResolveContext<'a> {
},
) => TypeResolution::Value(Ti::Vector {
size: columns,
kind: crate::ScalarKind::Float,
width,
scalar: crate::Scalar::float(width),
}),
(&Ti::Scalar { .. }, _) => res_right.clone(),
(_, &Ti::Scalar { .. }) => res_left.clone(),
@ -618,11 +583,10 @@ impl<'a> ResolveContext<'a> {
| crate::BinaryOperator::GreaterEqual
| crate::BinaryOperator::LogicalAnd
| crate::BinaryOperator::LogicalOr => {
let kind = crate::ScalarKind::Bool;
let width = crate::BOOL_WIDTH;
let scalar = crate::Scalar::BOOL;
let inner = match *past(left)?.inner_with(types) {
Ti::Scalar { .. } => Ti::Scalar { kind, width },
Ti::Vector { size, .. } => Ti::Vector { size, kind, width },
Ti::Scalar { .. } => Ti::Scalar(scalar),
Ti::Vector { size, .. } => Ti::Vector { size, scalar },
ref other => {
return Err(ResolveError::IncompatibleOperands(format!(
"{op:?}({other:?}, _)"
@ -643,20 +607,13 @@ impl<'a> ResolveContext<'a> {
crate::Expression::Derivative { expr, .. } => past(expr)?.clone(),
crate::Expression::Relational { fun, argument } => match fun {
crate::RelationalFunction::All | crate::RelationalFunction::Any => {
TypeResolution::Value(Ti::Scalar {
kind: crate::ScalarKind::Bool,
width: crate::BOOL_WIDTH,
})
TypeResolution::Value(Ti::Scalar(crate::Scalar::BOOL))
}
crate::RelationalFunction::IsNan | crate::RelationalFunction::IsInf => {
match *past(argument)?.inner_with(types) {
Ti::Scalar { .. } => TypeResolution::Value(Ti::Scalar {
kind: crate::ScalarKind::Bool,
width: crate::BOOL_WIDTH,
}),
Ti::Scalar { .. } => TypeResolution::Value(Ti::Scalar(crate::Scalar::BOOL)),
Ti::Vector { size, .. } => TypeResolution::Value(Ti::Vector {
kind: crate::ScalarKind::Bool,
width: crate::BOOL_WIDTH,
scalar: crate::Scalar::BOOL,
size,
}),
ref other => {
@ -714,14 +671,16 @@ impl<'a> ResolveContext<'a> {
Mf::Pow => res_arg.clone(),
Mf::Modf | Mf::Frexp => {
let (size, width) = match res_arg.inner_with(types) {
&Ti::Scalar {
&Ti::Scalar(crate::Scalar {
kind: crate::ScalarKind::Float,
width,
} => (None, width),
&Ti::Vector {
kind: crate::ScalarKind::Float,
size,
width,
}) => (None, width),
&Ti::Vector {
scalar: crate::Scalar {
kind: crate::ScalarKind::Float,
width,
},
size,
} => (Some(size), width),
ref other =>
return Err(ResolveError::IncompatibleOperands(format!("{fun:?}({other:?}, _)")))
@ -740,10 +699,9 @@ impl<'a> ResolveContext<'a> {
// geometry
Mf::Dot => match *res_arg.inner_with(types) {
Ti::Vector {
kind,
size: _,
width,
} => TypeResolution::Value(Ti::Scalar { kind, width }),
scalar,
} => TypeResolution::Value(Ti::Scalar(scalar)),
ref other =>
return Err(ResolveError::IncompatibleOperands(
format!("{fun:?}({other:?}, _)")
@ -754,7 +712,14 @@ impl<'a> ResolveContext<'a> {
format!("{fun:?}(_, None)")
))?;
match (res_arg.inner_with(types), past(arg1)?.inner_with(types)) {
(&Ti::Vector {kind: _, size: columns,width}, &Ti::Vector{ size: rows, .. }) => TypeResolution::Value(Ti::Matrix { columns, rows, width }),
(
&Ti::Vector { size: columns, scalar },
&Ti::Vector{ size: rows, .. }
) => TypeResolution::Value(Ti::Matrix {
columns,
rows,
width: scalar.width
}),
(left, right) =>
return Err(ResolveError::IncompatibleOperands(
format!("{fun:?}({left:?}, {right:?})")
@ -764,8 +729,8 @@ impl<'a> ResolveContext<'a> {
Mf::Cross => res_arg.clone(),
Mf::Distance |
Mf::Length => match *res_arg.inner_with(types) {
Ti::Scalar {width,kind} |
Ti::Vector {width,kind,size:_} => TypeResolution::Value(Ti::Scalar { kind, width }),
Ti::Scalar(scalar) |
Ti::Vector {scalar,size:_} => TypeResolution::Value(Ti::Scalar(scalar)),
ref other => return Err(ResolveError::IncompatibleOperands(
format!("{fun:?}({other:?})")
)),
@ -814,7 +779,7 @@ impl<'a> ResolveContext<'a> {
Ti::Matrix {
width,
..
} => TypeResolution::Value(Ti::Scalar { kind: crate::ScalarKind::Float, width }),
} => TypeResolution::Value(Ti::Scalar(crate::Scalar::float(width))),
ref other => return Err(ResolveError::IncompatibleOperands(
format!("{fun:?}({other:?})")
)),
@ -828,10 +793,17 @@ impl<'a> ResolveContext<'a> {
Mf::InsertBits |
Mf::FindLsb |
Mf::FindMsb => match *res_arg.inner_with(types) {
Ti::Scalar { kind: kind @ (crate::ScalarKind::Sint | crate::ScalarKind::Uint), width } =>
TypeResolution::Value(Ti::Scalar { kind, width }),
Ti::Vector { size, kind: kind @ (crate::ScalarKind::Sint | crate::ScalarKind::Uint), width } =>
TypeResolution::Value(Ti::Vector { size, kind, width }),
Ti::Scalar(scalar @ crate::Scalar {
kind: crate::ScalarKind::Sint | crate::ScalarKind::Uint,
..
}) => TypeResolution::Value(Ti::Scalar(scalar)),
Ti::Vector {
size,
scalar: scalar @ crate::Scalar {
kind: crate::ScalarKind::Sint | crate::ScalarKind::Uint,
..
}
} => TypeResolution::Value(Ti::Vector { size, scalar }),
ref other => return Err(ResolveError::IncompatibleOperands(
format!("{fun:?}({other:?})")
)),
@ -841,13 +813,19 @@ impl<'a> ResolveContext<'a> {
Mf::Pack4x8unorm |
Mf::Pack2x16snorm |
Mf::Pack2x16unorm |
Mf::Pack2x16float => TypeResolution::Value(Ti::Scalar { kind: crate::ScalarKind::Uint, width: 4 }),
Mf::Pack2x16float => TypeResolution::Value(Ti::Scalar(crate::Scalar::U32)),
// data unpacking
Mf::Unpack4x8snorm |
Mf::Unpack4x8unorm => TypeResolution::Value(Ti::Vector { size: crate::VectorSize::Quad, kind: crate::ScalarKind::Float, width: 4 }),
Mf::Unpack4x8unorm => TypeResolution::Value(Ti::Vector {
size: crate::VectorSize::Quad,
scalar: crate::Scalar::F32
}),
Mf::Unpack2x16snorm |
Mf::Unpack2x16unorm |
Mf::Unpack2x16float => TypeResolution::Value(Ti::Vector { size: crate::VectorSize::Bi, kind: crate::ScalarKind::Float, width: 4 }),
Mf::Unpack2x16float => TypeResolution::Value(Ti::Vector {
size: crate::VectorSize::Bi,
scalar: crate::Scalar::F32
}),
}
}
crate::Expression::As {
@ -855,18 +833,21 @@ impl<'a> ResolveContext<'a> {
kind,
convert,
} => match *past(expr)?.inner_with(types) {
Ti::Scalar { kind: _, width } => TypeResolution::Value(Ti::Scalar {
kind,
width: convert.unwrap_or(width),
}),
Ti::Scalar(crate::Scalar { width, .. }) => {
TypeResolution::Value(Ti::Scalar(crate::Scalar {
kind,
width: convert.unwrap_or(width),
}))
}
Ti::Vector {
kind: _,
size,
width,
scalar: crate::Scalar { kind: _, width },
} => TypeResolution::Value(Ti::Vector {
kind,
size,
width: convert.unwrap_or(width),
scalar: crate::Scalar {
kind,
width: convert.unwrap_or(width),
},
}),
Ti::Matrix {
columns,
@ -890,14 +871,12 @@ impl<'a> ResolveContext<'a> {
.ok_or(ResolveError::FunctionReturnsVoid)?;
TypeResolution::Handle(result.ty)
}
crate::Expression::ArrayLength(_) => TypeResolution::Value(Ti::Scalar {
kind: crate::ScalarKind::Uint,
width: 4,
}),
crate::Expression::RayQueryProceedResult => TypeResolution::Value(Ti::Scalar {
kind: crate::ScalarKind::Bool,
width: crate::BOOL_WIDTH,
}),
crate::Expression::ArrayLength(_) => {
TypeResolution::Value(Ti::Scalar(crate::Scalar::U32))
}
crate::Expression::RayQueryProceedResult => {
TypeResolution::Value(Ti::Scalar(crate::Scalar::BOOL))
}
crate::Expression::RayQueryGetIntersection { .. } => {
let result = self
.special_types

View File

@ -159,10 +159,10 @@ impl ExpressionInfo {
ref_count: 0,
assignable_global: None,
// this doesn't matter at this point, will be overwritten
ty: TypeResolution::Value(crate::TypeInner::Scalar {
ty: TypeResolution::Value(crate::TypeInner::Scalar(crate::Scalar {
kind: crate::ScalarKind::Bool,
width: 0,
}),
})),
}
}
}
@ -1070,8 +1070,7 @@ fn uniform_control_flow() {
name: None,
inner: crate::TypeInner::Vector {
size: crate::VectorSize::Bi,
kind: crate::ScalarKind::Float,
width: 4,
scalar: crate::Scalar::F32,
},
},
Default::default(),

View File

@ -24,19 +24,15 @@ pub fn validate_compose(
match gctx.types[self_ty_handle].inner {
// vectors are composed from scalars or other vectors
Ti::Vector { size, kind, width } => {
Ti::Vector { size, scalar } => {
let mut total = 0;
for (index, comp_res) in component_resolutions.enumerate() {
total += match *comp_res.inner_with(gctx.types) {
Ti::Scalar {
kind: comp_kind,
width: comp_width,
} if comp_kind == kind && comp_width == width => 1,
Ti::Scalar(comp_scalar) if comp_scalar == scalar => 1,
Ti::Vector {
size: comp_size,
kind: comp_kind,
width: comp_width,
} if comp_kind == kind && comp_width == width => comp_size as u32,
scalar: comp_scalar,
} if comp_scalar == scalar => comp_size as u32,
ref other => {
log::error!("Vector component[{}] type {:?}", index, other);
return Err(ComposeError::ComponentType {
@ -60,8 +56,7 @@ pub fn validate_compose(
} => {
let inner = Ti::Vector {
size: rows,
kind: crate::ScalarKind::Float,
width,
scalar: crate::Scalar::float(width),
};
if columns as usize != component_resolutions.len() {
return Err(ComposeError::ComponentCount {

View File

@ -221,7 +221,7 @@ impl super::Validator {
info: &FunctionInfo,
mod_info: &ModuleInfo,
) -> Result<ShaderStages, ExpressionError> {
use crate::{Expression as E, ScalarKind as Sk, TypeInner as Ti};
use crate::{Expression as E, Scalar as Sc, ScalarKind as Sk, TypeInner as Ti};
let resolver = ExpressionTypeResolver {
root,
@ -246,10 +246,10 @@ impl super::Validator {
};
match resolver[index] {
//TODO: only allow one of these
Ti::Scalar {
Ti::Scalar(Sc {
kind: Sk::Sint | Sk::Uint,
width: _,
} => {}
..
}) => {}
ref other => {
log::error!("Indexing by {:?}", other);
return Err(ExpressionError::InvalidIndexType(index));
@ -412,10 +412,10 @@ impl super::Validator {
}
if let Some(expr) = array_index {
match resolver[expr] {
Ti::Scalar {
Ti::Scalar(Sc {
kind: Sk::Sint | Sk::Uint,
width: _,
} => {}
..
}) => {}
_ => return Err(ExpressionError::InvalidImageArrayIndexType(expr)),
}
}
@ -452,13 +452,15 @@ impl super::Validator {
crate::ImageDimension::D3 | crate::ImageDimension::Cube => 3,
};
match resolver[coordinate] {
Ti::Scalar {
Ti::Scalar(Sc {
kind: Sk::Float, ..
} if num_components == 1 => {}
}) if num_components == 1 => {}
Ti::Vector {
size,
kind: Sk::Float,
..
scalar:
Sc {
kind: Sk::Float, ..
},
} if size as u32 == num_components => {}
_ => return Err(ExpressionError::InvalidImageCoordinateType(dim, coordinate)),
}
@ -466,11 +468,10 @@ impl super::Validator {
// check constant offset
if let Some(const_expr) = offset {
match *mod_info[const_expr].inner_with(&module.types) {
Ti::Scalar { kind: Sk::Sint, .. } if num_components == 1 => {}
Ti::Scalar(Sc { kind: Sk::Sint, .. }) if num_components == 1 => {}
Ti::Vector {
size,
kind: Sk::Sint,
..
scalar: Sc { kind: Sk::Sint, .. },
} if size as u32 == num_components => {}
_ => {
return Err(ExpressionError::InvalidSampleOffset(dim, const_expr));
@ -481,9 +482,9 @@ impl super::Validator {
// check depth reference type
if let Some(expr) = depth_ref {
match resolver[expr] {
Ti::Scalar {
Ti::Scalar(Sc {
kind: Sk::Float, ..
} => {}
}) => {}
_ => return Err(ExpressionError::InvalidDepthReference(expr)),
}
match level {
@ -518,44 +519,48 @@ impl super::Validator {
crate::SampleLevel::Zero => ShaderStages::all(),
crate::SampleLevel::Exact(expr) => {
match resolver[expr] {
Ti::Scalar {
Ti::Scalar(Sc {
kind: Sk::Float, ..
} => {}
}) => {}
_ => return Err(ExpressionError::InvalidSampleLevelExactType(expr)),
}
ShaderStages::all()
}
crate::SampleLevel::Bias(expr) => {
match resolver[expr] {
Ti::Scalar {
Ti::Scalar(Sc {
kind: Sk::Float, ..
} => {}
}) => {}
_ => return Err(ExpressionError::InvalidSampleLevelBiasType(expr)),
}
ShaderStages::FRAGMENT
}
crate::SampleLevel::Gradient { x, y } => {
match resolver[x] {
Ti::Scalar {
Ti::Scalar(Sc {
kind: Sk::Float, ..
} if num_components == 1 => {}
}) if num_components == 1 => {}
Ti::Vector {
size,
kind: Sk::Float,
..
scalar:
Sc {
kind: Sk::Float, ..
},
} if size as u32 == num_components => {}
_ => {
return Err(ExpressionError::InvalidSampleLevelGradientType(dim, x))
}
}
match resolver[y] {
Ti::Scalar {
Ti::Scalar(Sc {
kind: Sk::Float, ..
} if num_components == 1 => {}
}) if num_components == 1 => {}
Ti::Vector {
size,
kind: Sk::Float,
..
scalar:
Sc {
kind: Sk::Float, ..
},
} if size as u32 == num_components => {}
_ => {
return Err(ExpressionError::InvalidSampleLevelGradientType(dim, y))
@ -592,10 +597,10 @@ impl super::Validator {
}
if let Some(expr) = array_index {
match resolver[expr] {
Ti::Scalar {
Ti::Scalar(Sc {
kind: Sk::Sint | Sk::Uint,
width: _,
} => {}
}) => {}
_ => return Err(ExpressionError::InvalidImageArrayIndexType(expr)),
}
}
@ -669,7 +674,7 @@ impl super::Validator {
let right_inner = &resolver[right];
let good = match op {
Bo::Add | Bo::Subtract => match *left_inner {
Ti::Scalar { kind, .. } | Ti::Vector { kind, .. } => match kind {
Ti::Scalar(scalar) | Ti::Vector { scalar, .. } => match scalar.kind {
Sk::Uint | Sk::Sint | Sk::Float => left_inner == right_inner,
Sk::Bool => false,
},
@ -677,7 +682,7 @@ impl super::Validator {
_ => false,
},
Bo::Divide | Bo::Modulo => match *left_inner {
Ti::Scalar { kind, .. } | Ti::Vector { kind, .. } => match kind {
Ti::Scalar(scalar) | Ti::Vector { scalar, .. } => match scalar.kind {
Sk::Uint | Sk::Sint | Sk::Float => left_inner == right_inner,
Sk::Bool => false,
},
@ -690,52 +695,62 @@ impl super::Validator {
};
let types_match = match (left_inner, right_inner) {
// Straight scalar and mixed scalar/vector.
(&Ti::Scalar { kind: kind1, .. }, &Ti::Scalar { kind: kind2, .. })
| (&Ti::Vector { kind: kind1, .. }, &Ti::Scalar { kind: kind2, .. })
| (&Ti::Scalar { kind: kind1, .. }, &Ti::Vector { kind: kind2, .. }) => {
kind1 == kind2
}
(&Ti::Scalar(scalar1), &Ti::Scalar(scalar2))
| (
&Ti::Vector {
scalar: scalar1, ..
},
&Ti::Scalar(scalar2),
)
| (
&Ti::Scalar(scalar1),
&Ti::Vector {
scalar: scalar2, ..
},
) => scalar1 == scalar2,
// Scalar/matrix.
(
&Ti::Scalar {
&Ti::Scalar(Sc {
kind: Sk::Float, ..
},
}),
&Ti::Matrix { .. },
)
| (
&Ti::Matrix { .. },
&Ti::Scalar {
&Ti::Scalar(Sc {
kind: Sk::Float, ..
},
}),
) => true,
// Vector/vector.
(
&Ti::Vector {
kind: kind1,
size: size1,
..
scalar: scalar1,
},
&Ti::Vector {
kind: kind2,
size: size2,
..
scalar: scalar2,
},
) => kind1 == kind2 && size1 == size2,
) => scalar1 == scalar2 && size1 == size2,
// Matrix * vector.
(
&Ti::Matrix { columns, .. },
&Ti::Vector {
kind: Sk::Float,
size,
..
scalar:
Sc {
kind: Sk::Float, ..
},
},
) => columns == size,
// Vector * matrix.
(
&Ti::Vector {
kind: Sk::Float,
size,
..
scalar:
Sc {
kind: Sk::Float, ..
},
},
&Ti::Matrix { rows, .. },
) => size == rows,
@ -744,24 +759,14 @@ impl super::Validator {
}
_ => false,
};
let left_width = match *left_inner {
Ti::Scalar { width, .. }
| Ti::Vector { width, .. }
| Ti::Matrix { width, .. } => width,
_ => 0,
};
let right_width = match *right_inner {
Ti::Scalar { width, .. }
| Ti::Vector { width, .. }
| Ti::Matrix { width, .. } => width,
_ => 0,
};
let left_width = left_inner.scalar_width().unwrap_or(0);
let right_width = right_inner.scalar_width().unwrap_or(0);
kind_allowed && types_match && left_width == right_width
}
Bo::Equal | Bo::NotEqual => left_inner.is_sized() && left_inner == right_inner,
Bo::Less | Bo::LessEqual | Bo::Greater | Bo::GreaterEqual => {
match *left_inner {
Ti::Scalar { kind, .. } | Ti::Vector { kind, .. } => match kind {
Ti::Scalar(scalar) | Ti::Vector { scalar, .. } => match scalar.kind {
Sk::Uint | Sk::Sint | Sk::Float => left_inner == right_inner,
Sk::Bool => false,
},
@ -772,16 +777,18 @@ impl super::Validator {
}
}
Bo::LogicalAnd | Bo::LogicalOr => match *left_inner {
Ti::Scalar { kind: Sk::Bool, .. } | Ti::Vector { kind: Sk::Bool, .. } => {
left_inner == right_inner
}
Ti::Scalar(Sc { kind: Sk::Bool, .. })
| Ti::Vector {
scalar: Sc { kind: Sk::Bool, .. },
..
} => left_inner == right_inner,
ref other => {
log::error!("Op {:?} left type {:?}", op, other);
false
}
},
Bo::And | Bo::InclusiveOr => match *left_inner {
Ti::Scalar { kind, .. } | Ti::Vector { kind, .. } => match kind {
Ti::Scalar(scalar) | Ti::Vector { scalar, .. } => match scalar.kind {
Sk::Bool | Sk::Sint | Sk::Uint => left_inner == right_inner,
Sk::Float => false,
},
@ -791,7 +798,7 @@ impl super::Validator {
}
},
Bo::ExclusiveOr => match *left_inner {
Ti::Scalar { kind, .. } | Ti::Vector { kind, .. } => match kind {
Ti::Scalar(scalar) | Ti::Vector { scalar, .. } => match scalar.kind {
Sk::Sint | Sk::Uint => left_inner == right_inner,
Sk::Bool | Sk::Float => false,
},
@ -801,27 +808,26 @@ impl super::Validator {
}
},
Bo::ShiftLeft | Bo::ShiftRight => {
let (base_size, base_kind) = match *left_inner {
Ti::Scalar { kind, .. } => (Ok(None), kind),
Ti::Vector { size, kind, .. } => (Ok(Some(size)), kind),
let (base_size, base_scalar) = match *left_inner {
Ti::Scalar(scalar) => (Ok(None), scalar),
Ti::Vector { size, scalar } => (Ok(Some(size)), scalar),
ref other => {
log::error!("Op {:?} base type {:?}", op, other);
(Err(()), Sk::Bool)
(Err(()), Sc::BOOL)
}
};
let shift_size = match *right_inner {
Ti::Scalar { kind: Sk::Uint, .. } => Ok(None),
Ti::Scalar(Sc { kind: Sk::Uint, .. }) => Ok(None),
Ti::Vector {
size,
kind: Sk::Uint,
..
scalar: Sc { kind: Sk::Uint, .. },
} => Ok(Some(size)),
ref other => {
log::error!("Op {:?} shift type {:?}", op, other);
Err(())
}
};
match base_kind {
match base_scalar.kind {
Sk::Sint | Sk::Uint => base_size.is_ok() && base_size == shift_size,
Sk::Float | Sk::Bool => false,
}
@ -850,10 +856,10 @@ impl super::Validator {
let accept_inner = &resolver[accept];
let reject_inner = &resolver[reject];
let condition_good = match resolver[condition] {
Ti::Scalar {
Ti::Scalar(Sc {
kind: Sk::Bool,
width: _,
} => {
}) => {
// When `condition` is a single boolean, `accept` and
// `reject` can be vectors or scalars.
match *accept_inner {
@ -863,8 +869,11 @@ impl super::Validator {
}
Ti::Vector {
size,
kind: Sk::Bool,
width: _,
scalar:
Sc {
kind: Sk::Bool,
width: _,
},
} => match *accept_inner {
Ti::Vector {
size: other_size, ..
@ -880,11 +889,15 @@ impl super::Validator {
}
E::Derivative { expr, .. } => {
match resolver[expr] {
Ti::Scalar {
Ti::Scalar(Sc {
kind: Sk::Float, ..
}
})
| Ti::Vector {
kind: Sk::Float, ..
scalar:
Sc {
kind: Sk::Float, ..
},
..
} => {}
_ => return Err(ExpressionError::InvalidDerivative),
}
@ -895,19 +908,18 @@ impl super::Validator {
let argument_inner = &resolver[argument];
match fun {
Rf::All | Rf::Any => match *argument_inner {
Ti::Vector { kind: Sk::Bool, .. } => {}
Ti::Vector {
scalar: Sc { kind: Sk::Bool, .. },
..
} => {}
ref other => {
log::error!("All/Any of type {:?}", other);
return Err(ExpressionError::InvalidBooleanVector(argument));
}
},
Rf::IsNan | Rf::IsInf => match *argument_inner {
Ti::Scalar {
kind: Sk::Float, ..
}
| Ti::Vector {
kind: Sk::Float, ..
} => {}
Ti::Scalar(scalar) | Ti::Vector { scalar, .. }
if scalar.kind == Sk::Float => {}
ref other => {
log::error!("Float test of type {:?}", other);
return Err(ExpressionError::InvalidFloatArgument(argument));
@ -936,7 +948,9 @@ impl super::Validator {
return Err(ExpressionError::WrongArgumentCount(fun));
}
let good = match *arg_ty {
Ti::Scalar { kind, .. } | Ti::Vector { kind, .. } => kind != Sk::Bool,
Ti::Scalar(scalar) | Ti::Vector { scalar, .. } => {
scalar.kind != Sk::Bool
}
_ => false,
};
if !good {
@ -949,7 +963,9 @@ impl super::Validator {
_ => return Err(ExpressionError::WrongArgumentCount(fun)),
};
let good = match *arg_ty {
Ti::Scalar { kind, .. } | Ti::Vector { kind, .. } => kind != Sk::Bool,
Ti::Scalar(scalar) | Ti::Vector { scalar, .. } => {
scalar.kind != Sk::Bool
}
_ => false,
};
if !good {
@ -969,7 +985,9 @@ impl super::Validator {
_ => return Err(ExpressionError::WrongArgumentCount(fun)),
};
let good = match *arg_ty {
Ti::Scalar { kind, .. } | Ti::Vector { kind, .. } => kind != Sk::Bool,
Ti::Scalar(scalar) | Ti::Vector { scalar, .. } => {
scalar.kind != Sk::Bool
}
_ => false,
};
if !good {
@ -1021,12 +1039,8 @@ impl super::Validator {
return Err(ExpressionError::WrongArgumentCount(fun));
}
match *arg_ty {
Ti::Scalar {
kind: Sk::Float, ..
}
| Ti::Vector {
kind: Sk::Float, ..
} => {}
Ti::Scalar(scalar) | Ti::Vector { scalar, .. }
if scalar.kind == Sk::Float => {}
_ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)),
}
}
@ -1035,12 +1049,16 @@ impl super::Validator {
return Err(ExpressionError::WrongArgumentCount(fun));
}
match *arg_ty {
Ti::Scalar {
Ti::Scalar(Sc {
kind: Sk::Float | Sk::Sint,
..
}
})
| Ti::Vector {
kind: Sk::Float | Sk::Sint,
scalar:
Sc {
kind: Sk::Float | Sk::Sint,
..
},
..
} => {}
_ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)),
@ -1052,12 +1070,8 @@ impl super::Validator {
_ => return Err(ExpressionError::WrongArgumentCount(fun)),
};
match *arg_ty {
Ti::Scalar {
kind: Sk::Float, ..
}
| Ti::Vector {
kind: Sk::Float, ..
} => {}
Ti::Scalar(scalar) | Ti::Vector { scalar, .. }
if scalar.kind == Sk::Float => {}
_ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)),
}
if arg1_ty != arg_ty {
@ -1072,16 +1086,10 @@ impl super::Validator {
if arg1_ty.is_some() || arg2_ty.is_some() || arg3_ty.is_some() {
return Err(ExpressionError::WrongArgumentCount(fun));
}
if !matches!(
*arg_ty,
Ti::Scalar {
kind: Sk::Float,
..
} | Ti::Vector {
kind: Sk::Float,
..
},
) {
if !matches!(*arg_ty,
Ti::Scalar(scalar) | Ti::Vector { scalar, .. }
if scalar.kind == Sk::Float)
{
return Err(ExpressionError::InvalidArgumentType(fun, 1, arg));
}
}
@ -1091,24 +1099,25 @@ impl super::Validator {
_ => return Err(ExpressionError::WrongArgumentCount(fun)),
};
let size0 = match *arg_ty {
Ti::Scalar {
Ti::Scalar(Sc {
kind: Sk::Float, ..
} => None,
}) => None,
Ti::Vector {
kind: Sk::Float,
scalar:
Sc {
kind: Sk::Float, ..
},
size,
..
} => Some(size),
_ => {
return Err(ExpressionError::InvalidArgumentType(fun, 0, arg));
}
};
let good = match *arg1_ty {
Ti::Scalar { kind: Sk::Sint, .. } if size0.is_none() => true,
Ti::Scalar(Sc { kind: Sk::Sint, .. }) if size0.is_none() => true,
Ti::Vector {
size,
kind: Sk::Sint,
..
scalar: Sc { kind: Sk::Sint, .. },
} if Some(size) == size0 => true,
_ => false,
};
@ -1127,7 +1136,11 @@ impl super::Validator {
};
match *arg_ty {
Ti::Vector {
kind: Sk::Float | Sk::Sint | Sk::Uint,
scalar:
Sc {
kind: Sk::Float | Sk::Sint | Sk::Uint,
..
},
..
} => {}
_ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)),
@ -1147,7 +1160,11 @@ impl super::Validator {
};
match *arg_ty {
Ti::Vector {
kind: Sk::Float, ..
scalar:
Sc {
kind: Sk::Float, ..
},
..
} => {}
_ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)),
}
@ -1167,7 +1184,11 @@ impl super::Validator {
match *arg_ty {
Ti::Vector {
kind: Sk::Float, ..
scalar:
Sc {
kind: Sk::Float, ..
},
..
} => {}
_ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)),
}
@ -1183,13 +1204,17 @@ impl super::Validator {
match (arg_ty, arg2_ty) {
(
&Ti::Vector {
width: vector_width,
scalar:
Sc {
width: vector_width,
..
},
..
},
&Ti::Scalar {
&Ti::Scalar(Sc {
width: scalar_width,
kind: Sk::Float,
},
}),
) if vector_width == scalar_width => {}
_ => {
return Err(ExpressionError::InvalidArgumentType(
@ -1206,7 +1231,11 @@ impl super::Validator {
}
match *arg_ty {
Ti::Vector {
kind: Sk::Float, ..
scalar:
Sc {
kind: Sk::Float, ..
},
..
} => {}
_ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)),
}
@ -1217,11 +1246,15 @@ impl super::Validator {
_ => return Err(ExpressionError::WrongArgumentCount(fun)),
};
match *arg_ty {
Ti::Scalar {
Ti::Scalar(Sc {
kind: Sk::Float, ..
}
})
| Ti::Vector {
kind: Sk::Float, ..
scalar:
Sc {
kind: Sk::Float, ..
},
..
} => {}
_ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)),
}
@ -1246,13 +1279,16 @@ impl super::Validator {
_ => return Err(ExpressionError::WrongArgumentCount(fun)),
};
let arg_width = match *arg_ty {
Ti::Scalar {
Ti::Scalar(Sc {
kind: Sk::Float,
width,
}
})
| Ti::Vector {
kind: Sk::Float,
width,
scalar:
Sc {
kind: Sk::Float,
width,
},
..
} => width,
_ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)),
@ -1266,10 +1302,10 @@ impl super::Validator {
}
// the last argument can always be a scalar
match *arg2_ty {
Ti::Scalar {
Ti::Scalar(Sc {
kind: Sk::Float,
width,
} if width == arg_width => {}
}) if width == arg_width => {}
_ if arg2_ty == arg_ty => {}
_ => {
return Err(ExpressionError::InvalidArgumentType(
@ -1311,12 +1347,16 @@ impl super::Validator {
return Err(ExpressionError::WrongArgumentCount(fun));
}
match *arg_ty {
Ti::Scalar {
Ti::Scalar(Sc {
kind: Sk::Sint | Sk::Uint,
..
}
})
| Ti::Vector {
kind: Sk::Sint | Sk::Uint,
scalar:
Sc {
kind: Sk::Sint | Sk::Uint,
..
},
..
} => {}
_ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)),
@ -1328,12 +1368,16 @@ impl super::Validator {
_ => return Err(ExpressionError::WrongArgumentCount(fun)),
};
match *arg_ty {
Ti::Scalar {
Ti::Scalar(Sc {
kind: Sk::Sint | Sk::Uint,
..
}
})
| Ti::Vector {
kind: Sk::Sint | Sk::Uint,
scalar:
Sc {
kind: Sk::Sint | Sk::Uint,
..
},
..
} => {}
_ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)),
@ -1346,7 +1390,7 @@ impl super::Validator {
));
}
match *arg2_ty {
Ti::Scalar { kind: Sk::Uint, .. } => {}
Ti::Scalar(Sc { kind: Sk::Uint, .. }) => {}
_ => {
return Err(ExpressionError::InvalidArgumentType(
fun,
@ -1356,7 +1400,7 @@ impl super::Validator {
}
}
match *arg3_ty {
Ti::Scalar { kind: Sk::Uint, .. } => {}
Ti::Scalar(Sc { kind: Sk::Uint, .. }) => {}
_ => {
return Err(ExpressionError::InvalidArgumentType(
fun,
@ -1372,18 +1416,22 @@ impl super::Validator {
_ => return Err(ExpressionError::WrongArgumentCount(fun)),
};
match *arg_ty {
Ti::Scalar {
Ti::Scalar(Sc {
kind: Sk::Sint | Sk::Uint,
..
}
})
| Ti::Vector {
kind: Sk::Sint | Sk::Uint,
scalar:
Sc {
kind: Sk::Sint | Sk::Uint,
..
},
..
} => {}
_ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)),
}
match *arg1_ty {
Ti::Scalar { kind: Sk::Uint, .. } => {}
Ti::Scalar(Sc { kind: Sk::Uint, .. }) => {}
_ => {
return Err(ExpressionError::InvalidArgumentType(
fun,
@ -1393,7 +1441,7 @@ impl super::Validator {
}
}
match *arg2_ty {
Ti::Scalar { kind: Sk::Uint, .. } => {}
Ti::Scalar(Sc { kind: Sk::Uint, .. }) => {}
_ => {
return Err(ExpressionError::InvalidArgumentType(
fun,
@ -1410,8 +1458,10 @@ impl super::Validator {
match *arg_ty {
Ti::Vector {
size: crate::VectorSize::Bi,
kind: Sk::Float,
..
scalar:
Sc {
kind: Sk::Float, ..
},
} => {}
_ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)),
}
@ -1423,8 +1473,10 @@ impl super::Validator {
match *arg_ty {
Ti::Vector {
size: crate::VectorSize::Quad,
kind: Sk::Float,
..
scalar:
Sc {
kind: Sk::Float, ..
},
} => {}
_ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)),
}
@ -1438,7 +1490,7 @@ impl super::Validator {
return Err(ExpressionError::WrongArgumentCount(fun));
}
match *arg_ty {
Ti::Scalar { kind: Sk::Uint, .. } => {}
Ti::Scalar(Sc { kind: Sk::Uint, .. }) => {}
_ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)),
}
}
@ -1450,14 +1502,18 @@ impl super::Validator {
kind,
convert,
} => {
let base_width = match resolver[expr] {
crate::TypeInner::Scalar { width, .. }
| crate::TypeInner::Vector { width, .. }
| crate::TypeInner::Matrix { width, .. } => width,
let mut base_scalar = match resolver[expr] {
crate::TypeInner::Scalar(scalar) | crate::TypeInner::Vector { scalar, .. } => {
scalar
}
crate::TypeInner::Matrix { width, .. } => crate::Scalar::float(width),
_ => return Err(ExpressionError::InvalidCastArgument),
};
let width = convert.unwrap_or(base_width);
if self.check_width(kind, width).is_err() {
base_scalar.kind = kind;
if let Some(width) = convert {
base_scalar.width = width;
}
if self.check_width(base_scalar).is_err() {
return Err(ExpressionError::InvalidCastArgument);
}
ShaderStages::all()
@ -1465,10 +1521,12 @@ impl super::Validator {
E::CallResult(function) => mod_info.functions[function.index()].available_stages,
E::AtomicResult { ty, comparison } => {
let scalar_predicate = |ty: &crate::TypeInner| match ty {
&crate::TypeInner::Scalar {
kind: kind @ (crate::ScalarKind::Uint | crate::ScalarKind::Sint),
width,
} => self.check_width(kind, width).is_ok(),
&crate::TypeInner::Scalar(
scalar @ Sc {
kind: crate::ScalarKind::Uint | crate::ScalarKind::Sint,
..
},
) => self.check_width(scalar).is_ok(),
_ => false,
};
let good = match &module.types[ty].inner {
@ -1569,9 +1627,7 @@ impl super::Validator {
}
pub fn validate_literal(&self, literal: crate::Literal) -> Result<(), LiteralError> {
let kind = literal.scalar_kind();
let width = literal.width();
self.check_width(kind, width)?;
self.check_width(literal.scalar())?;
check_literal_value(literal)?;
Ok(())

View File

@ -345,9 +345,9 @@ impl super::Validator {
context: &BlockContext,
) -> Result<(), WithSpan<FunctionError>> {
let pointer_inner = context.resolve_type(pointer, &self.valid_expression_set)?;
let (ptr_kind, ptr_width) = match *pointer_inner {
let ptr_scalar = match *pointer_inner {
crate::TypeInner::Pointer { base, .. } => match context.types[base].inner {
crate::TypeInner::Atomic { kind, width } => (kind, width),
crate::TypeInner::Atomic(scalar) => scalar,
ref other => {
log::error!("Atomic pointer to type {:?}", other);
return Err(AtomicError::InvalidPointer(pointer)
@ -365,7 +365,7 @@ impl super::Validator {
let value_inner = context.resolve_type(value, &self.valid_expression_set)?;
match *value_inner {
crate::TypeInner::Scalar { width, kind } if kind == ptr_kind && width == ptr_width => {}
crate::TypeInner::Scalar(scalar) if scalar == ptr_scalar => {}
ref other => {
log::error!("Atomic operand type {:?}", other);
return Err(AtomicError::InvalidOperand(value)
@ -387,12 +387,8 @@ impl super::Validator {
match context.expressions[result] {
crate::Expression::AtomicResult { ty, comparison }
if {
let scalar_predicate = |ty: &crate::TypeInner| {
*ty == crate::TypeInner::Scalar {
kind: ptr_kind,
width: ptr_width,
}
};
let scalar_predicate =
|ty: &crate::TypeInner| *ty == crate::TypeInner::Scalar(ptr_scalar);
match &context.types[ty].inner {
ty if !comparison => scalar_predicate(ty),
&crate::TypeInner::Struct { ref members, .. } if comparison => {
@ -445,10 +441,10 @@ impl super::Validator {
ref reject,
} => {
match *context.resolve_type(condition, &self.valid_expression_set)? {
Ti::Scalar {
Ti::Scalar(crate::Scalar {
kind: crate::ScalarKind::Bool,
width: _,
} => {}
}) => {}
_ => {
return Err(FunctionError::InvalidIfType(condition)
.with_span_handle(condition, context.expressions))
@ -560,10 +556,10 @@ impl super::Validator {
if let Some(condition) = break_if {
match *context.resolve_type(condition, &self.valid_expression_set)? {
Ti::Scalar {
Ti::Scalar(crate::Scalar {
kind: crate::ScalarKind::Bool,
width: _,
} => {}
}) => {}
_ => {
return Err(FunctionError::InvalidIfType(condition)
.with_span_handle(condition, context.expressions))
@ -665,21 +661,19 @@ impl super::Validator {
let good = match *pointer_ty {
Ti::Pointer { base, space: _ } => match context.types[base].inner {
Ti::Atomic { kind, width } => *value_ty == Ti::Scalar { kind, width },
Ti::Atomic(scalar) => *value_ty == Ti::Scalar(scalar),
ref other => value_ty == other,
},
Ti::ValuePointer {
size: Some(size),
kind,
width,
scalar,
space: _,
} => *value_ty == Ti::Vector { size, kind, width },
} => *value_ty == Ti::Vector { size, scalar },
Ti::ValuePointer {
size: None,
kind,
width,
scalar,
space: _,
} => *value_ty == Ti::Scalar { kind, width },
} => *value_ty == Ti::Scalar(scalar),
_ => false,
};
if !good {
@ -768,10 +762,10 @@ impl super::Validator {
}
if let Some(expr) = array_index {
match *context.resolve_type(expr, &self.valid_expression_set)? {
Ti::Scalar {
Ti::Scalar(crate::Scalar {
kind: crate::ScalarKind::Sint | crate::ScalarKind::Uint,
width: _,
} => {}
}) => {}
_ => {
return Err(FunctionError::InvalidImageStore(
ExpressionError::InvalidImageArrayIndexType(expr),
@ -783,9 +777,11 @@ impl super::Validator {
match class {
crate::ImageClass::Storage { format, .. } => {
crate::TypeInner::Vector {
kind: format.into(),
size: crate::VectorSize::Quad,
width: 4,
scalar: crate::Scalar {
kind: format.into(),
width: 4,
},
}
}
_ => {

View File

@ -678,10 +678,7 @@ fn constant_deps() {
let i32_handle = types.insert(
Type {
name: None,
inner: TypeInner::Scalar {
kind: crate::ScalarKind::Sint,
width: 4,
},
inner: TypeInner::Scalar(crate::Scalar::I32),
},
nowhere,
);

View File

@ -142,9 +142,7 @@ impl VaryingContext<'_> {
ty: Handle<crate::Type>,
binding: &crate::Binding,
) -> Result<(), VaryingError> {
use crate::{
BuiltIn as Bi, ScalarKind as Sk, ShaderStage as St, TypeInner as Ti, VectorSize as Vs,
};
use crate::{BuiltIn as Bi, ShaderStage as St, TypeInner as Ti, VectorSize as Vs};
let ty_inner = &self.types[ty].inner;
match *binding {
@ -174,44 +172,30 @@ impl VaryingContext<'_> {
return Err(VaryingError::UnsupportedCapability(required));
}
let width = 4;
let (visible, type_good) = match built_in {
Bi::BaseInstance | Bi::BaseVertex | Bi::InstanceIndex | Bi::VertexIndex => (
self.stage == St::Vertex && !self.output,
*ty_inner
== Ti::Scalar {
kind: Sk::Uint,
width,
},
*ty_inner == Ti::Scalar(crate::Scalar::U32),
),
Bi::ClipDistance | Bi::CullDistance => (
self.stage == St::Vertex && self.output,
match *ty_inner {
Ti::Array { base, .. } => {
self.types[base].inner
== Ti::Scalar {
kind: Sk::Float,
width,
}
self.types[base].inner == Ti::Scalar(crate::Scalar::F32)
}
_ => false,
},
),
Bi::PointSize => (
self.stage == St::Vertex && self.output,
*ty_inner
== Ti::Scalar {
kind: Sk::Float,
width,
},
*ty_inner == Ti::Scalar(crate::Scalar::F32),
),
Bi::PointCoord => (
self.stage == St::Fragment && !self.output,
*ty_inner
== Ti::Vector {
size: Vs::Bi,
kind: Sk::Float,
width,
scalar: crate::Scalar::F32,
},
),
Bi::Position { .. } => (
@ -223,8 +207,7 @@ impl VaryingContext<'_> {
*ty_inner
== Ti::Vector {
size: Vs::Quad,
kind: Sk::Float,
width,
scalar: crate::Scalar::F32,
},
),
Bi::ViewIndex => (
@ -232,59 +215,31 @@ impl VaryingContext<'_> {
St::Vertex | St::Fragment => !self.output,
St::Compute => false,
},
*ty_inner
== Ti::Scalar {
kind: Sk::Sint,
width,
},
*ty_inner == Ti::Scalar(crate::Scalar::I32),
),
Bi::FragDepth => (
self.stage == St::Fragment && self.output,
*ty_inner
== Ti::Scalar {
kind: Sk::Float,
width,
},
*ty_inner == Ti::Scalar(crate::Scalar::F32),
),
Bi::FrontFacing => (
self.stage == St::Fragment && !self.output,
*ty_inner
== Ti::Scalar {
kind: Sk::Bool,
width: crate::BOOL_WIDTH,
},
*ty_inner == Ti::Scalar(crate::Scalar::BOOL),
),
Bi::PrimitiveIndex => (
self.stage == St::Fragment && !self.output,
*ty_inner
== Ti::Scalar {
kind: Sk::Uint,
width,
},
*ty_inner == Ti::Scalar(crate::Scalar::U32),
),
Bi::SampleIndex => (
self.stage == St::Fragment && !self.output,
*ty_inner
== Ti::Scalar {
kind: Sk::Uint,
width,
},
*ty_inner == Ti::Scalar(crate::Scalar::U32),
),
Bi::SampleMask => (
self.stage == St::Fragment,
*ty_inner
== Ti::Scalar {
kind: Sk::Uint,
width,
},
*ty_inner == Ti::Scalar(crate::Scalar::U32),
),
Bi::LocalInvocationIndex => (
self.stage == St::Compute && !self.output,
*ty_inner
== Ti::Scalar {
kind: Sk::Uint,
width,
},
*ty_inner == Ti::Scalar(crate::Scalar::U32),
),
Bi::GlobalInvocationId
| Bi::LocalInvocationId
@ -295,8 +250,7 @@ impl VaryingContext<'_> {
*ty_inner
== Ti::Vector {
size: Vs::Tri,
kind: Sk::Uint,
width,
scalar: crate::Scalar::U32,
},
),
};

View File

@ -264,19 +264,25 @@ impl crate::TypeInner {
#[cfg(feature = "validate")]
const fn image_storage_coordinates(&self) -> Option<crate::ImageDimension> {
match *self {
Self::Scalar {
Self::Scalar(crate::Scalar {
kind: crate::ScalarKind::Sint | crate::ScalarKind::Uint,
..
} => Some(crate::ImageDimension::D1),
}) => Some(crate::ImageDimension::D1),
Self::Vector {
size: crate::VectorSize::Bi,
kind: crate::ScalarKind::Sint | crate::ScalarKind::Uint,
..
scalar:
crate::Scalar {
kind: crate::ScalarKind::Sint | crate::ScalarKind::Uint,
..
},
} => Some(crate::ImageDimension::D2),
Self::Vector {
size: crate::VectorSize::Tri,
kind: crate::ScalarKind::Sint | crate::ScalarKind::Uint,
..
scalar:
crate::Scalar {
kind: crate::ScalarKind::Sint | crate::ScalarKind::Uint,
..
},
} => Some(crate::ImageDimension::D3),
_ => None,
}
@ -349,10 +355,11 @@ impl Validator {
ValidationError::from(e).with_span_handle(handle, &module.types)
})?;
let placeholder = TypeResolution::Value(crate::TypeInner::Scalar {
// These should all get overwritten.
let placeholder = TypeResolution::Value(crate::TypeInner::Scalar(crate::Scalar {
kind: crate::ScalarKind::Bool,
width: 0,
});
}));
let mut mod_info = ModuleInfo {
type_flags: Vec::with_capacity(module.types.len()),
@ -482,9 +489,5 @@ fn validate_atomic_compare_exchange_struct(
&& members[0].name.as_deref() == Some("old_value")
&& scalar_predicate(&types[members[0].ty].inner)
&& members[1].name.as_deref() == Some("exchanged")
&& types[members[1].ty].inner
== crate::TypeInner::Scalar {
kind: crate::ScalarKind::Bool,
width: crate::BOOL_WIDTH,
}
&& types[members[1].ty].inner == crate::TypeInner::Scalar(crate::Scalar::BOOL)
}

View File

@ -224,15 +224,11 @@ impl super::Validator {
}
}
pub(super) const fn check_width(
&self,
kind: crate::ScalarKind,
width: crate::Bytes,
) -> Result<(), WidthError> {
let good = match kind {
crate::ScalarKind::Bool => width == crate::BOOL_WIDTH,
pub(super) const fn check_width(&self, scalar: crate::Scalar) -> Result<(), WidthError> {
let good = match scalar.kind {
crate::ScalarKind::Bool => scalar.width == crate::BOOL_WIDTH,
crate::ScalarKind::Float => {
if width == 8 {
if scalar.width == 8 {
if !self.capabilities.contains(Capabilities::FLOAT64) {
return Err(WidthError::MissingCapability {
name: "f64",
@ -241,15 +237,15 @@ impl super::Validator {
}
true
} else {
width == 4
scalar.width == 4
}
}
crate::ScalarKind::Sint | crate::ScalarKind::Uint => width == 4,
crate::ScalarKind::Sint | crate::ScalarKind::Uint => scalar.width == 4,
};
if good {
Ok(())
} else {
Err(WidthError::Invalid(kind, width))
Err(WidthError::Invalid(scalar.kind, scalar.width))
}
}
@ -266,9 +262,9 @@ impl super::Validator {
) -> Result<TypeInfo, TypeError> {
use crate::TypeInner as Ti;
Ok(match gctx.types[handle].inner {
Ti::Scalar { kind, width } => {
self.check_width(kind, width)?;
let shareable = if kind.is_numeric() {
Ti::Scalar(scalar) => {
self.check_width(scalar)?;
let shareable = if scalar.kind.is_numeric() {
TypeFlags::IO_SHAREABLE | TypeFlags::HOST_SHAREABLE
} else {
TypeFlags::empty()
@ -280,12 +276,12 @@ impl super::Validator {
| TypeFlags::ARGUMENT
| TypeFlags::CONSTRUCTIBLE
| shareable,
Alignment::from_width(width),
Alignment::from_width(scalar.width),
)
}
Ti::Vector { size, kind, width } => {
self.check_width(kind, width)?;
let shareable = if kind.is_numeric() {
Ti::Vector { size, scalar } => {
self.check_width(scalar)?;
let shareable = if scalar.kind.is_numeric() {
TypeFlags::IO_SHAREABLE | TypeFlags::HOST_SHAREABLE
} else {
TypeFlags::empty()
@ -298,7 +294,7 @@ impl super::Validator {
| TypeFlags::ARGUMENT
| TypeFlags::CONSTRUCTIBLE
| shareable,
Alignment::from(size) * Alignment::from_width(width),
Alignment::from(size) * Alignment::from_width(scalar.width),
)
}
Ti::Matrix {
@ -306,7 +302,7 @@ impl super::Validator {
rows,
width,
} => {
self.check_width(crate::ScalarKind::Float, width)?;
self.check_width(crate::Scalar::float(width))?;
TypeInfo::new(
TypeFlags::DATA
| TypeFlags::SIZED
@ -317,7 +313,7 @@ impl super::Validator {
Alignment::from(rows) * Alignment::from_width(width),
)
}
Ti::Atomic { kind, width } => {
Ti::Atomic(crate::Scalar { kind, width }) => {
let good = match kind {
crate::ScalarKind::Bool | crate::ScalarKind::Float => false,
crate::ScalarKind::Sint | crate::ScalarKind::Uint => width == 4,
@ -373,8 +369,7 @@ impl super::Validator {
}
Ti::ValuePointer {
size: _,
kind,
width,
scalar,
space,
} => {
// ValuePointer should be treated the same way as the equivalent
@ -384,7 +379,7 @@ impl super::Validator {
// However, some cases are trivial: All our implicit base types
// are DATA and SIZED, so we can never return
// `InvalidPointerBase` or `InvalidPointerToUnsized`.
self.check_width(kind, width)?;
self.check_width(scalar)?;
// `Validator::validate_function` actually checks the address
// space of pointer arguments explicitly before checking the

View File

@ -1 +1 @@
{"files":{"COPYING":"01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f","Cargo.toml":"2e1ffefd2c70d47b5097d7ecc26184d92e4e2be1174c53147a617729024a4a51","LICENSE-MIT":"0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f","README.md":"cc4c882bde8d2ef26ef4770ff30d60eda603d87ae32e16d99525dc88f3377238","UNLICENSE":"7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c","rustfmt.toml":"1ca600239a27401c4a43f363cf3f38183a212affc1f31bff3ae93234bbaec228","src/lib.rs":"fe62bc640112ffb687366fbe4a084ed3bf749185f77d1e401757ab148313fb7e"},"package":"be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"}
{"files":{"COPYING":"01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f","Cargo.toml":"99e42d9c2cccfe0c7ba563ec3d1eef0ceb1a0a7b1e73722b51b98fb388ab5b39","LICENSE-MIT":"0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f","README.md":"b07f32791ef31fdc347d1d4a62a0bf0979ab825a361ca9079f31908a0b78ea96","UNLICENSE":"7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c","rustfmt.toml":"1ca600239a27401c4a43f363cf3f38183a212affc1f31bff3ae93234bbaec228","src/lib.rs":"82d177e0cd4be591e6af29fc422dc996fde5c8ef4c75cdabdd2b12884956fad2"},"package":"ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449"}

View File

@ -12,7 +12,7 @@
[package]
edition = "2018"
name = "termcolor"
version = "1.2.0"
version = "1.4.0"
authors = ["Andrew Gallant <jamslam@gmail.com>"]
description = """
A simple cross platform library for writing colored text to a terminal.

View File

@ -1,13 +1,13 @@
termcolor
=========
A simple cross platform library for writing colored text to a terminal. This
library writes colored text either using standard ANSI escape sequences or
by interacting with the Windows console. Several convenient abstractions
are provided for use in single-threaded or multi-threaded command line
library writes colored text either using standard ANSI escape sequences or by
interacting with the Windows console. Several convenient abstractions are
provided for use in single-threaded or multi-threaded command line
applications.
[![Build status](https://github.com/BurntSushi/termcolor/workflows/ci/badge.svg)](https://github.com/BurntSushi/termcolor/actions)
[![](https://img.shields.io/crates/v/termcolor.svg)](https://crates.io/crates/termcolor)
[![crates.io](https://img.shields.io/crates/v/termcolor.svg)](https://crates.io/crates/termcolor)
Dual-licensed under MIT or the [UNLICENSE](https://unlicense.org/).
@ -17,12 +17,7 @@ Dual-licensed under MIT or the [UNLICENSE](https://unlicense.org/).
### Usage
Add this to your `Cargo.toml`:
```toml
[dependencies]
termcolor = "1.1"
```
Run `cargo add termcolor` to add this dependency to your `Cargo.toml` file.
### Organization
@ -47,8 +42,8 @@ analogous type for the Windows console is not provided since it cannot exist.
### Example: using `StandardStream`
The `StandardStream` type in this crate works similarly to `std::io::Stdout`,
except it is augmented with methods for coloring by the `WriteColor` trait.
For example, to write some green text:
except it is augmented with methods for coloring by the `WriteColor` trait. For
example, to write some green text:
```rust
use std::io::{self, Write};
@ -98,8 +93,8 @@ termcolor will inspect the `TERM` and `NO_COLOR` environment variables:
This decision procedure may change over time.
Currently, `termcolor` does not attempt to detect whether a tty is present or
not. To achieve that, please use the [`atty`](https://crates.io/crates/atty)
crate.
not. To achieve that, please use
[`std::io::IsTerminal`](https://doc.rust-lang.org/std/io/trait.IsTerminal.html).
### Minimum Rust version policy

View File

@ -10,6 +10,8 @@ to an in memory buffer. While this is easy to do with ANSI escape sequences
(because they are in the buffer themselves), it is trickier to do with the
Windows console API, which requires synchronous communication.
In ANSI mode, this crate also provides support for writing hyperlinks.
# Organization
The `WriteColor` trait extends the `io::Write` trait with methods for setting
@ -85,21 +87,21 @@ is via libc's
[`isatty`](https://man7.org/linux/man-pages/man3/isatty.3.html)
function.
Unfortunately, this notoriously does not work well in Windows environments. To
work around that, the currently recommended solution is to use the
[`atty`](https://crates.io/crates/atty)
crate, which goes out of its way to get this as right as possible in Windows
environments.
work around that, the recommended solution is to use the standard library's
[`IsTerminal`](https://doc.rust-lang.org/std/io/trait.IsTerminal.html) trait.
It goes out of its way to get it as right as possible in Windows environments.
For example, in a command line application that exposes a `--color` flag,
your logic for how to enable colors might look like this:
```rust,ignore
use atty;
```ignore
use std::io::IsTerminal;
use termcolor::{ColorChoice, StandardStream};
let preference = argv.get_flag("color").unwrap_or("auto");
let mut choice = preference.parse::<ColorChoice>()?;
if choice == ColorChoice::Auto && !atty::is(atty::Stream::Stdout) {
if choice == ColorChoice::Auto && !std::io::stdin().is_terminal() {
choice = ColorChoice::Never;
}
let stdout = StandardStream::stdout(choice);
@ -146,6 +148,10 @@ pub trait WriteColor: io::Write {
///
/// If there was a problem resetting the color settings, then an error is
/// returned.
///
/// Note that this does not reset hyperlinks. Those need to be
/// reset on their own, e.g., by calling `set_hyperlink` with
/// [`HyperlinkSpec::none`].
fn reset(&mut self) -> io::Result<()>;
/// Returns true if and only if the underlying writer must synchronously
@ -162,15 +168,49 @@ pub trait WriteColor: io::Write {
fn is_synchronous(&self) -> bool {
false
}
/// Set the current hyperlink of the writer.
///
/// The typical way to use this is to first call it with a
/// [`HyperlinkSpec::open`] to write the actual URI to a tty that supports
/// [OSC-8]. At this point, the caller can now write the label for the
/// hyperlink. This may include coloring or other styles. Once the caller
/// has finished writing the label, one should call this method again with
/// [`HyperlinkSpec::close`].
///
/// If there was a problem setting the hyperlink, then an error is
/// returned.
///
/// This defaults to doing nothing.
///
/// [OSC8]: https://github.com/Alhadis/OSC8-Adoption/
fn set_hyperlink(&mut self, _link: &HyperlinkSpec) -> io::Result<()> {
Ok(())
}
/// Returns true if and only if the underlying writer supports hyperlinks.
///
/// This can be used to avoid generating hyperlink URIs unnecessarily.
///
/// This defaults to `false`.
fn supports_hyperlinks(&self) -> bool {
false
}
}
impl<'a, T: ?Sized + WriteColor> WriteColor for &'a mut T {
fn supports_color(&self) -> bool {
(&**self).supports_color()
}
fn supports_hyperlinks(&self) -> bool {
(&**self).supports_hyperlinks()
}
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
(&mut **self).set_color(spec)
}
fn set_hyperlink(&mut self, link: &HyperlinkSpec) -> io::Result<()> {
(&mut **self).set_hyperlink(link)
}
fn reset(&mut self) -> io::Result<()> {
(&mut **self).reset()
}
@ -183,9 +223,15 @@ impl<T: ?Sized + WriteColor> WriteColor for Box<T> {
fn supports_color(&self) -> bool {
(&**self).supports_color()
}
fn supports_hyperlinks(&self) -> bool {
(&**self).supports_hyperlinks()
}
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
(&mut **self).set_color(spec)
}
fn set_hyperlink(&mut self, link: &HyperlinkSpec) -> io::Result<()> {
(&mut **self).set_hyperlink(link)
}
fn reset(&mut self) -> io::Result<()> {
(&mut **self).reset()
}
@ -668,11 +714,21 @@ impl WriteColor for StandardStream {
self.wtr.supports_color()
}
#[inline]
fn supports_hyperlinks(&self) -> bool {
self.wtr.supports_hyperlinks()
}
#[inline]
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
self.wtr.set_color(spec)
}
#[inline]
fn set_hyperlink(&mut self, link: &HyperlinkSpec) -> io::Result<()> {
self.wtr.set_hyperlink(link)
}
#[inline]
fn reset(&mut self) -> io::Result<()> {
self.wtr.reset()
@ -702,11 +758,21 @@ impl<'a> WriteColor for StandardStreamLock<'a> {
self.wtr.supports_color()
}
#[inline]
fn supports_hyperlinks(&self) -> bool {
self.wtr.supports_hyperlinks()
}
#[inline]
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
self.wtr.set_color(spec)
}
#[inline]
fn set_hyperlink(&mut self, link: &HyperlinkSpec) -> io::Result<()> {
self.wtr.set_hyperlink(link)
}
#[inline]
fn reset(&mut self) -> io::Result<()> {
self.wtr.reset()
@ -736,6 +802,11 @@ impl WriteColor for BufferedStandardStream {
self.wtr.supports_color()
}
#[inline]
fn supports_hyperlinks(&self) -> bool {
self.wtr.supports_hyperlinks()
}
#[inline]
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
if self.is_synchronous() {
@ -744,6 +815,14 @@ impl WriteColor for BufferedStandardStream {
self.wtr.set_color(spec)
}
#[inline]
fn set_hyperlink(&mut self, link: &HyperlinkSpec) -> io::Result<()> {
if self.is_synchronous() {
self.wtr.flush()?;
}
self.wtr.set_hyperlink(link)
}
#[inline]
fn reset(&mut self) -> io::Result<()> {
self.wtr.reset()
@ -787,6 +866,15 @@ impl<W: io::Write> WriteColor for WriterInner<W> {
}
}
fn supports_hyperlinks(&self) -> bool {
match *self {
WriterInner::NoColor(_) => false,
WriterInner::Ansi(_) => true,
#[cfg(windows)]
WriterInner::Windows { .. } => false,
}
}
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
match *self {
WriterInner::NoColor(ref mut wtr) => wtr.set_color(spec),
@ -800,6 +888,15 @@ impl<W: io::Write> WriteColor for WriterInner<W> {
}
}
fn set_hyperlink(&mut self, link: &HyperlinkSpec) -> io::Result<()> {
match *self {
WriterInner::NoColor(ref mut wtr) => wtr.set_hyperlink(link),
WriterInner::Ansi(ref mut wtr) => wtr.set_hyperlink(link),
#[cfg(windows)]
WriterInner::Windows { .. } => Ok(()),
}
}
fn reset(&mut self) -> io::Result<()> {
match *self {
WriterInner::NoColor(ref mut wtr) => wtr.reset(),
@ -856,6 +953,16 @@ impl<'a, W: io::Write> WriteColor for WriterInnerLock<'a, W> {
}
}
fn supports_hyperlinks(&self) -> bool {
match *self {
WriterInnerLock::Unreachable(_) => unreachable!(),
WriterInnerLock::NoColor(_) => false,
WriterInnerLock::Ansi(_) => true,
#[cfg(windows)]
WriterInnerLock::Windows { .. } => false,
}
}
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
match *self {
WriterInnerLock::Unreachable(_) => unreachable!(),
@ -869,6 +976,16 @@ impl<'a, W: io::Write> WriteColor for WriterInnerLock<'a, W> {
}
}
fn set_hyperlink(&mut self, link: &HyperlinkSpec) -> io::Result<()> {
match *self {
WriterInnerLock::Unreachable(_) => unreachable!(),
WriterInnerLock::NoColor(ref mut wtr) => wtr.set_hyperlink(link),
WriterInnerLock::Ansi(ref mut wtr) => wtr.set_hyperlink(link),
#[cfg(windows)]
WriterInnerLock::Windows { .. } => Ok(()),
}
}
fn reset(&mut self) -> io::Result<()> {
match *self {
WriterInnerLock::Unreachable(_) => unreachable!(),
@ -1062,11 +1179,11 @@ impl BufferWriter {
/// method, which will take color preferences and the environment into
/// account. However, buffers can also be manually created using `no_color`,
/// `ansi` or `console` (on Windows).
#[derive(Debug)]
#[derive(Clone, Debug)]
pub struct Buffer(BufferInner);
/// BufferInner is an enumeration of different buffer types.
#[derive(Debug)]
#[derive(Clone, Debug)]
enum BufferInner {
/// No coloring information should be applied. This ignores all coloring
/// directives.
@ -1219,6 +1336,16 @@ impl WriteColor for Buffer {
}
}
#[inline]
fn supports_hyperlinks(&self) -> bool {
match self.0 {
BufferInner::NoColor(_) => false,
BufferInner::Ansi(_) => true,
#[cfg(windows)]
BufferInner::Windows(_) => false,
}
}
#[inline]
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
match self.0 {
@ -1229,6 +1356,16 @@ impl WriteColor for Buffer {
}
}
#[inline]
fn set_hyperlink(&mut self, link: &HyperlinkSpec) -> io::Result<()> {
match self.0 {
BufferInner::NoColor(ref mut w) => w.set_hyperlink(link),
BufferInner::Ansi(ref mut w) => w.set_hyperlink(link),
#[cfg(windows)]
BufferInner::Windows(ref mut w) => w.set_hyperlink(link),
}
}
#[inline]
fn reset(&mut self) -> io::Result<()> {
match self.0 {
@ -1246,7 +1383,7 @@ impl WriteColor for Buffer {
}
/// Satisfies `WriteColor` but ignores all color options.
#[derive(Debug)]
#[derive(Clone, Debug)]
pub struct NoColor<W>(W);
impl<W: Write> NoColor<W> {
@ -1290,11 +1427,21 @@ impl<W: io::Write> WriteColor for NoColor<W> {
false
}
#[inline]
fn supports_hyperlinks(&self) -> bool {
false
}
#[inline]
fn set_color(&mut self, _: &ColorSpec) -> io::Result<()> {
Ok(())
}
#[inline]
fn set_hyperlink(&mut self, _: &HyperlinkSpec) -> io::Result<()> {
Ok(())
}
#[inline]
fn reset(&mut self) -> io::Result<()> {
Ok(())
@ -1307,7 +1454,7 @@ impl<W: io::Write> WriteColor for NoColor<W> {
}
/// Satisfies `WriteColor` using standard ANSI escape sequences.
#[derive(Debug)]
#[derive(Clone, Debug)]
pub struct Ansi<W>(W);
impl<W: Write> Ansi<W> {
@ -1362,6 +1509,11 @@ impl<W: io::Write> WriteColor for Ansi<W> {
true
}
#[inline]
fn supports_hyperlinks(&self) -> bool {
true
}
#[inline]
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
if spec.reset {
@ -1391,6 +1543,15 @@ impl<W: io::Write> WriteColor for Ansi<W> {
Ok(())
}
#[inline]
fn set_hyperlink(&mut self, link: &HyperlinkSpec) -> io::Result<()> {
self.write_str("\x1B]8;;")?;
if let Some(uri) = link.uri() {
self.write_all(uri)?;
}
self.write_str("\x1B\\")
}
#[inline]
fn reset(&mut self) -> io::Result<()> {
self.write_str("\x1B[0m")
@ -1522,10 +1683,18 @@ impl WriteColor for io::Sink {
false
}
fn supports_hyperlinks(&self) -> bool {
false
}
fn set_color(&mut self, _: &ColorSpec) -> io::Result<()> {
Ok(())
}
fn set_hyperlink(&mut self, _: &HyperlinkSpec) -> io::Result<()> {
Ok(())
}
fn reset(&mut self) -> io::Result<()> {
Ok(())
}
@ -1624,12 +1793,22 @@ impl WriteColor for WindowsBuffer {
true
}
#[inline]
fn supports_hyperlinks(&self) -> bool {
false
}
#[inline]
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
self.push(Some(spec.clone()));
Ok(())
}
#[inline]
fn set_hyperlink(&mut self, _: &HyperlinkSpec) -> io::Result<()> {
Ok(())
}
#[inline]
fn reset(&mut self) -> io::Result<()> {
self.push(None);
@ -2085,6 +2264,29 @@ impl FromStr for Color {
}
}
/// A hyperlink specification.
#[derive(Clone, Debug)]
pub struct HyperlinkSpec<'a> {
uri: Option<&'a [u8]>,
}
impl<'a> HyperlinkSpec<'a> {
/// Creates a new hyperlink specification.
pub fn open(uri: &'a [u8]) -> HyperlinkSpec<'a> {
HyperlinkSpec { uri: Some(uri) }
}
/// Creates a hyperlink specification representing no hyperlink.
pub fn close() -> HyperlinkSpec<'a> {
HyperlinkSpec { uri: None }
}
/// Returns the URI of the hyperlink if one is attached to this spec.
pub fn uri(&self) -> Option<&'a [u8]> {
self.uri
}
}
#[derive(Debug)]
struct LossyStandardStream<W> {
wtr: W,
@ -2124,9 +2326,15 @@ impl<W: WriteColor> WriteColor for LossyStandardStream<W> {
fn supports_color(&self) -> bool {
self.wtr.supports_color()
}
fn supports_hyperlinks(&self) -> bool {
self.wtr.supports_hyperlinks()
}
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
self.wtr.set_color(spec)
}
fn set_hyperlink(&mut self, link: &HyperlinkSpec) -> io::Result<()> {
self.wtr.set_hyperlink(link)
}
fn reset(&mut self) -> io::Result<()> {
self.wtr.reset()
}
@ -2170,8 +2378,8 @@ fn write_lossy_utf8<W: io::Write>(mut w: W, buf: &[u8]) -> io::Result<usize> {
#[cfg(test)]
mod tests {
use super::{
Ansi, Color, ColorSpec, ParseColorError, ParseColorErrorKind,
StandardStream, WriteColor,
Ansi, Color, ColorSpec, HyperlinkSpec, ParseColorError,
ParseColorErrorKind, StandardStream, WriteColor,
};
fn assert_is_send<T: Send>() {}
@ -2347,4 +2555,18 @@ mod tests {
assert!(color1.is_none(), "{:?} => {:?}", color, color1);
}
}
#[test]
fn test_ansi_hyperlink() {
let mut buf = Ansi::new(vec![]);
buf.set_hyperlink(&HyperlinkSpec::open(b"https://example.com"))
.unwrap();
buf.write_str("label").unwrap();
buf.set_hyperlink(&HyperlinkSpec::close()).unwrap();
assert_eq!(
buf.0,
b"\x1B]8;;https://example.com\x1B\\label\x1B]8;;\x1B\\".to_vec()
);
}
}

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"a01dee48cee8d362ac28b8c920b914d11be2362ca6d7d6036b6d786eca348be2","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","src/binding_model.rs":"f6d9b170a9328751b3109c81d6f1b555a6db1410f1b7e67c59cc596a1fd1d293","src/command/bind.rs":"67b8431a32f403e358b9c1593e6e0d64519f5f0b699059e6ea5374800d5c23d9","src/command/bundle.rs":"d5456be31f973fcae55ee01781da963f1c950aa5db7eae4d3c6166d4f1a132ca","src/command/clear.rs":"bf78a5eab40f67343054dc982c51f45caab36fb5bddaf065b7a4c1b7a0ada803","src/command/compute.rs":"8caa0f5fa1956a3747f0b845fdeec2572b9462a7e98fdb5cf7b562c472bd6c4c","src/command/draw.rs":"3687cbde422a29f28c1c3d17e132d912b3b4b2bcc98efca68d1ee0d563a5bf56","src/command/memory_init.rs":"b50d3d20dbf659052f19da2e79469ba6435e06370f19d6ef45e1b1128d9900b7","src/command/mod.rs":"4eac2ac0283c0cfdcc3512af5439fe38e7004e5f406bf52a66d3017ad1ae7632","src/command/query.rs":"d39e1b8cb6a054fd31333a916da5d79a6671a724212c90c490c13e55043a1685","src/command/render.rs":"c445f52d0b82d80033071025446ca2488ef702d4fd452fe4c67b154392630bab","src/command/transfer.rs":"2b6f266ba1155ab42bed23b28abffc1008ce26d60b656f56012b896e63daa111","src/conv.rs":"da95b36b7680ae74ebf810ad8f1decf01bd3eeaff44b3c5af1d4b3c3f0e2059a","src/device/global.rs":"704343ae4ef83e48b362f97a8daa29642cdcb8b02c7599615b250982844ae421","src/device/life.rs":"9ac0aab46de65fd2b493f3ee2c3527e37eaad9dbde1583752958eace71423cef","src/device/mod.rs":"702cd9c88015fb40d8ea838ed607afcfceb5bea809f508c49a70b49d5b9803fd","src/device/queue.rs":"e92840c4cf6af66947cd9b7189f1c539ead08f4610a7dddf9726a8c1294b6a36","src/device/resource.rs":"8ae77a27fc7179bb2020aaa41ce7deba4db33d239ca42ba3307d3b3c34d3b363","src/device/trace.rs":"21408dfd2c99e3ce36a77d08ba86cf52f32bb376ed82690bbbf74937bfd42cbe","src/error.rs":"ca37282283985e2b7d184b2ab7ca6f53f726432d920f8d8477bfff6fab9b34e2","src/global.rs":"cf551de97c3eb5acd0c2710da09ebd92cc863ad0bb0f53c0fd4911bf8cd3ad97","src/hal_api.rs":"92a2f0cb80f192693530ed61048919bbad446742c2370bf0944c44b1c5df8362","src/hub.rs":"b4207d0a450da9e1d9edb0abc3c99e495132793ebe26af78ea07397d2e5c0b85","src/id.rs":"ef7b3a77110277f4eb2fa1a2ae3d89318023b74d5671181684d2845ef7b7d87a","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":"37b1d19ebbc03642368c0ef668f5f897a3cac8a6cccc553b50f3de5c800fde8b","src/lib.rs":"71d42899594be62c2e7074618e03f3639b5ef510b42d6dde660aaa4d5672691e","src/pipeline.rs":"4741c36fad7dedb856c3254f7869cad68dcf143aaac280f7f5920009b13c899a","src/present.rs":"a81f62ca967825f777a5f0d32defb2febb8793406c527d08c6ab0e129df5a81a","src/registry.rs":"4098413de7f48e9ff15d0246793be47a0d54c95b4c8594baf9fafd222a90ba84","src/resource.rs":"f140a1071d03dccae9859047c063dcd289e653352d635082dba76ef37a6ca4c3","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":"815961f6a38cd0691aa8af85e739fd3668133c0ca8937c84bfe698070490d418"},"package":null}
{"files":{"Cargo.toml":"a01dee48cee8d362ac28b8c920b914d11be2362ca6d7d6036b6d786eca348be2","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","src/binding_model.rs":"f6d9b170a9328751b3109c81d6f1b555a6db1410f1b7e67c59cc596a1fd1d293","src/command/bind.rs":"67b8431a32f403e358b9c1593e6e0d64519f5f0b699059e6ea5374800d5c23d9","src/command/bundle.rs":"d5456be31f973fcae55ee01781da963f1c950aa5db7eae4d3c6166d4f1a132ca","src/command/clear.rs":"9c4c1734705a79b64a31540ddf7ec4e9f10b9d923b6d21783d98314a7b10bb25","src/command/compute.rs":"8caa0f5fa1956a3747f0b845fdeec2572b9462a7e98fdb5cf7b562c472bd6c4c","src/command/draw.rs":"3687cbde422a29f28c1c3d17e132d912b3b4b2bcc98efca68d1ee0d563a5bf56","src/command/memory_init.rs":"b50d3d20dbf659052f19da2e79469ba6435e06370f19d6ef45e1b1128d9900b7","src/command/mod.rs":"4eac2ac0283c0cfdcc3512af5439fe38e7004e5f406bf52a66d3017ad1ae7632","src/command/query.rs":"d39e1b8cb6a054fd31333a916da5d79a6671a724212c90c490c13e55043a1685","src/command/render.rs":"c445f52d0b82d80033071025446ca2488ef702d4fd452fe4c67b154392630bab","src/command/transfer.rs":"1fc4d8a87eef3241134f0e6d3bb617511629afe10fddb16440f688e17bee7719","src/conv.rs":"da95b36b7680ae74ebf810ad8f1decf01bd3eeaff44b3c5af1d4b3c3f0e2059a","src/device/global.rs":"2ccbc26fddb9291fecd0fe3c5e85c806cf77319fe2818a8684a81bed3ea7e649","src/device/life.rs":"6a7cbf7d47155fe1171387221141eefab135868196a03b0bba86ab168d9dee58","src/device/mod.rs":"a7627267001bbadb7309f4f0721ecec404dcba06bd6aab4dd6fa17410fc7402b","src/device/queue.rs":"56cbce0ed748c78d2360e3e042ffade1d941231acbb873d7aab4ac65b938ad06","src/device/resource.rs":"c4173ab900d5332984bb20e5e2733c4c1aa799e06bfe1e975fe55982ec3cdf29","src/device/trace.rs":"21408dfd2c99e3ce36a77d08ba86cf52f32bb376ed82690bbbf74937bfd42cbe","src/error.rs":"ca37282283985e2b7d184b2ab7ca6f53f726432d920f8d8477bfff6fab9b34e2","src/global.rs":"cf551de97c3eb5acd0c2710da09ebd92cc863ad0bb0f53c0fd4911bf8cd3ad97","src/hal_api.rs":"92a2f0cb80f192693530ed61048919bbad446742c2370bf0944c44b1c5df8362","src/hub.rs":"b4207d0a450da9e1d9edb0abc3c99e495132793ebe26af78ea07397d2e5c0b85","src/id.rs":"ef7b3a77110277f4eb2fa1a2ae3d89318023b74d5671181684d2845ef7b7d87a","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":"37b1d19ebbc03642368c0ef668f5f897a3cac8a6cccc553b50f3de5c800fde8b","src/lib.rs":"71d42899594be62c2e7074618e03f3639b5ef510b42d6dde660aaa4d5672691e","src/pipeline.rs":"4741c36fad7dedb856c3254f7869cad68dcf143aaac280f7f5920009b13c899a","src/present.rs":"a81f62ca967825f777a5f0d32defb2febb8793406c527d08c6ab0e129df5a81a","src/registry.rs":"4098413de7f48e9ff15d0246793be47a0d54c95b4c8594baf9fafd222a90ba84","src/resource.rs":"f140a1071d03dccae9859047c063dcd289e653352d635082dba76ef37a6ca4c3","src/storage.rs":"11ccae01252ae68727a256e5db6826f74973cfc753a18dedf7fabf8aef5596cc","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":"8b4db473ef01d3603f45eac6bf613874624755bc2f85972720ca94db7b556753"},"package":null}

View File

@ -331,7 +331,7 @@ fn clear_texture_via_buffer_copies<A: hal::Api>(
let mut zero_buffer_copy_regions = Vec::new();
let buffer_copy_pitch = alignments.buffer_copy_pitch.get() as u32;
let (block_width, block_height) = texture_desc.format.block_dimensions();
let block_size = texture_desc.format.block_size(None).unwrap();
let block_size = texture_desc.format.block_copy_size(None).unwrap();
let bytes_per_row_alignment = get_lowest_common_denom(buffer_copy_pitch, block_size);

View File

@ -254,7 +254,7 @@ pub(crate) fn validate_linear_texture_data(
let offset = layout.offset;
let block_size = format.block_size(Some(aspect)).unwrap() as BufferAddress;
let block_size = format.block_copy_size(Some(aspect)).unwrap() as BufferAddress;
let (block_width, block_height) = format.block_dimensions();
let block_width = block_width as BufferAddress;
let block_height = block_height as BufferAddress;

View File

@ -3,7 +3,9 @@ use crate::device::trace;
use crate::{
binding_model::{self, BindGroupLayout},
command, conv,
device::{life::WaitIdleError, map_buffer, queue, Device, DeviceError, HostMap},
device::{
life::WaitIdleError, map_buffer, queue, Device, DeviceError, DeviceLostClosure, HostMap,
},
global::Global,
hal_api::HalApi,
hub::Token,
@ -494,7 +496,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
log::trace!("Buffer::destroy {buffer_id:?}");
let (mut buffer_guard, _) = hub.buffers.write(&mut token);
let buffer = buffer_guard
.get_mut(buffer_id)
.get_and_mark_destroyed(buffer_id)
.map_err(|_| resource::DestroyError::Invalid)?;
let device = &mut device_guard[buffer.device_id.value];
@ -549,7 +551,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let (ref_count, last_submit_index, device_id) = {
let (mut buffer_guard, _) = hub.buffers.write(&mut token);
match buffer_guard.get_mut(buffer_id) {
match buffer_guard.get_occupied_or_destroyed_mut(buffer_id) {
Ok(buffer) => {
let ref_count = buffer.life_guard.ref_count.take().unwrap();
let last_submit_index = buffer.life_guard.life_count();
@ -799,7 +801,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let (mut texture_guard, _) = hub.textures.write(&mut token);
let texture = texture_guard
.get_mut(texture_id)
.get_and_mark_destroyed(texture_id)
.map_err(|_| resource::DestroyError::Invalid)?;
let device = &mut device_guard[texture.device_id.value];
@ -853,7 +855,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let (ref_count, last_submit_index, device_id) = {
let (mut texture_guard, _) = hub.textures.write(&mut token);
match texture_guard.get_mut(texture_id) {
match texture_guard.get_occupied_or_destroyed_mut(texture_id) {
Ok(texture) => {
let ref_count = texture.life_guard.ref_count.take().unwrap();
let last_submit_index = texture.life_guard.life_count();
@ -2672,6 +2674,21 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
}
}
pub fn device_set_device_lost_closure<A: HalApi>(
&self,
device_id: DeviceId,
device_lost_closure: DeviceLostClosure,
) {
let hub = A::hub(self);
let mut token = Token::root();
let (mut device_guard, mut token) = hub.devices.write(&mut token);
if let Ok(device) = device_guard.get_mut(device_id) {
let mut life_tracker = device.lock_life(&mut token);
life_tracker.device_lost_closure = Some(device_lost_closure);
}
}
pub fn device_destroy<A: HalApi>(&self, device_id: DeviceId) {
log::trace!("Device::destroy {device_id:?}");
@ -2683,36 +2700,26 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
// Follow the steps at
// https://gpuweb.github.io/gpuweb/#dom-gpudevice-destroy.
// It's legal to call destroy multiple times, but if the device
// is already invalid, there's nothing more to do. There's also
// no need to return an error.
if !device.valid {
return;
}
// The last part of destroy is to lose the device. The spec says
// delay that until all "currently-enqueued operations on any
// queue on this device are completed."
// TODO: implement this delay.
// Finish by losing the device.
// TODO: associate this "destroyed" reason more tightly with
// the GPUDeviceLostReason defined in webgpu.idl.
device.lose(Some("destroyed"));
// queue on this device are completed." This is accomplished by
// setting valid to false, and then relying upon maintain to
// check for empty queues and a DeviceLostClosure. At that time,
// the DeviceLostClosure will be called with "destroyed" as the
// reason.
device.valid = false;
}
}
pub fn device_lose<A: HalApi>(&self, device_id: DeviceId, reason: Option<&str>) {
log::trace!("Device::lose {device_id:?}");
pub fn device_mark_lost<A: HalApi>(&self, device_id: DeviceId, message: &str) {
log::trace!("Device::mark_lost {device_id:?}");
let hub = A::hub(self);
let mut token = Token::root();
let (mut device_guard, _) = hub.devices.write(&mut token);
let (mut device_guard, mut token) = hub.devices.write(&mut token);
if let Ok(device) = device_guard.get_mut(device_id) {
device.lose(reason);
device.lose(&mut token, message);
}
}

View File

@ -3,7 +3,7 @@ use crate::device::trace;
use crate::{
device::{
queue::{EncoderInFlight, SubmittedWorkDoneClosure, TempResource},
DeviceError,
DeviceError, DeviceLostClosure,
},
hal_api::HalApi,
hub::{Hub, Token},
@ -313,6 +313,11 @@ pub(super) struct LifetimeTracker<A: hal::Api> {
/// must happen _after_ all mapped buffer callbacks are mapped, so we defer them
/// here until the next time the device is maintained.
work_done_closures: SmallVec<[SubmittedWorkDoneClosure; 1]>,
/// Closure to be called on "lose the device". This is invoked directly by
/// device.lose or by the UserCallbacks returned from maintain when the device
/// has been destroyed and its queues are empty.
pub device_lost_closure: Option<DeviceLostClosure>,
}
impl<A: hal::Api> LifetimeTracker<A> {
@ -326,6 +331,7 @@ impl<A: hal::Api> LifetimeTracker<A> {
free_resources: NonReferencedResources::new(),
ready_to_map: Vec::new(),
work_done_closures: SmallVec::new(),
device_lost_closure: None,
}
}
@ -834,21 +840,22 @@ impl<A: HalApi> LifetimeTracker<A> {
for stored in self.mapped.drain(..) {
let resource_id = stored.value;
let buf = &buffer_guard[resource_id];
// The buffer may have been destroyed since the map request.
if let Ok(buf) = buffer_guard.get(resource_id.0) {
let submit_index = buf.life_guard.life_count();
log::trace!(
"Mapping of {:?} at submission {:?} gets assigned to active {:?}",
resource_id,
submit_index,
self.active.iter().position(|a| a.index == submit_index)
);
let submit_index = buf.life_guard.life_count();
log::trace!(
"Mapping of {:?} at submission {:?} gets assigned to active {:?}",
resource_id,
submit_index,
self.active.iter().position(|a| a.index == submit_index)
);
self.active
.iter_mut()
.find(|a| a.index == submit_index)
.map_or(&mut self.ready_to_map, |a| &mut a.mapped)
.push(resource_id);
self.active
.iter_mut()
.find(|a| a.index == submit_index)
.map_or(&mut self.ready_to_map, |a| &mut a.mapped)
.push(resource_id);
}
}
}
@ -873,7 +880,13 @@ impl<A: HalApi> LifetimeTracker<A> {
Vec::with_capacity(self.ready_to_map.len());
let mut trackers = trackers.lock();
for buffer_id in self.ready_to_map.drain(..) {
let buffer = &mut buffer_guard[buffer_id];
let buffer = match buffer_guard.get_occupied_or_destroyed_mut(buffer_id.0) {
Ok(buf) => buf,
Err(..) => {
// The buffer may have been destroyed since the map request.
continue;
}
};
if buffer.life_guard.ref_count.is_none() && trackers.buffers.remove_abandoned(buffer_id)
{
buffer.map_state = resource::BufferMapState::Idle;

View File

@ -12,8 +12,9 @@ use crate::{
use arrayvec::ArrayVec;
use hal::Device as _;
use smallvec::SmallVec;
use std::os::raw::c_char;
use thiserror::Error;
use wgt::{BufferAddress, TextureFormat};
use wgt::{BufferAddress, DeviceLostReason, TextureFormat};
use std::{iter, num::NonZeroU32, ptr};
@ -169,12 +170,15 @@ pub type BufferMapPendingClosure = (BufferMapOperation, BufferAccessResult);
pub struct UserClosures {
pub mappings: Vec<BufferMapPendingClosure>,
pub submissions: SmallVec<[queue::SubmittedWorkDoneClosure; 1]>,
pub device_lost_invocations: SmallVec<[DeviceLostInvocation; 1]>,
}
impl UserClosures {
fn extend(&mut self, other: Self) {
self.mappings.extend(other.mappings);
self.submissions.extend(other.submissions);
self.device_lost_invocations
.extend(other.device_lost_invocations);
}
fn fire(self) {
@ -189,6 +193,98 @@ impl UserClosures {
for closure in self.submissions {
closure.call();
}
for invocation in self.device_lost_invocations {
invocation
.closure
.call(invocation.reason, invocation.message);
}
}
}
#[cfg(any(
not(target_arch = "wasm32"),
all(
feature = "fragile-send-sync-non-atomic-wasm",
not(target_feature = "atomics")
)
))]
pub type DeviceLostCallback = Box<dyn FnOnce(DeviceLostReason, String) + Send + 'static>;
#[cfg(not(any(
not(target_arch = "wasm32"),
all(
feature = "fragile-send-sync-non-atomic-wasm",
not(target_feature = "atomics")
)
)))]
pub type DeviceLostCallback = Box<dyn FnOnce(DeviceLostReason, String) + 'static>;
#[repr(C)]
pub struct DeviceLostClosureC {
pub callback: unsafe extern "C" fn(user_data: *mut u8, reason: u8, message: *const c_char),
pub user_data: *mut u8,
}
#[cfg(any(
not(target_arch = "wasm32"),
all(
feature = "fragile-send-sync-non-atomic-wasm",
not(target_feature = "atomics")
)
))]
unsafe impl Send for DeviceLostClosureC {}
pub struct DeviceLostClosure {
// We wrap this so creating the enum in the C variant can be unsafe,
// allowing our call function to be safe.
inner: DeviceLostClosureInner,
}
pub struct DeviceLostInvocation {
closure: DeviceLostClosure,
reason: DeviceLostReason,
message: String,
}
enum DeviceLostClosureInner {
Rust { callback: DeviceLostCallback },
C { inner: DeviceLostClosureC },
}
impl DeviceLostClosure {
pub fn from_rust(callback: DeviceLostCallback) -> Self {
Self {
inner: DeviceLostClosureInner::Rust { callback },
}
}
/// # Safety
///
/// - The callback pointer must be valid to call with the provided `user_data`
/// pointer.
///
/// - Both pointers must point to `'static` data, as the callback may happen at
/// an unspecified time.
pub unsafe fn from_c(inner: DeviceLostClosureC) -> Self {
Self {
inner: DeviceLostClosureInner::C { inner },
}
}
#[allow(trivial_casts)]
pub(crate) fn call(self, reason: DeviceLostReason, message: String) {
match self.inner {
DeviceLostClosureInner::Rust { callback } => callback(reason, message),
// SAFETY: the contract of the call to from_c says that this unsafe is sound.
DeviceLostClosureInner::C { inner } => unsafe {
// We need to pass message as a c_char typed pointer. To avoid trivial
// conversion warnings on some platforms, we use the allow lint.
(inner.callback)(
inner.user_data,
reason as u8,
message.as_ptr() as *const c_char,
)
},
}
}
}

View File

@ -697,7 +697,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let block_size = dst
.desc
.format
.block_size(Some(destination.aspect))
.block_copy_size(Some(destination.aspect))
.unwrap();
let bytes_per_row_alignment =
get_lowest_common_denom(device.alignments.buffer_copy_pitch.get() as u32, block_size);
@ -1110,13 +1110,12 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
// it, so make sure to set_size on it.
used_surface_textures.set_size(texture_guard.len());
// TODO: ideally we would use `get_and_mark_destroyed` but the code here
// wants to consume the command buffer.
#[allow(unused_mut)]
let mut cmdbuf = match hub
.command_buffers
.unregister_locked(cmb_id, &mut *command_buffer_guard)
{
Some(cmdbuf) => cmdbuf,
None => continue,
let mut cmdbuf = match command_buffer_guard.replace_with_error(cmb_id) {
Ok(cmdbuf) => cmdbuf,
Err(_) => continue,
};
if cmdbuf.device_id.value.0 != queue_id {
@ -1140,13 +1139,16 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
// update submission IDs
for id in cmdbuf.trackers.buffers.used() {
let buffer = &mut buffer_guard[id];
let raw_buf = match buffer.raw {
Some(ref raw) => raw,
None => {
let buffer = match buffer_guard.get(id.0) {
Ok(buf) => buf,
Err(..) => {
return Err(QueueSubmitError::DestroyedBuffer(id.0));
}
};
// get fails if the buffer is invalid or destroyed so we can assume
// the raw buffer is not None.
let raw_buf = buffer.raw.as_ref().unwrap();
if !buffer.life_guard.use_at(submit_index) {
if let BufferMapState::Active { .. } = buffer.map_state {
log::warn!("Dropped buffer has a pending mapping.");
@ -1162,10 +1164,16 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
}
}
for id in cmdbuf.trackers.textures.used() {
let texture = &mut texture_guard[id];
let texture = match texture_guard.get_mut(id.0) {
Ok(tex) => tex,
Err(..) => {
return Err(QueueSubmitError::DestroyedTexture(id.0));
}
};
let should_extend = match texture.inner {
TextureInner::Native { raw: None } => {
return Err(QueueSubmitError::DestroyedTexture(id.0));
unreachable!();
}
TextureInner::Native { raw: Some(_) } => false,
TextureInner::Surface {

View File

@ -8,8 +8,8 @@ use crate::{
command, conv,
device::life::WaitIdleError,
device::{
AttachmentData, CommandAllocator, MissingDownlevelFlags, MissingFeatures,
RenderPassContext, CLEANUP_WAIT_MS,
AttachmentData, CommandAllocator, DeviceLostInvocation, MissingDownlevelFlags,
MissingFeatures, RenderPassContext, CLEANUP_WAIT_MS,
},
hal_api::HalApi,
hal_label,
@ -34,7 +34,7 @@ use hal::{CommandEncoder as _, Device as _};
use parking_lot::{Mutex, MutexGuard};
use smallvec::SmallVec;
use thiserror::Error;
use wgt::{TextureFormat, TextureSampleType, TextureViewDimension};
use wgt::{DeviceLostReason, TextureFormat, TextureSampleType, TextureViewDimension};
use std::{borrow::Cow, iter, num::NonZeroU32};
@ -315,9 +315,24 @@ impl<A: HalApi> Device<A> {
let mapping_closures = life_tracker.handle_mapping(hub, &self.raw, &self.trackers, token);
life_tracker.cleanup(&self.raw);
// Detect if we have been destroyed and now need to lose the device.
// If we are invalid (set at start of destroy) and our queue is empty,
// and we have a DeviceLostClosure, return the closure to be called by
// our caller. This will complete the steps for both destroy and for
// "lose the device".
let mut device_lost_invocations = SmallVec::new();
if !self.valid && life_tracker.queue_empty() && life_tracker.device_lost_closure.is_some() {
device_lost_invocations.push(DeviceLostInvocation {
closure: life_tracker.device_lost_closure.take().unwrap(),
reason: DeviceLostReason::Destroyed,
message: String::new(),
});
}
let closures = UserClosures {
mappings: mapping_closures,
submissions: submission_closures,
device_lost_invocations,
};
Ok((closures, life_tracker.queue_empty()))
}
@ -342,42 +357,90 @@ impl<A: HalApi> Device<A> {
let (sampler_guard, _) = hub.samplers.read(&mut token);
for id in trackers.buffers.used() {
if buffer_guard[id].life_guard.ref_count.is_none() {
if buffer_guard
.get_occupied_or_destroyed(id.0)
.unwrap()
.life_guard
.ref_count
.is_none()
{
self.temp_suspected.buffers.push(id);
}
}
for id in trackers.textures.used() {
if texture_guard[id].life_guard.ref_count.is_none() {
if texture_guard
.get_occupied_or_destroyed(id.0)
.unwrap()
.life_guard
.ref_count
.is_none()
{
self.temp_suspected.textures.push(id);
}
}
for id in trackers.views.used() {
if texture_view_guard[id].life_guard.ref_count.is_none() {
if texture_view_guard
.get_occupied_or_destroyed(id.0)
.unwrap()
.life_guard
.ref_count
.is_none()
{
self.temp_suspected.texture_views.push(id);
}
}
for id in trackers.bind_groups.used() {
if bind_group_guard[id].life_guard.ref_count.is_none() {
if bind_group_guard
.get_occupied_or_destroyed(id.0)
.unwrap()
.life_guard
.ref_count
.is_none()
{
self.temp_suspected.bind_groups.push(id);
}
}
for id in trackers.samplers.used() {
if sampler_guard[id].life_guard.ref_count.is_none() {
if sampler_guard
.get_occupied_or_destroyed(id.0)
.unwrap()
.life_guard
.ref_count
.is_none()
{
self.temp_suspected.samplers.push(id);
}
}
for id in trackers.compute_pipelines.used() {
if compute_pipe_guard[id].life_guard.ref_count.is_none() {
if compute_pipe_guard
.get_occupied_or_destroyed(id.0)
.unwrap()
.life_guard
.ref_count
.is_none()
{
self.temp_suspected.compute_pipelines.push(id);
}
}
for id in trackers.render_pipelines.used() {
if render_pipe_guard[id].life_guard.ref_count.is_none() {
if render_pipe_guard
.get_occupied_or_destroyed(id.0)
.unwrap()
.life_guard
.ref_count
.is_none()
{
self.temp_suspected.render_pipelines.push(id);
}
}
for id in trackers.query_sets.used() {
if query_set_guard[id].life_guard.ref_count.is_none() {
if query_set_guard
.get_occupied_or_destroyed(id.0)
.unwrap()
.life_guard
.ref_count
.is_none()
{
self.temp_suspected.query_sets.push(id);
}
}
@ -3304,17 +3367,23 @@ impl<A: HalApi> Device<A> {
})
}
pub(crate) fn lose(&mut self, _reason: Option<&str>) {
pub(crate) fn lose<'this, 'token: 'this>(
&'this mut self,
token: &mut Token<'token, Self>,
message: &str,
) {
// Follow the steps at https://gpuweb.github.io/gpuweb/#lose-the-device.
// Mark the device explicitly as invalid. This is checked in various
// places to prevent new work from being submitted.
self.valid = false;
// The following steps remain in "lose the device":
// 1) Resolve the GPUDevice device.lost promise.
// TODO: triggger this passively or actively, and supply the reason.
let mut life_tracker = self.lock_life(token);
if life_tracker.device_lost_closure.is_some() {
let device_lost_closure = life_tracker.device_lost_closure.take().unwrap();
device_lost_closure.call(DeviceLostReason::Unknown, message.to_string());
}
// 2) Complete any outstanding mapAsync() steps.
// 3) Complete any outstanding onSubmittedWorkDone() steps.

View File

@ -14,6 +14,10 @@ pub(crate) enum Element<T> {
/// epoch.
Occupied(T, Epoch),
/// Like `Occupied`, but the resource has been marked as destroyed
/// and hasn't been dropped yet.
Destroyed(T, Epoch),
/// Like `Occupied`, but an error occurred when creating the
/// resource.
///
@ -68,9 +72,11 @@ impl<T, I: id::TypedId> Storage<T, I> {
let (index, epoch, _) = id.unzip();
match self.map.get(index as usize) {
Some(&Element::Vacant) => false,
Some(&Element::Occupied(_, storage_epoch) | &Element::Error(storage_epoch, _)) => {
storage_epoch == epoch
}
Some(
&Element::Occupied(_, storage_epoch)
| &Element::Destroyed(_, storage_epoch)
| &Element::Error(storage_epoch, _),
) => storage_epoch == epoch,
None => false,
}
}
@ -87,7 +93,9 @@ impl<T, I: id::TypedId> Storage<T, I> {
let (result, storage_epoch) = match self.map.get(index as usize) {
Some(&Element::Occupied(ref v, epoch)) => (Ok(Some(v)), epoch),
Some(&Element::Vacant) => return Ok(None),
Some(&Element::Error(epoch, ..)) => (Err(InvalidId), epoch),
Some(&Element::Error(epoch, ..)) | Some(&Element::Destroyed(.., epoch)) => {
(Err(InvalidId), epoch)
}
None => return Err(InvalidId),
};
assert_eq!(
@ -106,6 +114,7 @@ impl<T, I: id::TypedId> Storage<T, I> {
Some(&Element::Occupied(ref v, epoch)) => (Ok(v), epoch),
Some(&Element::Vacant) => panic!("{}[{}] does not exist", self.kind, index),
Some(&Element::Error(epoch, ..)) => (Err(InvalidId), epoch),
Some(&Element::Destroyed(.., epoch)) => (Err(InvalidId), epoch),
None => return Err(InvalidId),
};
assert_eq!(
@ -124,6 +133,46 @@ impl<T, I: id::TypedId> Storage<T, I> {
Some(&mut Element::Occupied(ref mut v, epoch)) => (Ok(v), epoch),
Some(&mut Element::Vacant) | None => panic!("{}[{}] does not exist", self.kind, index),
Some(&mut Element::Error(epoch, ..)) => (Err(InvalidId), epoch),
Some(&mut Element::Destroyed(.., epoch)) => (Err(InvalidId), epoch),
};
assert_eq!(
epoch, storage_epoch,
"{}[{}] is no longer alive",
self.kind, index
);
result
}
/// Like `get_mut`, but returns the element even if it is destroyed.
///
/// In practice, most API entry points should use `get`/`get_mut` so that a
/// destroyed resource leads to a validation error. This should be used internally
/// in places where we want to do some manipulation potentially after the element
/// was destroyed (for example the drop implementation).
pub(crate) fn get_occupied_or_destroyed_mut(&mut self, id: I) -> Result<&mut T, InvalidId> {
let (index, epoch, _) = id.unzip();
let (result, storage_epoch) = match self.map.get_mut(index as usize) {
Some(&mut Element::Occupied(ref mut v, epoch))
| Some(&mut Element::Destroyed(ref mut v, epoch)) => (Ok(v), epoch),
Some(&mut Element::Vacant) | None => panic!("{}[{}] does not exist", self.kind, index),
Some(&mut Element::Error(epoch, ..)) => (Err(InvalidId), epoch),
};
assert_eq!(
epoch, storage_epoch,
"{}[{}] is no longer alive",
self.kind, index
);
result
}
pub(crate) fn get_occupied_or_destroyed(&self, id: I) -> Result<&T, InvalidId> {
let (index, epoch, _) = id.unzip();
let (result, storage_epoch) = match self.map.get(index as usize) {
Some(&Element::Occupied(ref v, epoch)) | Some(&Element::Destroyed(ref v, epoch)) => {
(Ok(v), epoch)
}
Some(&Element::Vacant) | None => panic!("{}[{}] does not exist", self.kind, index),
Some(&Element::Error(epoch, ..)) => (Err(InvalidId), epoch),
};
assert_eq!(
epoch, storage_epoch,
@ -137,7 +186,7 @@ impl<T, I: id::TypedId> Storage<T, I> {
match self.map[id as usize] {
Element::Occupied(ref v, _) => v,
Element::Vacant => panic!("{}[{}] does not exist", self.kind, id),
Element::Error(_, _) => panic!(""),
Element::Error(_, _) | Element::Destroyed(..) => panic!(""),
}
}
@ -169,6 +218,42 @@ impl<T, I: id::TypedId> Storage<T, I> {
self.insert_impl(index as usize, Element::Error(epoch, label.to_string()))
}
pub(crate) fn replace_with_error(&mut self, id: I) -> Result<T, InvalidId> {
let (index, epoch, _) = id.unzip();
match std::mem::replace(
&mut self.map[index as usize],
Element::Error(epoch, String::new()),
) {
Element::Vacant => panic!("Cannot access vacant resource"),
Element::Occupied(value, storage_epoch) => {
assert_eq!(epoch, storage_epoch);
Ok(value)
}
_ => Err(InvalidId),
}
}
pub(crate) fn get_and_mark_destroyed(&mut self, id: I) -> Result<&mut T, InvalidId> {
let (index, epoch, _) = id.unzip();
let slot = &mut self.map[index as usize];
// borrowck dance: we have to move the element out before we can replace it
// with another variant with the same value.
if let &mut Element::Occupied(..) = slot {
if let Element::Occupied(value, storage_epoch) =
std::mem::replace(slot, Element::Vacant)
{
debug_assert_eq!(storage_epoch, epoch);
*slot = Element::Destroyed(value, storage_epoch);
}
}
if let Element::Destroyed(ref mut value, ..) = *slot {
Ok(value)
} else {
Err(InvalidId)
}
}
pub(crate) fn force_replace(&mut self, id: I, value: T) {
let (index, epoch, _) = id.unzip();
self.map[index as usize] = Element::Occupied(value, epoch);
@ -177,7 +262,7 @@ impl<T, I: id::TypedId> Storage<T, I> {
pub(crate) fn remove(&mut self, id: I) -> Option<T> {
let (index, epoch, _) = id.unzip();
match std::mem::replace(&mut self.map[index as usize], Element::Vacant) {
Element::Occupied(value, storage_epoch) => {
Element::Occupied(value, storage_epoch) | Element::Destroyed(value, storage_epoch) => {
assert_eq!(epoch, storage_epoch);
Some(value)
}
@ -224,7 +309,7 @@ impl<T, I: id::TypedId> Storage<T, I> {
};
for element in self.map.iter() {
match *element {
Element::Occupied(..) => report.num_occupied += 1,
Element::Occupied(..) | Element::Destroyed(..) => report.num_occupied += 1,
Element::Vacant => report.num_vacant += 1,
Element::Error(..) => report.num_error += 1,
}

View File

@ -57,13 +57,18 @@ impl NumericDimension {
#[derive(Clone, Copy, Debug)]
pub struct NumericType {
dim: NumericDimension,
kind: naga::ScalarKind,
width: naga::Bytes,
scalar: naga::Scalar,
}
impl fmt::Display for NumericType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}{}{}", self.kind, self.width * 8, self.dim)
write!(
f,
"{:?}{}{}",
self.scalar.kind,
self.scalar.width * 8,
self.dim
)
}
}
@ -592,77 +597,76 @@ impl Resource {
impl NumericType {
fn from_vertex_format(format: wgt::VertexFormat) -> Self {
use naga::{ScalarKind as Sk, VectorSize as Vs};
use naga::{Scalar, VectorSize as Vs};
use wgt::VertexFormat as Vf;
let (dim, kind, width) = match format {
Vf::Uint32 => (NumericDimension::Scalar, Sk::Uint, 4),
let (dim, scalar) = match format {
Vf::Uint32 => (NumericDimension::Scalar, Scalar::U32),
Vf::Uint8x2 | Vf::Uint16x2 | Vf::Uint32x2 => {
(NumericDimension::Vector(Vs::Bi), Sk::Uint, 4)
(NumericDimension::Vector(Vs::Bi), Scalar::U32)
}
Vf::Uint32x3 => (NumericDimension::Vector(Vs::Tri), Sk::Uint, 4),
Vf::Uint32x3 => (NumericDimension::Vector(Vs::Tri), Scalar::U32),
Vf::Uint8x4 | Vf::Uint16x4 | Vf::Uint32x4 => {
(NumericDimension::Vector(Vs::Quad), Sk::Uint, 4)
(NumericDimension::Vector(Vs::Quad), Scalar::U32)
}
Vf::Sint32 => (NumericDimension::Scalar, Sk::Sint, 4),
Vf::Sint32 => (NumericDimension::Scalar, Scalar::I32),
Vf::Sint8x2 | Vf::Sint16x2 | Vf::Sint32x2 => {
(NumericDimension::Vector(Vs::Bi), Sk::Sint, 4)
(NumericDimension::Vector(Vs::Bi), Scalar::I32)
}
Vf::Sint32x3 => (NumericDimension::Vector(Vs::Tri), Sk::Sint, 4),
Vf::Sint32x3 => (NumericDimension::Vector(Vs::Tri), Scalar::I32),
Vf::Sint8x4 | Vf::Sint16x4 | Vf::Sint32x4 => {
(NumericDimension::Vector(Vs::Quad), Sk::Sint, 4)
(NumericDimension::Vector(Vs::Quad), Scalar::I32)
}
Vf::Float32 => (NumericDimension::Scalar, Sk::Float, 4),
Vf::Float32 => (NumericDimension::Scalar, Scalar::F32),
Vf::Unorm8x2
| Vf::Snorm8x2
| Vf::Unorm16x2
| Vf::Snorm16x2
| Vf::Float16x2
| Vf::Float32x2 => (NumericDimension::Vector(Vs::Bi), Sk::Float, 4),
Vf::Float32x3 => (NumericDimension::Vector(Vs::Tri), Sk::Float, 4),
| Vf::Float32x2 => (NumericDimension::Vector(Vs::Bi), Scalar::F32),
Vf::Float32x3 => (NumericDimension::Vector(Vs::Tri), Scalar::F32),
Vf::Unorm8x4
| Vf::Snorm8x4
| Vf::Unorm16x4
| Vf::Snorm16x4
| Vf::Float16x4
| Vf::Float32x4 => (NumericDimension::Vector(Vs::Quad), Sk::Float, 4),
Vf::Float64 => (NumericDimension::Scalar, Sk::Float, 8),
Vf::Float64x2 => (NumericDimension::Vector(Vs::Bi), Sk::Float, 8),
Vf::Float64x3 => (NumericDimension::Vector(Vs::Tri), Sk::Float, 8),
Vf::Float64x4 => (NumericDimension::Vector(Vs::Quad), Sk::Float, 8),
| Vf::Float32x4 => (NumericDimension::Vector(Vs::Quad), Scalar::F32),
Vf::Float64 => (NumericDimension::Scalar, Scalar::F64),
Vf::Float64x2 => (NumericDimension::Vector(Vs::Bi), Scalar::F64),
Vf::Float64x3 => (NumericDimension::Vector(Vs::Tri), Scalar::F64),
Vf::Float64x4 => (NumericDimension::Vector(Vs::Quad), Scalar::F64),
};
NumericType {
dim,
kind,
//Note: Shader always sees data as int, uint, or float.
// It doesn't know if the original is normalized in a tighter form.
width,
scalar,
}
}
fn from_texture_format(format: wgt::TextureFormat) -> Self {
use naga::{ScalarKind as Sk, VectorSize as Vs};
use naga::{Scalar, VectorSize as Vs};
use wgt::TextureFormat as Tf;
let (dim, kind) = match format {
let (dim, scalar) = match format {
Tf::R8Unorm | Tf::R8Snorm | Tf::R16Float | Tf::R32Float => {
(NumericDimension::Scalar, Sk::Float)
(NumericDimension::Scalar, Scalar::F32)
}
Tf::R8Uint | Tf::R16Uint | Tf::R32Uint => (NumericDimension::Scalar, Sk::Uint),
Tf::R8Sint | Tf::R16Sint | Tf::R32Sint => (NumericDimension::Scalar, Sk::Sint),
Tf::R8Uint | Tf::R16Uint | Tf::R32Uint => (NumericDimension::Scalar, Scalar::U32),
Tf::R8Sint | Tf::R16Sint | Tf::R32Sint => (NumericDimension::Scalar, Scalar::I32),
Tf::Rg8Unorm | Tf::Rg8Snorm | Tf::Rg16Float | Tf::Rg32Float => {
(NumericDimension::Vector(Vs::Bi), Sk::Float)
(NumericDimension::Vector(Vs::Bi), Scalar::F32)
}
Tf::Rg8Uint | Tf::Rg16Uint | Tf::Rg32Uint => {
(NumericDimension::Vector(Vs::Bi), Sk::Uint)
(NumericDimension::Vector(Vs::Bi), Scalar::U32)
}
Tf::Rg8Sint | Tf::Rg16Sint | Tf::Rg32Sint => {
(NumericDimension::Vector(Vs::Bi), Sk::Sint)
(NumericDimension::Vector(Vs::Bi), Scalar::I32)
}
Tf::R16Snorm | Tf::R16Unorm => (NumericDimension::Scalar, Sk::Float),
Tf::Rg16Snorm | Tf::Rg16Unorm => (NumericDimension::Vector(Vs::Bi), Sk::Float),
Tf::Rgba16Snorm | Tf::Rgba16Unorm => (NumericDimension::Vector(Vs::Quad), Sk::Float),
Tf::R16Snorm | Tf::R16Unorm => (NumericDimension::Scalar, Scalar::F32),
Tf::Rg16Snorm | Tf::Rg16Unorm => (NumericDimension::Vector(Vs::Bi), Scalar::F32),
Tf::Rgba16Snorm | Tf::Rgba16Unorm => (NumericDimension::Vector(Vs::Quad), Scalar::F32),
Tf::Rgba8Unorm
| Tf::Rgba8UnormSrgb
| Tf::Rgba8Snorm
@ -670,14 +674,14 @@ impl NumericType {
| Tf::Bgra8UnormSrgb
| Tf::Rgb10a2Unorm
| Tf::Rgba16Float
| Tf::Rgba32Float => (NumericDimension::Vector(Vs::Quad), Sk::Float),
| Tf::Rgba32Float => (NumericDimension::Vector(Vs::Quad), Scalar::F32),
Tf::Rgba8Uint | Tf::Rgba16Uint | Tf::Rgba32Uint | Tf::Rgb10a2Uint => {
(NumericDimension::Vector(Vs::Quad), Sk::Uint)
(NumericDimension::Vector(Vs::Quad), Scalar::U32)
}
Tf::Rgba8Sint | Tf::Rgba16Sint | Tf::Rgba32Sint => {
(NumericDimension::Vector(Vs::Quad), Sk::Sint)
(NumericDimension::Vector(Vs::Quad), Scalar::I32)
}
Tf::Rg11b10Float => (NumericDimension::Vector(Vs::Tri), Sk::Float),
Tf::Rg11b10Float => (NumericDimension::Vector(Vs::Tri), Scalar::F32),
Tf::Stencil8
| Tf::Depth16Unorm
| Tf::Depth32Float
@ -686,7 +690,7 @@ impl NumericType {
| Tf::Depth24PlusStencil8 => {
panic!("Unexpected depth format")
}
Tf::Rgb9e5Ufloat => (NumericDimension::Vector(Vs::Tri), Sk::Float),
Tf::Rgb9e5Ufloat => (NumericDimension::Vector(Vs::Tri), Scalar::F32),
Tf::Bc1RgbaUnorm
| Tf::Bc1RgbaUnormSrgb
| Tf::Bc2RgbaUnorm
@ -698,36 +702,35 @@ impl NumericType {
| Tf::Etc2Rgb8A1Unorm
| Tf::Etc2Rgb8A1UnormSrgb
| Tf::Etc2Rgba8Unorm
| Tf::Etc2Rgba8UnormSrgb => (NumericDimension::Vector(Vs::Quad), Sk::Float),
| Tf::Etc2Rgba8UnormSrgb => (NumericDimension::Vector(Vs::Quad), Scalar::F32),
Tf::Bc4RUnorm | Tf::Bc4RSnorm | Tf::EacR11Unorm | Tf::EacR11Snorm => {
(NumericDimension::Scalar, Sk::Float)
(NumericDimension::Scalar, Scalar::F32)
}
Tf::Bc5RgUnorm | Tf::Bc5RgSnorm | Tf::EacRg11Unorm | Tf::EacRg11Snorm => {
(NumericDimension::Vector(Vs::Bi), Sk::Float)
(NumericDimension::Vector(Vs::Bi), Scalar::F32)
}
Tf::Bc6hRgbUfloat | Tf::Bc6hRgbFloat | Tf::Etc2Rgb8Unorm | Tf::Etc2Rgb8UnormSrgb => {
(NumericDimension::Vector(Vs::Tri), Sk::Float)
(NumericDimension::Vector(Vs::Tri), Scalar::F32)
}
Tf::Astc {
block: _,
channel: _,
} => (NumericDimension::Vector(Vs::Quad), Sk::Float),
} => (NumericDimension::Vector(Vs::Quad), Scalar::F32),
};
NumericType {
dim,
kind,
//Note: Shader always sees data as int, uint, or float.
// It doesn't know if the original is normalized in a tighter form.
width: 4,
scalar,
}
}
fn is_subtype_of(&self, other: &NumericType) -> bool {
if self.width > other.width {
if self.scalar.width > other.scalar.width {
return false;
}
if self.kind != other.kind {
if self.scalar.kind != other.scalar.kind {
return false;
}
match (self.dim, other.dim) {
@ -742,7 +745,7 @@ impl NumericType {
}
fn is_compatible_with(&self, other: &NumericType) -> bool {
if self.kind != other.kind {
if self.scalar.kind != other.scalar.kind {
return false;
}
match (self.dim, other.dim) {
@ -778,15 +781,13 @@ impl Interface {
arena: &naga::UniqueArena<naga::Type>,
) {
let numeric_ty = match arena[ty].inner {
naga::TypeInner::Scalar { kind, width } => NumericType {
naga::TypeInner::Scalar(scalar) => NumericType {
dim: NumericDimension::Scalar,
kind,
width,
scalar,
},
naga::TypeInner::Vector { size, kind, width } => NumericType {
naga::TypeInner::Vector { size, scalar } => NumericType {
dim: NumericDimension::Vector(size),
kind,
width,
scalar,
},
naga::TypeInner::Matrix {
columns,
@ -794,8 +795,7 @@ impl Interface {
width,
} => NumericType {
dim: NumericDimension::Matrix(columns, rows),
kind: naga::ScalarKind::Float,
width,
scalar: naga::Scalar::float(width),
},
naga::TypeInner::Struct { ref members, .. } => {
for member in members {

File diff suppressed because one or more lines are too long

View File

@ -39,7 +39,7 @@ impl crate::BufferTextureCopy {
let actual = self.buffer_layout.bytes_per_row.unwrap_or_else(|| {
// this may happen for single-line updates
let block_size = format
.block_size(Some(self.texture_base.aspect.map()))
.block_copy_size(Some(self.texture_base.aspect.map()))
.unwrap();
(self.size.width / block_width) * block_size
});

View File

@ -564,7 +564,7 @@ impl super::Queue {
ref copy,
} => {
let (block_width, block_height) = dst_format.block_dimensions();
let block_size = dst_format.block_size(None).unwrap();
let block_size = dst_format.block_copy_size(None).unwrap();
let format_desc = self.shared.describe_texture_format(dst_format);
let row_texels = copy
.buffer_layout
@ -702,7 +702,7 @@ impl super::Queue {
dst_target: _,
ref copy,
} => {
let block_size = src_format.block_size(None).unwrap();
let block_size = src_format.block_copy_size(None).unwrap();
if src_format.is_compressed() {
log::error!("Not implemented yet: compressed texture copy to buffer");
return;
@ -1463,33 +1463,27 @@ impl super::Queue {
//
// --- Float 1-4 Component ---
//
naga::TypeInner::Scalar {
kind: naga::ScalarKind::Float,
width: 4,
} => {
naga::TypeInner::Scalar(naga::Scalar::F32) => {
let data = unsafe { get_data::<f32, 1>(data_bytes, offset)[0] };
unsafe { gl.uniform_1_f32(location, data) };
}
naga::TypeInner::Vector {
kind: naga::ScalarKind::Float,
size: naga::VectorSize::Bi,
width: 4,
scalar: naga::Scalar::F32,
} => {
let data = unsafe { get_data::<f32, 2>(data_bytes, offset) };
unsafe { gl.uniform_2_f32_slice(location, data) };
}
naga::TypeInner::Vector {
kind: naga::ScalarKind::Float,
size: naga::VectorSize::Tri,
width: 4,
scalar: naga::Scalar::F32,
} => {
let data = unsafe { get_data::<f32, 3>(data_bytes, offset) };
unsafe { gl.uniform_3_f32_slice(location, data) };
}
naga::TypeInner::Vector {
kind: naga::ScalarKind::Float,
size: naga::VectorSize::Quad,
width: 4,
scalar: naga::Scalar::F32,
} => {
let data = unsafe { get_data::<f32, 4>(data_bytes, offset) };
unsafe { gl.uniform_4_f32_slice(location, data) };
@ -1498,33 +1492,27 @@ impl super::Queue {
//
// --- Int 1-4 Component ---
//
naga::TypeInner::Scalar {
kind: naga::ScalarKind::Sint,
width: 4,
} => {
naga::TypeInner::Scalar(naga::Scalar::I32) => {
let data = unsafe { get_data::<i32, 1>(data_bytes, offset)[0] };
unsafe { gl.uniform_1_i32(location, data) };
}
naga::TypeInner::Vector {
kind: naga::ScalarKind::Sint,
size: naga::VectorSize::Bi,
width: 4,
scalar: naga::Scalar::I32,
} => {
let data = unsafe { get_data::<i32, 2>(data_bytes, offset) };
unsafe { gl.uniform_2_i32_slice(location, data) };
}
naga::TypeInner::Vector {
kind: naga::ScalarKind::Sint,
size: naga::VectorSize::Tri,
width: 4,
scalar: naga::Scalar::I32,
} => {
let data = unsafe { get_data::<i32, 3>(data_bytes, offset) };
unsafe { gl.uniform_3_i32_slice(location, data) };
}
naga::TypeInner::Vector {
kind: naga::ScalarKind::Sint,
size: naga::VectorSize::Quad,
width: 4,
scalar: naga::Scalar::I32,
} => {
let data = unsafe { get_data::<i32, 4>(data_bytes, offset) };
unsafe { gl.uniform_4_i32_slice(location, data) };
@ -1533,33 +1521,27 @@ impl super::Queue {
//
// --- Uint 1-4 Component ---
//
naga::TypeInner::Scalar {
kind: naga::ScalarKind::Uint,
width: 4,
} => {
naga::TypeInner::Scalar(naga::Scalar::U32) => {
let data = unsafe { get_data::<u32, 1>(data_bytes, offset)[0] };
unsafe { gl.uniform_1_u32(location, data) };
}
naga::TypeInner::Vector {
kind: naga::ScalarKind::Uint,
size: naga::VectorSize::Bi,
width: 4,
scalar: naga::Scalar::U32,
} => {
let data = unsafe { get_data::<u32, 2>(data_bytes, offset) };
unsafe { gl.uniform_2_u32_slice(location, data) };
}
naga::TypeInner::Vector {
kind: naga::ScalarKind::Uint,
size: naga::VectorSize::Tri,
width: 4,
scalar: naga::Scalar::U32,
} => {
let data = unsafe { get_data::<u32, 3>(data_bytes, offset) };
unsafe { gl.uniform_3_u32_slice(location, data) };
}
naga::TypeInner::Vector {
kind: naga::ScalarKind::Uint,
size: naga::VectorSize::Quad,
width: 4,
scalar: naga::Scalar::U32,
} => {
let data = unsafe { get_data::<u32, 4>(data_bytes, offset) };
unsafe { gl.uniform_4_u32_slice(location, data) };

View File

@ -23,7 +23,7 @@ impl super::Texture {
buffer_offset: r.buffer_layout.offset,
buffer_row_length: r.buffer_layout.bytes_per_row.map_or(0, |bpr| {
let block_size = format
.block_size(Some(r.texture_base.aspect.map()))
.block_copy_size(Some(r.texture_base.aspect.map()))
.unwrap();
block_width * (bpr / block_size)
}),

View File

@ -451,8 +451,7 @@ pub fn map_vk_present_mode(mode: vk::PresentModeKHR) -> Option<wgt::PresentMode>
} else if mode == vk::PresentModeKHR::FIFO {
Some(wgt::PresentMode::Fifo)
} else if mode == vk::PresentModeKHR::FIFO_RELAXED {
//Some(wgt::PresentMode::Relaxed)
None
Some(wgt::PresentMode::FifoRelaxed)
} else {
log::warn!("Unrecognized present mode {:?}", mode);
None

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"e45ee369c8f91526056ba7f46504e270da1d8b2de65431bbaf36426bcd54da68","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","src/assertions.rs":"3fe98027aa73970c8ab7874a3e13dbfd6faa87df2081beb5c83aeec4c60f372f","src/lib.rs":"82e95f3af2d4e7279e5ea31897fb51dd614e4c6cae9c23ddd2b8b5b6bb2ad35a","src/math.rs":"4d03039736dd6926feb139bc68734cb59df34ede310427bbf059e5c925e0af3b"},"package":null}
{"files":{"Cargo.toml":"e45ee369c8f91526056ba7f46504e270da1d8b2de65431bbaf36426bcd54da68","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","src/assertions.rs":"3fe98027aa73970c8ab7874a3e13dbfd6faa87df2081beb5c83aeec4c60f372f","src/lib.rs":"4e1ef56078799af2c15ca573a05b5deebbb084b447a5840cd61971afa4c73924","src/math.rs":"4d03039736dd6926feb139bc68734cb59df34ede310427bbf059e5c925e0af3b"},"package":null}

View File

@ -2813,7 +2813,9 @@ impl TextureFormat {
}
}
/// Returns the dimension of a block of texels.
/// Returns the dimension of a [block](https://gpuweb.github.io/gpuweb/#texel-block) of texels.
///
/// Uncompressed formats have a block dimension of `(1, 1)`.
pub fn block_dimensions(&self) -> (u32, u32) {
match *self {
Self::R8Unorm
@ -3225,14 +3227,34 @@ impl TextureFormat {
}
}
/// Returns the [texel block size](https://gpuweb.github.io/gpuweb/#texel-block-size)
/// of this format.
/// The number of bytes one [texel block](https://gpuweb.github.io/gpuweb/#texel-block) occupies during an image copy, if applicable.
///
/// Known as the [texel block copy footprint](https://gpuweb.github.io/gpuweb/#texel-block-copy-footprint).
///
/// Note that for uncompressed formats this is the same as the size of a single texel,
/// since uncompressed formats have a block size of 1x1.
///
/// Returns `None` if any of the following are true:
/// - the format is combined depth-stencil and no `aspect` was provided
/// - the format is `Depth24Plus`
/// - the format is `Depth24PlusStencil8` and `aspect` is depth.
#[deprecated(since = "0.19.0", note = "Use `block_copy_size` instead.")]
pub fn block_size(&self, aspect: Option<TextureAspect>) -> Option<u32> {
self.block_copy_size(aspect)
}
/// The number of bytes one [texel block](https://gpuweb.github.io/gpuweb/#texel-block) occupies during an image copy, if applicable.
///
/// Known as the [texel block copy footprint](https://gpuweb.github.io/gpuweb/#texel-block-copy-footprint).
///
/// Note that for uncompressed formats this is the same as the size of a single texel,
/// since uncompressed formats have a block size of 1x1.
///
/// Returns `None` if any of the following are true:
/// - the format is combined depth-stencil and no `aspect` was provided
/// - the format is `Depth24Plus`
/// - the format is `Depth24PlusStencil8` and `aspect` is depth.
pub fn block_copy_size(&self, aspect: Option<TextureAspect>) -> Option<u32> {
match *self {
Self::R8Unorm | Self::R8Snorm | Self::R8Uint | Self::R8Sint => Some(1),
@ -6707,3 +6729,15 @@ mod send_sync {
)))]
impl<T> WasmNotSync for T {}
}
/// Reason for "lose the device".
///
/// Corresponds to [WebGPU `GPUDeviceLostReason`](https://gpuweb.github.io/gpuweb/#enumdef-gpudevicelostreason).
#[repr(u8)]
#[derive(Debug, Copy, Clone)]
pub enum DeviceLostReason {
/// Triggered by driver
Unknown = 0,
/// After Device::destroy
Destroyed = 1,
}