[naga wgsl-in] Introduce Scalar type.

Introduce a new struct `Scalar`, holding a scalar kind and width, and
use it as appropriate in the WGSL front end. This consolidates
many (kind, width) pairs, and lets us name the two components.

Ideally, `Scalar` would be used throughout Naga, but this would be a large
change, touching hundreds of use sites. This patch begins by
introducing `Scalar` to the WGSL front end only.
This commit is contained in:
Jim Blandy
2023-11-05 15:18:55 -08:00
committed by Teodor Tanasoaia
parent 0dad15989f
commit 267bd488d3
8 changed files with 251 additions and 150 deletions

View File

@@ -1,4 +1,5 @@
use crate::front::wgsl::parse::lexer::Token;
use crate::front::wgsl::Scalar;
use crate::proc::{Alignment, ConstantEvaluatorError, ResolveError};
use crate::{SourceLocation, Span};
use codespan_reporting::diagnostic::{Diagnostic, Label};
@@ -139,7 +140,7 @@ pub enum Error<'a> {
UnexpectedComponents(Span),
UnexpectedOperationInConstContext(Span),
BadNumber(Span, NumberError),
BadMatrixScalarKind(Span, crate::ScalarKind, u8),
BadMatrixScalarKind(Span, Scalar),
BadAccessor(Span),
BadTexture(Span),
BadTypeCast {
@@ -149,8 +150,7 @@ pub enum Error<'a> {
},
BadTextureSampleType {
span: Span,
kind: crate::ScalarKind,
width: u8,
scalar: Scalar,
},
BadIncrDecrReferenceType(Span),
InvalidResolve(ResolveError),
@@ -304,10 +304,10 @@ impl<'a> Error<'a> {
labels: vec![(bad_span, err.to_string().into())],
notes: vec![],
},
Error::BadMatrixScalarKind(span, kind, width) => ParseError {
Error::BadMatrixScalarKind(span, scalar) => ParseError {
message: format!(
"matrix scalar type must be floating-point, but found `{}`",
kind.to_wgsl(width)
scalar.to_wgsl()
),
labels: vec![(span, "must be floating-point (e.g. `f32`)".into())],
notes: vec![],
@@ -327,10 +327,10 @@ impl<'a> Error<'a> {
labels: vec![(bad_span, "unknown scalar type".into())],
notes: vec!["Valid scalar types are f32, f64, i32, u32, bool".into()],
},
Error::BadTextureSampleType { span, kind, width } => ParseError {
Error::BadTextureSampleType { span, scalar } => ParseError {
message: format!(
"texture sample type must be one of f32, i32 or u32, but found {}",
kind.to_wgsl(width)
scalar.to_wgsl()
),
labels: vec![(span, "must be one of f32, i32 or u32".into())],
notes: vec![],

View File

@@ -516,13 +516,13 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
ctx: &mut ExpressionContext<'source, '_, 'out>,
) -> Result<Constructor<Handle<crate::Type>>, Error<'source>> {
let handle = match *constructor {
ast::ConstructorType::Scalar { width, kind } => {
let ty = ctx.ensure_type_exists(crate::TypeInner::Scalar { width, kind });
ast::ConstructorType::Scalar(scalar) => {
let ty = ctx.ensure_type_exists(scalar.to_inner_scalar());
Constructor::Type(ty)
}
ast::ConstructorType::PartialVector { size } => Constructor::PartialVector { size },
ast::ConstructorType::Vector { size, kind, width } => {
let ty = ctx.ensure_type_exists(crate::TypeInner::Vector { size, kind, width });
ast::ConstructorType::Vector { size, scalar } => {
let ty = ctx.ensure_type_exists(scalar.to_inner_vector(size));
Constructor::Type(ty)
}
ast::ConstructorType::PartialMatrix { columns, rows } => {

View File

@@ -2549,10 +2549,8 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
ctx: &mut GlobalContext<'source, '_, '_>,
) -> Result<Handle<crate::Type>, Error<'source>> {
let inner = match ctx.types[handle] {
ast::Type::Scalar { kind, width } => crate::TypeInner::Scalar { kind, width },
ast::Type::Vector { size, kind, width } => {
crate::TypeInner::Vector { size, kind, width }
}
ast::Type::Scalar(scalar) => scalar.to_inner_scalar(),
ast::Type::Vector { size, scalar } => scalar.to_inner_vector(size),
ast::Type::Matrix {
rows,
columns,
@@ -2562,7 +2560,7 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
rows,
width,
},
ast::Type::Atomic { kind, width } => crate::TypeInner::Atomic { kind, width },
ast::Type::Atomic(scalar) => scalar.to_inner_atomic(),
ast::Type::Pointer { base, space } => {
let base = self.resolve_ast_type(base, ctx)?;
crate::TypeInner::Pointer { base, space }

View File

@@ -104,9 +104,10 @@ impl crate::TypeInner {
use crate::TypeInner as Ti;
match *self {
Ti::Scalar { kind, width } => kind.to_wgsl(width),
Ti::Scalar { kind, width } => Scalar { kind, width }.to_wgsl(),
Ti::Vector { size, kind, width } => {
format!("vec{}<{}>", size as u32, kind.to_wgsl(width))
let scalar = Scalar { kind, width };
format!("vec{}<{}>", size as u32, scalar.to_wgsl())
}
Ti::Matrix {
columns,
@@ -117,11 +118,15 @@ impl crate::TypeInner {
"mat{}x{}<{}>",
columns as u32,
rows as u32,
crate::ScalarKind::Float.to_wgsl(width),
Scalar {
kind: crate::ScalarKind::Float,
width
}
.to_wgsl(),
)
}
Ti::Atomic { kind, width } => {
format!("atomic<{}>", kind.to_wgsl(width))
format!("atomic<{}>", Scalar { kind, width }.to_wgsl())
}
Ti::Pointer { base, .. } => {
let base = &gctx.types[base];
@@ -129,7 +134,7 @@ impl crate::TypeInner {
format!("ptr<{name}>")
}
Ti::ValuePointer { kind, width, .. } => {
format!("ptr<{}>", kind.to_wgsl(width))
format!("ptr<{}>", Scalar { kind, width }.to_wgsl())
}
Ti::Array { base, size, .. } => {
let member_type = &gctx.types[base];
@@ -169,7 +174,7 @@ impl crate::TypeInner {
// 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 = kind.to_wgsl(4);
let element_type = Scalar { kind, width: 4 }.to_wgsl();
format!("<{element_type}>")
}
crate::ImageClass::Depth { multi: _ } => String::new(),
@@ -287,17 +292,49 @@ mod type_inner_tests {
}
}
impl crate::ScalarKind {
/// 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, width: u8) -> String {
let prefix = match self {
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, width * 8)
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

@@ -1,4 +1,5 @@
use crate::front::wgsl::parse::number::Number;
use crate::front::wgsl::Scalar;
use crate::{Arena, FastIndexSet, Handle, Span};
use std::hash::Hash;
@@ -212,24 +213,17 @@ pub enum ArraySize<'a> {
#[derive(Debug)]
pub enum Type<'a> {
Scalar {
kind: crate::ScalarKind,
width: crate::Bytes,
},
Scalar(Scalar),
Vector {
size: crate::VectorSize,
kind: crate::ScalarKind,
width: crate::Bytes,
scalar: Scalar,
},
Matrix {
columns: crate::VectorSize,
rows: crate::VectorSize,
width: crate::Bytes,
},
Atomic {
kind: crate::ScalarKind,
width: crate::Bytes,
},
Atomic(Scalar),
Pointer {
base: Handle<Type<'a>>,
space: crate::AddressSpace,
@@ -344,10 +338,7 @@ pub struct SwitchCase<'a> {
#[derive(Debug)]
pub enum ConstructorType<'a> {
/// A scalar type or conversion: `f32(1)`.
Scalar {
kind: crate::ScalarKind,
width: crate::Bytes,
},
Scalar(Scalar),
/// A vector construction whose component type is inferred from the
/// argument: `vec3(1.0)`.
@@ -357,8 +348,7 @@ pub enum ConstructorType<'a> {
/// `vec3<f32>(1.0)`.
Vector {
size: crate::VectorSize,
kind: crate::ScalarKind,
width: crate::Bytes,
scalar: Scalar,
},
/// A matrix construction whose component type is inferred from the

View File

@@ -1,4 +1,5 @@
use super::Error;
use crate::front::wgsl::Scalar;
use crate::Span;
pub fn map_address_space(word: &str, span: Span) -> Result<crate::AddressSpace, Error<'_>> {
@@ -103,14 +104,30 @@ pub fn map_storage_format(word: &str, span: Span) -> Result<crate::StorageFormat
})
}
pub fn get_scalar_type(word: &str) -> Option<(crate::ScalarKind, crate::Bytes)> {
pub fn get_scalar_type(word: &str) -> Option<Scalar> {
use crate::ScalarKind as Sk;
match word {
// "f16" => Some((crate::ScalarKind::Float, 2)),
"f32" => Some((crate::ScalarKind::Float, 4)),
"f64" => Some((crate::ScalarKind::Float, 8)),
"i32" => Some((crate::ScalarKind::Sint, 4)),
"u32" => Some((crate::ScalarKind::Uint, 4)),
"bool" => Some((crate::ScalarKind::Bool, crate::BOOL_WIDTH)),
// "f16" => Some(Scalar { kind: Sk::Float, width: 2 }),
"f32" => Some(Scalar {
kind: Sk::Float,
width: 4,
}),
"f64" => Some(Scalar {
kind: Sk::Float,
width: 8,
}),
"i32" => Some(Scalar {
kind: Sk::Sint,
width: 4,
}),
"u32" => Some(Scalar {
kind: Sk::Uint,
width: 4,
}),
"bool" => Some(Scalar {
kind: Sk::Bool,
width: crate::BOOL_WIDTH,
}),
_ => None,
}
}

View File

@@ -1,6 +1,7 @@
use super::{number::consume_number, Error, ExpectedToken};
use crate::front::wgsl::error::NumberError;
use crate::front::wgsl::parse::{conv, Number};
use crate::front::wgsl::Scalar;
use crate::Span;
type TokenSpan<'a> = (Token<'a>, Span);
@@ -374,9 +375,7 @@ impl<'a> Lexer<'a> {
}
/// Parses a generic scalar type, for example `<f32>`.
pub(in crate::front::wgsl) fn next_scalar_generic(
&mut self,
) -> Result<(crate::ScalarKind, crate::Bytes), Error<'a>> {
pub(in crate::front::wgsl) fn next_scalar_generic(&mut self) -> Result<Scalar, Error<'a>> {
self.expect_generic_paren('<')?;
let pair = match self.next() {
(Token::Word(word), span) => {
@@ -393,11 +392,11 @@ impl<'a> Lexer<'a> {
/// Returns the span covering the inner type, excluding the brackets.
pub(in crate::front::wgsl) fn next_scalar_generic_with_span(
&mut self,
) -> Result<(crate::ScalarKind, crate::Bytes, Span), Error<'a>> {
) -> Result<(Scalar, Span), Error<'a>> {
self.expect_generic_paren('<')?;
let pair = match self.next() {
(Token::Word(word), span) => conv::get_scalar_type(word)
.map(|(a, b)| (a, b, span))
.map(|scalar| (scalar, span))
.ok_or(Error::UnknownScalarType(span)),
(_, span) => Err(Error::UnknownScalarType(span)),
}?;

View File

@@ -1,6 +1,7 @@
use crate::front::wgsl::error::{Error, ExpectedToken};
use crate::front::wgsl::parse::lexer::{Lexer, Token};
use crate::front::wgsl::parse::number::Number;
use crate::front::wgsl::Scalar;
use crate::front::SymbolTable;
use crate::{Arena, FastIndexSet, Handle, ShaderStage, Span};
@@ -277,8 +278,8 @@ impl Parser {
span: Span,
ctx: &mut ExpressionContext<'a, '_, '_>,
) -> Result<Option<ast::ConstructorType<'a>>, Error<'a>> {
if let Some((kind, width)) = conv::get_scalar_type(word) {
return Ok(Some(ast::ConstructorType::Scalar { kind, width }));
if let Some(scalar) = conv::get_scalar_type(word) {
return Ok(Some(ast::ConstructorType::Scalar(scalar)));
}
let partial = match word {
@@ -288,22 +289,28 @@ impl Parser {
"vec2i" => {
return Ok(Some(ast::ConstructorType::Vector {
size: crate::VectorSize::Bi,
kind: crate::ScalarKind::Sint,
width: 4,
scalar: Scalar {
kind: crate::ScalarKind::Sint,
width: 4,
},
}))
}
"vec2u" => {
return Ok(Some(ast::ConstructorType::Vector {
size: crate::VectorSize::Bi,
kind: crate::ScalarKind::Uint,
width: 4,
scalar: Scalar {
kind: crate::ScalarKind::Uint,
width: 4,
},
}))
}
"vec2f" => {
return Ok(Some(ast::ConstructorType::Vector {
size: crate::VectorSize::Bi,
kind: crate::ScalarKind::Float,
width: 4,
scalar: Scalar {
kind: crate::ScalarKind::Float,
width: 4,
},
}))
}
"vec3" => ast::ConstructorType::PartialVector {
@@ -312,22 +319,28 @@ impl Parser {
"vec3i" => {
return Ok(Some(ast::ConstructorType::Vector {
size: crate::VectorSize::Tri,
kind: crate::ScalarKind::Sint,
width: 4,
scalar: Scalar {
kind: crate::ScalarKind::Sint,
width: 4,
},
}))
}
"vec3u" => {
return Ok(Some(ast::ConstructorType::Vector {
size: crate::VectorSize::Tri,
kind: crate::ScalarKind::Uint,
width: 4,
scalar: Scalar {
kind: crate::ScalarKind::Uint,
width: 4,
},
}))
}
"vec3f" => {
return Ok(Some(ast::ConstructorType::Vector {
size: crate::VectorSize::Tri,
kind: crate::ScalarKind::Float,
width: 4,
scalar: Scalar {
kind: crate::ScalarKind::Float,
width: 4,
},
}))
}
"vec4" => ast::ConstructorType::PartialVector {
@@ -336,22 +349,28 @@ impl Parser {
"vec4i" => {
return Ok(Some(ast::ConstructorType::Vector {
size: crate::VectorSize::Quad,
kind: crate::ScalarKind::Sint,
width: 4,
scalar: Scalar {
kind: crate::ScalarKind::Sint,
width: 4,
},
}))
}
"vec4u" => {
return Ok(Some(ast::ConstructorType::Vector {
size: crate::VectorSize::Quad,
kind: crate::ScalarKind::Uint,
width: 4,
scalar: Scalar {
kind: crate::ScalarKind::Uint,
width: 4,
},
}))
}
"vec4f" => {
return Ok(Some(ast::ConstructorType::Vector {
size: crate::VectorSize::Quad,
kind: crate::ScalarKind::Float,
width: 4,
scalar: Scalar {
kind: crate::ScalarKind::Float,
width: 4,
},
}))
}
"mat2x2" => ast::ConstructorType::PartialMatrix {
@@ -483,18 +502,18 @@ impl Parser {
// parse component type if present
match (lexer.peek().0, partial) {
(Token::Paren('<'), ast::ConstructorType::PartialVector { size }) => {
let (kind, width) = lexer.next_scalar_generic()?;
Ok(Some(ast::ConstructorType::Vector { size, kind, width }))
let scalar = lexer.next_scalar_generic()?;
Ok(Some(ast::ConstructorType::Vector { size, scalar }))
}
(Token::Paren('<'), ast::ConstructorType::PartialMatrix { columns, rows }) => {
let (kind, width, span) = lexer.next_scalar_generic_with_span()?;
match kind {
let (scalar, span) = lexer.next_scalar_generic_with_span()?;
match scalar.kind {
crate::ScalarKind::Float => Ok(Some(ast::ConstructorType::Matrix {
columns,
rows,
width,
width: scalar.width,
})),
_ => Err(Error::BadMatrixScalarKind(span, kind, width)),
_ => Err(Error::BadMatrixScalarKind(span, scalar)),
}
}
(Token::Paren('<'), ast::ConstructorType::PartialArray) => {
@@ -1045,14 +1064,14 @@ impl Parser {
columns: crate::VectorSize,
rows: crate::VectorSize,
) -> Result<ast::Type<'a>, Error<'a>> {
let (kind, width, span) = lexer.next_scalar_generic_with_span()?;
match kind {
let (scalar, span) = lexer.next_scalar_generic_with_span()?;
match scalar.kind {
crate::ScalarKind::Float => Ok(ast::Type::Matrix {
columns,
rows,
width,
width: scalar.width,
}),
_ => Err(Error::BadMatrixScalarKind(span, kind, width)),
_ => Err(Error::BadMatrixScalarKind(span, scalar)),
}
}
@@ -1062,79 +1081,94 @@ impl Parser {
word: &'a str,
ctx: &mut ExpressionContext<'a, '_, '_>,
) -> Result<Option<ast::Type<'a>>, Error<'a>> {
if let Some((kind, width)) = conv::get_scalar_type(word) {
return Ok(Some(ast::Type::Scalar { kind, width }));
if let Some(scalar) = conv::get_scalar_type(word) {
return Ok(Some(ast::Type::Scalar(scalar)));
}
Ok(Some(match word {
"vec2" => {
let (kind, width) = lexer.next_scalar_generic()?;
let scalar = lexer.next_scalar_generic()?;
ast::Type::Vector {
size: crate::VectorSize::Bi,
kind,
width,
scalar,
}
}
"vec2i" => ast::Type::Vector {
size: crate::VectorSize::Bi,
kind: crate::ScalarKind::Sint,
width: 4,
scalar: Scalar {
kind: crate::ScalarKind::Sint,
width: 4,
},
},
"vec2u" => ast::Type::Vector {
size: crate::VectorSize::Bi,
kind: crate::ScalarKind::Uint,
width: 4,
scalar: Scalar {
kind: crate::ScalarKind::Uint,
width: 4,
},
},
"vec2f" => ast::Type::Vector {
size: crate::VectorSize::Bi,
kind: crate::ScalarKind::Float,
width: 4,
scalar: Scalar {
kind: crate::ScalarKind::Float,
width: 4,
},
},
"vec3" => {
let (kind, width) = lexer.next_scalar_generic()?;
let scalar = lexer.next_scalar_generic()?;
ast::Type::Vector {
size: crate::VectorSize::Tri,
kind,
width,
scalar,
}
}
"vec3i" => ast::Type::Vector {
size: crate::VectorSize::Tri,
kind: crate::ScalarKind::Sint,
width: 4,
scalar: Scalar {
kind: crate::ScalarKind::Sint,
width: 4,
},
},
"vec3u" => ast::Type::Vector {
size: crate::VectorSize::Tri,
kind: crate::ScalarKind::Uint,
width: 4,
scalar: Scalar {
kind: crate::ScalarKind::Uint,
width: 4,
},
},
"vec3f" => ast::Type::Vector {
size: crate::VectorSize::Tri,
kind: crate::ScalarKind::Float,
width: 4,
scalar: Scalar {
kind: crate::ScalarKind::Float,
width: 4,
},
},
"vec4" => {
let (kind, width) = lexer.next_scalar_generic()?;
let scalar = lexer.next_scalar_generic()?;
ast::Type::Vector {
size: crate::VectorSize::Quad,
kind,
width,
scalar,
}
}
"vec4i" => ast::Type::Vector {
size: crate::VectorSize::Quad,
kind: crate::ScalarKind::Sint,
width: 4,
scalar: Scalar {
kind: crate::ScalarKind::Sint,
width: 4,
},
},
"vec4u" => ast::Type::Vector {
size: crate::VectorSize::Quad,
kind: crate::ScalarKind::Uint,
width: 4,
scalar: Scalar {
kind: crate::ScalarKind::Uint,
width: 4,
},
},
"vec4f" => ast::Type::Vector {
size: crate::VectorSize::Quad,
kind: crate::ScalarKind::Float,
width: 4,
scalar: Scalar {
kind: crate::ScalarKind::Float,
width: 4,
},
},
"mat2x2" => {
self.matrix_scalar_type(lexer, crate::VectorSize::Bi, crate::VectorSize::Bi)?
@@ -1209,8 +1243,8 @@ impl Parser {
width: 4,
},
"atomic" => {
let (kind, width) = lexer.next_scalar_generic()?;
ast::Type::Atomic { kind, width }
let scalar = lexer.next_scalar_generic()?;
ast::Type::Atomic(scalar)
}
"ptr" => {
lexer.expect_generic_paren('<')?;
@@ -1257,84 +1291,111 @@ impl Parser {
"sampler" => ast::Type::Sampler { comparison: false },
"sampler_comparison" => ast::Type::Sampler { comparison: true },
"texture_1d" => {
let (kind, width, span) = lexer.next_scalar_generic_with_span()?;
Self::check_texture_sample_type(kind, width, span)?;
let (scalar, span) = lexer.next_scalar_generic_with_span()?;
Self::check_texture_sample_type(scalar, span)?;
ast::Type::Image {
dim: crate::ImageDimension::D1,
arrayed: false,
class: crate::ImageClass::Sampled { kind, multi: false },
class: crate::ImageClass::Sampled {
kind: scalar.kind,
multi: false,
},
}
}
"texture_1d_array" => {
let (kind, width, span) = lexer.next_scalar_generic_with_span()?;
Self::check_texture_sample_type(kind, width, span)?;
let (scalar, span) = lexer.next_scalar_generic_with_span()?;
Self::check_texture_sample_type(scalar, span)?;
ast::Type::Image {
dim: crate::ImageDimension::D1,
arrayed: true,
class: crate::ImageClass::Sampled { kind, multi: false },
class: crate::ImageClass::Sampled {
kind: scalar.kind,
multi: false,
},
}
}
"texture_2d" => {
let (kind, width, span) = lexer.next_scalar_generic_with_span()?;
Self::check_texture_sample_type(kind, width, span)?;
let (scalar, span) = lexer.next_scalar_generic_with_span()?;
Self::check_texture_sample_type(scalar, span)?;
ast::Type::Image {
dim: crate::ImageDimension::D2,
arrayed: false,
class: crate::ImageClass::Sampled { kind, multi: false },
class: crate::ImageClass::Sampled {
kind: scalar.kind,
multi: false,
},
}
}
"texture_2d_array" => {
let (kind, width, span) = lexer.next_scalar_generic_with_span()?;
Self::check_texture_sample_type(kind, width, span)?;
let (scalar, span) = lexer.next_scalar_generic_with_span()?;
Self::check_texture_sample_type(scalar, span)?;
ast::Type::Image {
dim: crate::ImageDimension::D2,
arrayed: true,
class: crate::ImageClass::Sampled { kind, multi: false },
class: crate::ImageClass::Sampled {
kind: scalar.kind,
multi: false,
},
}
}
"texture_3d" => {
let (kind, width, span) = lexer.next_scalar_generic_with_span()?;
Self::check_texture_sample_type(kind, width, span)?;
let (scalar, span) = lexer.next_scalar_generic_with_span()?;
Self::check_texture_sample_type(scalar, span)?;
ast::Type::Image {
dim: crate::ImageDimension::D3,
arrayed: false,
class: crate::ImageClass::Sampled { kind, multi: false },
class: crate::ImageClass::Sampled {
kind: scalar.kind,
multi: false,
},
}
}
"texture_cube" => {
let (kind, width, span) = lexer.next_scalar_generic_with_span()?;
Self::check_texture_sample_type(kind, width, span)?;
let (scalar, span) = lexer.next_scalar_generic_with_span()?;
Self::check_texture_sample_type(scalar, span)?;
ast::Type::Image {
dim: crate::ImageDimension::Cube,
arrayed: false,
class: crate::ImageClass::Sampled { kind, multi: false },
class: crate::ImageClass::Sampled {
kind: scalar.kind,
multi: false,
},
}
}
"texture_cube_array" => {
let (kind, width, span) = lexer.next_scalar_generic_with_span()?;
Self::check_texture_sample_type(kind, width, span)?;
let (scalar, span) = lexer.next_scalar_generic_with_span()?;
Self::check_texture_sample_type(scalar, span)?;
ast::Type::Image {
dim: crate::ImageDimension::Cube,
arrayed: true,
class: crate::ImageClass::Sampled { kind, multi: false },
class: crate::ImageClass::Sampled {
kind: scalar.kind,
multi: false,
},
}
}
"texture_multisampled_2d" => {
let (kind, width, span) = lexer.next_scalar_generic_with_span()?;
Self::check_texture_sample_type(kind, width, span)?;
let (scalar, span) = lexer.next_scalar_generic_with_span()?;
Self::check_texture_sample_type(scalar, span)?;
ast::Type::Image {
dim: crate::ImageDimension::D2,
arrayed: false,
class: crate::ImageClass::Sampled { kind, multi: true },
class: crate::ImageClass::Sampled {
kind: scalar.kind,
multi: true,
},
}
}
"texture_multisampled_2d_array" => {
let (kind, width, span) = lexer.next_scalar_generic_with_span()?;
Self::check_texture_sample_type(kind, width, span)?;
let (scalar, span) = lexer.next_scalar_generic_with_span()?;
Self::check_texture_sample_type(scalar, span)?;
ast::Type::Image {
dim: crate::ImageDimension::D2,
arrayed: true,
class: crate::ImageClass::Sampled { kind, multi: true },
class: crate::ImageClass::Sampled {
kind: scalar.kind,
multi: true,
},
}
}
"texture_depth_2d" => ast::Type::Image {
@@ -1410,16 +1471,15 @@ impl Parser {
}))
}
const fn check_texture_sample_type(
kind: crate::ScalarKind,
width: u8,
span: Span,
) -> Result<(), Error<'static>> {
const fn check_texture_sample_type(scalar: Scalar, span: Span) -> Result<(), Error<'static>> {
use crate::ScalarKind::*;
// Validate according to https://gpuweb.github.io/gpuweb/wgsl/#sampled-texture-type
match (kind, width) {
(Float | Sint | Uint, 4) => Ok(()),
_ => Err(Error::BadTextureSampleType { span, kind, width }),
match scalar {
Scalar {
kind: Float | Sint | Uint,
width: 4,
} => Ok(()),
_ => Err(Error::BadTextureSampleType { span, scalar }),
}
}