From 267bd488d385ce2d35158195562624eda7ec85d1 Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Sun, 5 Nov 2023 15:18:55 -0800 Subject: [PATCH 01/34] [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. --- naga/src/front/wgsl/error.rs | 14 +- naga/src/front/wgsl/lower/construction.rs | 8 +- naga/src/front/wgsl/lower/mod.rs | 8 +- naga/src/front/wgsl/mod.rs | 57 ++++- naga/src/front/wgsl/parse/ast.rs | 22 +- naga/src/front/wgsl/parse/conv.rs | 31 ++- naga/src/front/wgsl/parse/lexer.rs | 9 +- naga/src/front/wgsl/parse/mod.rs | 252 +++++++++++++--------- 8 files changed, 251 insertions(+), 150 deletions(-) diff --git a/naga/src/front/wgsl/error.rs b/naga/src/front/wgsl/error.rs index 9143a8c07ec..e4d3e6d325d 100644 --- a/naga/src/front/wgsl/error.rs +++ b/naga/src/front/wgsl/error.rs @@ -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![], diff --git a/naga/src/front/wgsl/lower/construction.rs b/naga/src/front/wgsl/lower/construction.rs index 912713f9112..1393022f8b6 100644 --- a/naga/src/front/wgsl/lower/construction.rs +++ b/naga/src/front/wgsl/lower/construction.rs @@ -516,13 +516,13 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { ctx: &mut ExpressionContext<'source, '_, 'out>, ) -> Result>, 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 } => { diff --git a/naga/src/front/wgsl/lower/mod.rs b/naga/src/front/wgsl/lower/mod.rs index c48413aba68..567360b5d82 100644 --- a/naga/src/front/wgsl/lower/mod.rs +++ b/naga/src/front/wgsl/lower/mod.rs @@ -2549,10 +2549,8 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { ctx: &mut GlobalContext<'source, '_, '_>, ) -> Result, 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 } diff --git a/naga/src/front/wgsl/mod.rs b/naga/src/front/wgsl/mod.rs index 56834d5d926..c1d263ee69c 100644 --- a/naga/src/front/wgsl/mod.rs +++ b/naga/src/front/wgsl/mod.rs @@ -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, + } } } diff --git a/naga/src/front/wgsl/parse/ast.rs b/naga/src/front/wgsl/parse/ast.rs index f88e880a3f5..dbaac523cbe 100644 --- a/naga/src/front/wgsl/parse/ast.rs +++ b/naga/src/front/wgsl/parse/ast.rs @@ -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>, 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(1.0)`. Vector { size: crate::VectorSize, - kind: crate::ScalarKind, - width: crate::Bytes, + scalar: Scalar, }, /// A matrix construction whose component type is inferred from the diff --git a/naga/src/front/wgsl/parse/conv.rs b/naga/src/front/wgsl/parse/conv.rs index 51977173d6b..08f1e392857 100644 --- a/naga/src/front/wgsl/parse/conv.rs +++ b/naga/src/front/wgsl/parse/conv.rs @@ -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> { @@ -103,14 +104,30 @@ pub fn map_storage_format(word: &str, span: Span) -> Result Option<(crate::ScalarKind, crate::Bytes)> { +pub fn get_scalar_type(word: &str) -> Option { + 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, } } diff --git a/naga/src/front/wgsl/parse/lexer.rs b/naga/src/front/wgsl/parse/lexer.rs index ed273fbbb16..dc229bb5fa3 100644 --- a/naga/src/front/wgsl/parse/lexer.rs +++ b/naga/src/front/wgsl/parse/lexer.rs @@ -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 ``. - 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> { 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)), }?; diff --git a/naga/src/front/wgsl/parse/mod.rs b/naga/src/front/wgsl/parse/mod.rs index ae690018f1c..bd635b9189e 100644 --- a/naga/src/front/wgsl/parse/mod.rs +++ b/naga/src/front/wgsl/parse/mod.rs @@ -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>, 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, 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>, 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 }), } } From 7f72c9fc3b39947aaa81d5ef3440fde0513b6da9 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Mon, 6 Nov 2023 07:58:26 -0500 Subject: [PATCH 02/34] Fix GL Push Constant Layout (#4607) * It verks! * More tests * Fixes * Working multi-stage push constants * Comments * Add push constant partial update teste * Docs * Update Cargo.toml * Comments --- Cargo.lock | 3 +- naga/src/back/glsl/mod.rs | 155 ++++++++++- .../glsl/push-constants.main.Fragment.glsl | 4 +- .../glsl/push-constants.vert_main.Vertex.glsl | 4 +- tests/src/image.rs | 16 +- tests/tests/gpu.rs | 2 + tests/tests/partially_bounded_arrays/mod.rs | 7 +- tests/tests/push_constants.rs | 151 +++++++++++ tests/tests/regression/issue_3349.fs.wgsl | 46 ++++ tests/tests/regression/issue_3349.rs | 178 ++++++++++++ tests/tests/regression/issue_3349.vs.wgsl | 22 ++ tests/tests/scissor_tests/mod.rs | 2 +- tests/tests/shader/mod.rs | 10 + tests/tests/shader/shader_test.wgsl | 2 + tests/tests/shader/struct_layout.rs | 50 +++- tests/tests/shader_primitive_index/mod.rs | 2 +- wgpu-hal/Cargo.toml | 6 +- wgpu-hal/src/dx11/command.rs | 2 +- wgpu-hal/src/dx12/command.rs | 7 +- wgpu-hal/src/empty.rs | 2 +- wgpu-hal/src/gles/command.rs | 91 +++++-- wgpu-hal/src/gles/conv.rs | 102 ------- wgpu-hal/src/gles/device.rs | 73 ++--- wgpu-hal/src/gles/mod.rs | 21 +- wgpu-hal/src/gles/queue.rs | 255 +++++++++++++++--- wgpu-hal/src/lib.rs | 13 +- wgpu-hal/src/metal/command.rs | 8 +- wgpu-hal/src/vulkan/command.rs | 4 +- wgpu-hal/src/vulkan/device.rs | 2 +- wgpu/src/backend/direct.rs | 6 +- 30 files changed, 993 insertions(+), 253 deletions(-) create mode 100644 tests/tests/push_constants.rs create mode 100644 tests/tests/regression/issue_3349.fs.wgsl create mode 100644 tests/tests/regression/issue_3349.rs create mode 100644 tests/tests/regression/issue_3349.vs.wgsl diff --git a/Cargo.lock b/Cargo.lock index 3e7cc227ad4..a241b78fb70 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1567,8 +1567,7 @@ checksum = "b5418c17512bdf42730f9032c74e1ae39afc408745ebb2acf72fbc4691c17945" [[package]] name = "glow" version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "886c2a30b160c4c6fec8f987430c26b526b7988ca71f664e6a699ddf6f9601e4" +source = "git+https://github.com/grovesNL/glow.git?rev=29ff917a2b2ff7ce0a81b2cc5681de6d4735b36e#29ff917a2b2ff7ce0a81b2cc5681de6d4735b36e" dependencies = [ "js-sys", "slotmap", diff --git a/naga/src/back/glsl/mod.rs b/naga/src/back/glsl/mod.rs index 592c72a9a5e..b33c904f305 100644 --- a/naga/src/back/glsl/mod.rs +++ b/naga/src/back/glsl/mod.rs @@ -309,6 +309,8 @@ pub struct ReflectionInfo { pub uniforms: crate::FastHashMap, String>, /// Mapping between names and attribute locations. pub varying: crate::FastHashMap, + /// List of push constant items in the shader. + pub push_constant_items: Vec, } /// Mapping between a texture and its sampler, if it exists. @@ -328,6 +330,50 @@ pub struct TextureMapping { pub sampler: Option>, } +/// All information to bind a single uniform value to the shader. +/// +/// Push constants are emulated using traditional uniforms in OpenGL. +/// +/// These are composed of a set of primatives (scalar, vector, matrix) that +/// are given names. Because they are not backed by the concept of a buffer, +/// we must do the work of calculating the offset of each primative in the +/// push constant block. +#[derive(Debug, Clone)] +pub struct PushConstantItem { + /// GL uniform name for the item. This name is the same as if you were + /// to access it directly from a GLSL shader. + /// + /// The with the following example, the following names will be generated, + /// one name per GLSL uniform. + /// + /// ```glsl + /// struct InnerStruct { + /// value: f32, + /// } + /// + /// struct PushConstant { + /// InnerStruct inner; + /// vec4 array[2]; + /// } + /// + /// uniform PushConstants _push_constant_binding_cs; + /// ``` + /// + /// ```text + /// - _push_constant_binding_cs.inner.value + /// - _push_constant_binding_cs.array[0] + /// - _push_constant_binding_cs.array[1] + /// ``` + /// + pub access_path: String, + /// Type of the uniform. This will only ever be a scalar, vector, or matrix. + pub ty: Handle, + /// The offset in the push constant memory block this uniform maps to. + /// + /// The size of the uniform can be derived from the type. + pub offset: u32, +} + /// Helper structure that generates a number #[derive(Default)] struct IdGenerator(u32); @@ -1264,8 +1310,8 @@ impl<'a, W: Write> Writer<'a, W> { handle: Handle, global: &crate::GlobalVariable, ) -> String { - match global.binding { - Some(ref br) => { + match (&global.binding, global.space) { + (&Some(ref br), _) => { format!( "_group_{}_binding_{}_{}", br.group, @@ -1273,7 +1319,10 @@ impl<'a, W: Write> Writer<'a, W> { self.entry_point.stage.to_str() ) } - None => self.names[&NameKey::GlobalVariable(handle)].clone(), + (&None, crate::AddressSpace::PushConstant) => { + format!("_push_constant_binding_{}", self.entry_point.stage.to_str()) + } + (&None, _) => self.names[&NameKey::GlobalVariable(handle)].clone(), } } @@ -1283,15 +1332,20 @@ impl<'a, W: Write> Writer<'a, W> { handle: Handle, global: &crate::GlobalVariable, ) -> BackendResult { - match global.binding { - Some(ref br) => write!( + match (&global.binding, global.space) { + (&Some(ref br), _) => write!( self.out, "_group_{}_binding_{}_{}", br.group, br.binding, self.entry_point.stage.to_str() )?, - None => write!( + (&None, crate::AddressSpace::PushConstant) => write!( + self.out, + "_push_constant_binding_{}", + self.entry_point.stage.to_str() + )?, + (&None, _) => write!( self.out, "{}", &self.names[&NameKey::GlobalVariable(handle)] @@ -4069,6 +4123,7 @@ impl<'a, W: Write> Writer<'a, W> { } } + let mut push_constant_info = None; for (handle, var) in self.module.global_variables.iter() { if info[handle].is_empty() { continue; @@ -4093,17 +4148,105 @@ impl<'a, W: Write> Writer<'a, W> { let name = self.reflection_names_globals[&handle].clone(); uniforms.insert(handle, name); } + crate::AddressSpace::PushConstant => { + let name = self.reflection_names_globals[&handle].clone(); + push_constant_info = Some((name, var.ty)); + } _ => (), }, } } + let mut push_constant_segments = Vec::new(); + let mut push_constant_items = vec![]; + + if let Some((name, ty)) = push_constant_info { + // We don't have a layouter available to us, so we need to create one. + // + // This is potentially a bit wasteful, but the set of types in the program + // shouldn't be too large. + let mut layouter = crate::proc::Layouter::default(); + layouter.update(self.module.to_ctx()).unwrap(); + + // We start with the name of the binding itself. + push_constant_segments.push(name); + + // We then recursively collect all the uniform fields of the push constant. + self.collect_push_constant_items( + ty, + &mut push_constant_segments, + &layouter, + &mut 0, + &mut push_constant_items, + ); + } + Ok(ReflectionInfo { texture_mapping, uniforms, varying: mem::take(&mut self.varying), + push_constant_items, }) } + + fn collect_push_constant_items( + &mut self, + ty: Handle, + segments: &mut Vec, + layouter: &crate::proc::Layouter, + offset: &mut u32, + items: &mut Vec, + ) { + // At this point in the recursion, `segments` contains the path + // needed to access `ty` from the root. + + let layout = &layouter[ty]; + *offset = layout.alignment.round_up(*offset); + match self.module.types[ty].inner { + // All these types map directly to GL uniforms. + TypeInner::Scalar { .. } | TypeInner::Vector { .. } | TypeInner::Matrix { .. } => { + // Build the full name, by combining all current segments. + let name: String = segments.iter().map(String::as_str).collect(); + items.push(PushConstantItem { + access_path: name, + offset: *offset, + ty, + }); + *offset += layout.size; + } + // Arrays are recursed into. + TypeInner::Array { base, size, .. } => { + let crate::ArraySize::Constant(count) = size else { + unreachable!("Cannot have dynamic arrays in push constants"); + }; + + for i in 0..count.get() { + // Add the array accessor and recurse. + segments.push(format!("[{}]", i)); + self.collect_push_constant_items(base, segments, layouter, offset, items); + segments.pop(); + } + + // Ensure the stride is kept by rounding up to the alignment. + *offset = layout.alignment.round_up(*offset) + } + TypeInner::Struct { ref members, .. } => { + for (index, member) in members.iter().enumerate() { + // Add struct accessor and recurse. + segments.push(format!( + ".{}", + self.names[&NameKey::StructMember(ty, index as u32)] + )); + self.collect_push_constant_items(member.ty, segments, layouter, offset, items); + segments.pop(); + } + + // Ensure ending padding is kept by rounding up to the alignment. + *offset = layout.alignment.round_up(*offset) + } + _ => unreachable!(), + } + } } /// Structure returned by [`glsl_scalar`] diff --git a/naga/tests/out/glsl/push-constants.main.Fragment.glsl b/naga/tests/out/glsl/push-constants.main.Fragment.glsl index fa1be9f61f1..8131e9e8976 100644 --- a/naga/tests/out/glsl/push-constants.main.Fragment.glsl +++ b/naga/tests/out/glsl/push-constants.main.Fragment.glsl @@ -9,14 +9,14 @@ struct PushConstants { struct FragmentIn { vec4 color; }; -uniform PushConstants pc; +uniform PushConstants _push_constant_binding_fs; layout(location = 0) smooth in vec4 _vs2fs_location0; layout(location = 0) out vec4 _fs2p_location0; void main() { FragmentIn in_ = FragmentIn(_vs2fs_location0); - float _e4 = pc.multiplier; + float _e4 = _push_constant_binding_fs.multiplier; _fs2p_location0 = (in_.color * _e4); return; } diff --git a/naga/tests/out/glsl/push-constants.vert_main.Vertex.glsl b/naga/tests/out/glsl/push-constants.vert_main.Vertex.glsl index 27cd7037abf..4519dc4c6c2 100644 --- a/naga/tests/out/glsl/push-constants.vert_main.Vertex.glsl +++ b/naga/tests/out/glsl/push-constants.vert_main.Vertex.glsl @@ -9,14 +9,14 @@ struct PushConstants { struct FragmentIn { vec4 color; }; -uniform PushConstants pc; +uniform PushConstants _push_constant_binding_vs; layout(location = 0) in vec2 _p2vs_location0; void main() { vec2 pos = _p2vs_location0; uint vi = uint(gl_VertexID); - float _e5 = pc.multiplier; + float _e5 = _push_constant_binding_vs.multiplier; gl_Position = vec4(((float(vi) * _e5) * pos), 0.0, 1.0); return; } diff --git a/tests/src/image.rs b/tests/src/image.rs index 0e3ea9ea8e5..66f6abf16a1 100644 --- a/tests/src/image.rs +++ b/tests/src/image.rs @@ -625,12 +625,16 @@ impl ReadbackBuffers { buffer_zero && stencil_buffer_zero } - pub fn check_buffer_contents(&self, device: &Device, expected_data: &[u8]) -> bool { - let result = self - .retrieve_buffer(device, &self.buffer, self.buffer_aspect()) - .iter() - .eq(expected_data.iter()); + pub fn assert_buffer_contents(&self, device: &Device, expected_data: &[u8]) { + let result_buffer = self.retrieve_buffer(device, &self.buffer, self.buffer_aspect()); + assert!( + result_buffer.len() >= expected_data.len(), + "Result buffer ({}) smaller than expected buffer ({})", + result_buffer.len(), + expected_data.len() + ); + let result_buffer = &result_buffer[..expected_data.len()]; + assert_eq!(result_buffer, expected_data); self.buffer.unmap(); - result } } diff --git a/tests/tests/gpu.rs b/tests/tests/gpu.rs index a5fbcde9da9..c10df13ed73 100644 --- a/tests/tests/gpu.rs +++ b/tests/tests/gpu.rs @@ -1,4 +1,5 @@ mod regression { + mod issue_3349; mod issue_3457; mod issue_4024; mod issue_4122; @@ -19,6 +20,7 @@ mod occlusion_query; mod partially_bounded_arrays; mod pipeline; mod poll; +mod push_constants; mod query_set; mod queue_transfer; mod resource_descriptor_accessor; diff --git a/tests/tests/partially_bounded_arrays/mod.rs b/tests/tests/partially_bounded_arrays/mod.rs index acadaad67b3..5a41ae8f29c 100644 --- a/tests/tests/partially_bounded_arrays/mod.rs +++ b/tests/tests/partially_bounded_arrays/mod.rs @@ -97,9 +97,6 @@ static PARTIALLY_BOUNDED_ARRAY: GpuTestConfiguration = GpuTestConfiguration::new ctx.queue.submit(Some(encoder.finish())); - assert!( - readback_buffers - .check_buffer_contents(device, bytemuck::bytes_of(&[4.0f32, 3.0, 2.0, 1.0])), - "texture storage values are incorrect!" - ); + readback_buffers + .assert_buffer_contents(device, bytemuck::bytes_of(&[4.0f32, 3.0, 2.0, 1.0])); }); diff --git a/tests/tests/push_constants.rs b/tests/tests/push_constants.rs new file mode 100644 index 00000000000..e39000173c4 --- /dev/null +++ b/tests/tests/push_constants.rs @@ -0,0 +1,151 @@ +use std::num::NonZeroU64; + +use wgpu_test::{gpu_test, GpuTestConfiguration, TestParameters, TestingContext}; + +/// We want to test that partial updates to push constants work as expected. +/// +/// As such, we dispatch two compute passes, one which writes the values +/// before a parital update, and one which writes the values after the partial update. +/// +/// If the update code is working correctly, the values not written to by the second update +/// will remain unchanged. +#[gpu_test] +static PARTIAL_UPDATE: GpuTestConfiguration = GpuTestConfiguration::new() + .parameters( + TestParameters::default() + .features(wgpu::Features::PUSH_CONSTANTS) + .limits(wgpu::Limits { + max_push_constant_size: 32, + ..Default::default() + }), + ) + .run_sync(partial_update_test); + +const SHADER: &str = r#" + struct Pc { + offset: u32, + vector: vec4f, + } + + var pc: Pc; + + @group(0) @binding(0) + var output: array; + + @compute @workgroup_size(1) + fn main() { + output[pc.offset] = pc.vector; + } +"#; + +fn partial_update_test(ctx: TestingContext) { + let sm = ctx + .device + .create_shader_module(wgpu::ShaderModuleDescriptor { + label: Some("shader"), + source: wgpu::ShaderSource::Wgsl(SHADER.into()), + }); + + let bgl = ctx + .device + .create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("bind_group_layout"), + entries: &[wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::COMPUTE, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Storage { read_only: false }, + has_dynamic_offset: false, + min_binding_size: NonZeroU64::new(16), + }, + count: None, + }], + }); + + let gpu_buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor { + label: Some("gpu_buffer"), + size: 32, + usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_SRC, + mapped_at_creation: false, + }); + + let cpu_buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor { + label: Some("cpu_buffer"), + size: 32, + usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ, + mapped_at_creation: false, + }); + + let bind_group = ctx.device.create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("bind_group"), + layout: &bgl, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: gpu_buffer.as_entire_binding(), + }], + }); + + let pipeline_layout = ctx + .device + .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("pipeline_layout"), + bind_group_layouts: &[&bgl], + push_constant_ranges: &[wgpu::PushConstantRange { + stages: wgpu::ShaderStages::COMPUTE, + range: 0..32, + }], + }); + + let pipeline = ctx + .device + .create_compute_pipeline(&wgpu::ComputePipelineDescriptor { + label: Some("pipeline"), + layout: Some(&pipeline_layout), + module: &sm, + entry_point: "main", + }); + + let mut encoder = ctx + .device + .create_command_encoder(&wgpu::CommandEncoderDescriptor { + label: Some("encoder"), + }); + + { + let mut cpass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor { + label: Some("compute_pass"), + timestamp_writes: None, + }); + cpass.set_pipeline(&pipeline); + cpass.set_bind_group(0, &bind_group, &[]); + + // -- Dispatch 0 -- + + // Dispatch number + cpass.set_push_constants(0, bytemuck::bytes_of(&[0_u32])); + // Update the whole vector. + cpass.set_push_constants(16, bytemuck::bytes_of(&[1.0_f32, 2.0, 3.0, 4.0])); + cpass.dispatch_workgroups(1, 1, 1); + + // -- Dispatch 1 -- + + // Dispatch number + cpass.set_push_constants(0, bytemuck::bytes_of(&[1_u32])); + // Update just the y component of the vector. + cpass.set_push_constants(20, bytemuck::bytes_of(&[5.0_f32])); + cpass.dispatch_workgroups(1, 1, 1); + } + + encoder.copy_buffer_to_buffer(&gpu_buffer, 0, &cpu_buffer, 0, 32); + ctx.queue.submit([encoder.finish()]); + cpu_buffer.slice(..).map_async(wgpu::MapMode::Read, |_| ()); + ctx.device.poll(wgpu::Maintain::Wait); + + let data = cpu_buffer.slice(..).get_mapped_range(); + + let floats: &[f32] = bytemuck::cast_slice(&data); + + // first 4 floats the initial value + // second 4 floats the first update + assert_eq!(floats, [1.0, 2.0, 3.0, 4.0, 1.0, 5.0, 3.0, 4.0]); +} diff --git a/tests/tests/regression/issue_3349.fs.wgsl b/tests/tests/regression/issue_3349.fs.wgsl new file mode 100644 index 00000000000..d6a5ea5ceb3 --- /dev/null +++ b/tests/tests/regression/issue_3349.fs.wgsl @@ -0,0 +1,46 @@ +struct ShaderData { + a: f32, + b: f32, + c: f32, + d: f32, +} + +@group(0) @binding(0) +var data1: ShaderData; + +var data2: ShaderData; + +struct FsIn { + @builtin(position) position: vec4f, + @location(0) data1: vec4f, + @location(1) data2: vec4f, +} + +@fragment +fn fs_main(fs_in: FsIn) -> @location(0) vec4f { + let floored = vec2u(floor(fs_in.position.xy)); + // We're outputting a 2x2 image, each pixel coming from a different source + let serial = floored.x + floored.y * 2u; + + switch serial { + // (0, 0) - uniform buffer from the vertex shader + case 0u: { + return fs_in.data1; + } + // (1, 0) - push constant from the vertex shader + case 1u: { + return fs_in.data2; + } + // (0, 1) - uniform buffer from the fragment shader + case 2u: { + return vec4f(data1.a, data1.b, data1.c, data1.d); + } + // (1, 1) - push constant from the fragment shader + case 3u: { + return vec4f(data2.a, data2.b, data2.c, data2.d); + } + default: { + return vec4f(0.0); + } + } +} diff --git a/tests/tests/regression/issue_3349.rs b/tests/tests/regression/issue_3349.rs new file mode 100644 index 00000000000..5db5575ddf1 --- /dev/null +++ b/tests/tests/regression/issue_3349.rs @@ -0,0 +1,178 @@ +use wgpu::util::DeviceExt; +use wgpu_test::{ + gpu_test, image::ReadbackBuffers, GpuTestConfiguration, TestParameters, TestingContext, +}; + +/// We thought we had an OpenGL bug that, when running without explicit in-shader locations, +/// we will not properly bind uniform buffers to both the vertex and fragment +/// shaders. This turned out to not reproduce at all with this test case. +/// +/// However, it also caught issues with the push constant implementation, +/// making sure that it works correctly with different definitions for the push constant +/// block in vertex and fragment shaders. +/// +/// This test needs to be able to run on GLES 3.0 +/// +/// What this test does is render a 2x2 texture. Each pixel corresponds to a different +/// data source. +/// +/// top left: Vertex Shader / Uniform Buffer +/// top right: Vertex Shader / Push Constant +/// bottom left: Fragment Shader / Uniform Buffer +/// bottom right: Fragment Shader / Push Constant +/// +/// We then validate the data is correct from every position. +#[gpu_test] +static MULTI_STAGE_DATA_BINDING: GpuTestConfiguration = GpuTestConfiguration::new() + .parameters( + TestParameters::default() + .features(wgpu::Features::PUSH_CONSTANTS) + .limits(wgpu::Limits { + max_push_constant_size: 16, + ..Default::default() + }), + ) + .run_sync(multi_stage_data_binding_test); + +fn multi_stage_data_binding_test(ctx: TestingContext) { + // We use different shader modules to allow us to use different + // types for the uniform and push constant blocks between stages. + let vs_sm = ctx + .device + .create_shader_module(wgpu::include_wgsl!("issue_3349.vs.wgsl")); + + let fs_sm = ctx + .device + .create_shader_module(wgpu::include_wgsl!("issue_3349.fs.wgsl")); + + // We start with u8s then convert to float, to make sure we don't have + // cross-vendor rounding issues unorm. + let input_as_unorm: [u8; 4] = [25_u8, 50, 75, 100]; + let input = input_as_unorm.map(|v| v as f32 / 255.0); + + let buffer = ctx + .device + .create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("buffer"), + contents: bytemuck::cast_slice(&input), + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + }); + + let bgl = ctx + .device + .create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("bgl"), + entries: &[wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::VERTEX_FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }], + }); + + let bg = ctx.device.create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("bg"), + layout: &bgl, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: buffer.as_entire_binding(), + }], + }); + + let pll = ctx + .device + .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("pll"), + bind_group_layouts: &[&bgl], + push_constant_ranges: &[wgpu::PushConstantRange { + stages: wgpu::ShaderStages::VERTEX_FRAGMENT, + range: 0..16, + }], + }); + + let pipeline = ctx + .device + .create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: Some("pipeline"), + layout: Some(&pll), + vertex: wgpu::VertexState { + module: &vs_sm, + entry_point: "vs_main", + buffers: &[], + }, + fragment: Some(wgpu::FragmentState { + module: &fs_sm, + entry_point: "fs_main", + targets: &[Some(wgpu::ColorTargetState { + format: wgpu::TextureFormat::Rgba8Unorm, + blend: None, + write_mask: wgpu::ColorWrites::ALL, + })], + }), + primitive: wgpu::PrimitiveState::default(), + depth_stencil: None, + multisample: wgpu::MultisampleState::default(), + multiview: None, + }); + + let texture = ctx.device.create_texture(&wgpu::TextureDescriptor { + label: Some("texture"), + size: wgpu::Extent3d { + width: 2, + height: 2, + depth_or_array_layers: 1, + }, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + // Important: NOT srgb. + format: wgpu::TextureFormat::Rgba8Unorm, + usage: wgpu::TextureUsages::COPY_SRC | wgpu::TextureUsages::RENDER_ATTACHMENT, + view_formats: &[], + }); + + let view = texture.create_view(&wgpu::TextureViewDescriptor::default()); + + let mut encoder = ctx + .device + .create_command_encoder(&wgpu::CommandEncoderDescriptor { + label: Some("encoder"), + }); + + { + let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("rpass"), + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: &view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(wgpu::Color::BLACK), + store: wgpu::StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, + }); + + rpass.set_pipeline(&pipeline); + rpass.set_bind_group(0, &bg, &[]); + rpass.set_push_constants( + wgpu::ShaderStages::VERTEX_FRAGMENT, + 0, + bytemuck::cast_slice(&input), + ); + rpass.draw(0..3, 0..1); + } + + let buffers = ReadbackBuffers::new(&ctx.device, &texture); + buffers.copy_from(&ctx.device, &mut encoder, &texture); + ctx.queue.submit([encoder.finish()]); + + let result = input_as_unorm.repeat(4); + buffers.assert_buffer_contents(&ctx.device, &result); +} diff --git a/tests/tests/regression/issue_3349.vs.wgsl b/tests/tests/regression/issue_3349.vs.wgsl new file mode 100644 index 00000000000..85992a756b7 --- /dev/null +++ b/tests/tests/regression/issue_3349.vs.wgsl @@ -0,0 +1,22 @@ +@group(0) @binding(0) +var data1: vec4f; + +// D3DCompile requires this to be a struct +struct Pc { + inner: vec4f, +} + +var data2: Pc; + +struct VsOut { + @builtin(position) position: vec4f, + @location(0) data1: vec4f, + @location(1) data2: vec4f, +} + +@vertex +fn vs_main(@builtin(vertex_index) vertexIndex: u32) -> VsOut { + let uv = vec2f(f32((vertexIndex << 1u) & 2u), f32(vertexIndex & 2u)); + let position = vec4f(uv * 2.0 - 1.0, 0.0, 1.0); + return VsOut(position, data1, data2.inner); +} diff --git a/tests/tests/scissor_tests/mod.rs b/tests/tests/scissor_tests/mod.rs index d53d31cdace..40801a343ad 100644 --- a/tests/tests/scissor_tests/mod.rs +++ b/tests/tests/scissor_tests/mod.rs @@ -94,7 +94,7 @@ fn scissor_test_impl(ctx: &TestingContext, scissor_rect: Rect, expected_data: [u readback_buffer.copy_from(&ctx.device, &mut encoder, &texture); ctx.queue.submit(Some(encoder.finish())); } - assert!(readback_buffer.check_buffer_contents(&ctx.device, &expected_data)); + readback_buffer.assert_buffer_contents(&ctx.device, &expected_data); } #[gpu_test] diff --git a/tests/tests/shader/mod.rs b/tests/tests/shader/mod.rs index a8ca9a27bb2..48800bfb356 100644 --- a/tests/tests/shader/mod.rs +++ b/tests/tests/shader/mod.rs @@ -40,6 +40,8 @@ impl InputStorageType { struct ShaderTest { /// Human readable name name: String, + /// Header text. This is arbitrary code injected at the top of the shader. Replaces {{header}} + header: String, /// This text will be the body of the `Input` struct. Replaces "{{input_members}}" /// in the shader_test shader. custom_struct_members: String, @@ -132,6 +134,7 @@ impl ShaderTest { ) -> Self { Self { name, + header: String::new(), custom_struct_members, body, input_type: String::from("CustomStruct"), @@ -144,6 +147,12 @@ impl ShaderTest { } } + fn header(mut self, header: String) -> Self { + self.header = header; + + self + } + /// Add another set of possible outputs. If any of the given /// output values are seen it's considered a success (i.e. this is OR, not AND). /// @@ -272,6 +281,7 @@ fn shader_input_output_test( // This isn't terribly efficient but the string is short and it's a test. // The body and input members are the longest part, so do them last. let mut processed = source + .replace("{{header}}", &test.header) .replace("{{storage_type}}", storage_type.as_str()) .replace("{{input_type}}", &test.input_type) .replace("{{output_type}}", &test.output_type) diff --git a/tests/tests/shader/shader_test.wgsl b/tests/tests/shader/shader_test.wgsl index efe8692bd5b..91c86365746 100644 --- a/tests/tests/shader/shader_test.wgsl +++ b/tests/tests/shader/shader_test.wgsl @@ -1,3 +1,5 @@ +{{header}} + struct CustomStruct { {{input_members}} } diff --git a/tests/tests/shader/struct_layout.rs b/tests/tests/shader/struct_layout.rs index f17dceac081..a7460b9abdf 100644 --- a/tests/tests/shader/struct_layout.rs +++ b/tests/tests/shader/struct_layout.rs @@ -99,7 +99,7 @@ fn create_struct_layout_tests(storage_type: InputStorageType) -> Vec } } - // https://github.com/gfx-rs/naga/issues/1785 + // https://github.com/gfx-rs/wgpu/issues/4371 let failures = if storage_type == InputStorageType::Uniform && rows == 2 { Backends::GL } else { @@ -171,6 +171,51 @@ fn create_struct_layout_tests(storage_type: InputStorageType) -> Vec } } + // Nested struct and array test. + // + // This tries to exploit all the weird edge cases of the struct layout algorithm. + { + let header = + String::from("struct Inner { scalar: f32, member: array, 2>, scalar2: f32 }"); + let members = String::from("inner: Inner, scalar3: f32, vector: vec3, scalar4: f32"); + let direct = String::from( + "\ + output[0] = bitcast(input.inner.scalar); + output[1] = bitcast(input.inner.member[0].x); + output[2] = bitcast(input.inner.member[0].y); + output[3] = bitcast(input.inner.member[0].z); + output[4] = bitcast(input.inner.member[1].x); + output[5] = bitcast(input.inner.member[1].y); + output[6] = bitcast(input.inner.member[1].z); + output[7] = bitcast(input.inner.scalar2); + output[8] = bitcast(input.scalar3); + output[9] = bitcast(input.vector.x); + output[10] = bitcast(input.vector.y); + output[11] = bitcast(input.vector.z); + output[12] = bitcast(input.scalar4); + ", + ); + + tests.push( + ShaderTest::new( + String::from("nested struct and array"), + members, + direct, + &input_values, + &[ + 0, // inner.scalar + 4, 5, 6, // inner.member[0] + 8, 9, 10, // inner.member[1] + 12, // scalar2 + 16, // scalar3 + 20, 21, 22, // vector + 23, // scalar4 + ], + ) + .header(header), + ); + } + tests } @@ -215,8 +260,7 @@ static PUSH_CONSTANT_INPUT: GpuTestConfiguration = GpuTestConfiguration::new() .limits(Limits { max_push_constant_size: MAX_BUFFER_SIZE as u32, ..Limits::downlevel_defaults() - }) - .expect_fail(FailureCase::backend(Backends::GL)), + }), ) .run_sync(|ctx| { shader_input_output_test( diff --git a/tests/tests/shader_primitive_index/mod.rs b/tests/tests/shader_primitive_index/mod.rs index e5157a7c93f..13ba76a3288 100644 --- a/tests/tests/shader_primitive_index/mod.rs +++ b/tests/tests/shader_primitive_index/mod.rs @@ -192,5 +192,5 @@ fn pulling_common( } readback_buffer.copy_from(&ctx.device, &mut encoder, &color_texture); ctx.queue.submit(Some(encoder.finish())); - assert!(readback_buffer.check_buffer_contents(&ctx.device, expected)); + readback_buffer.assert_buffer_contents(&ctx.device, expected); } diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index 261a148f262..6d1d056b56a 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -96,7 +96,7 @@ rustc-hash = "1.1" log = "0.4" # backend: Gles -glow = { version = "0.13", optional = true } +glow = { version = "0.13", git = "https://github.com/grovesNL/glow.git", rev = "29ff917a2b2ff7ce0a81b2cc5681de6d4735b36e", optional = true } [dependencies.wgt] package = "wgpu-types" @@ -180,7 +180,9 @@ features = ["wgsl-in"] [dev-dependencies] cfg-if = "1" env_logger = "0.10" -winit = { version = "0.29.2", features = [ "android-native-activity" ] } # for "halmark" example +winit = { version = "0.29.2", features = [ + "android-native-activity", +] } # for "halmark" example [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] glutin = "0.29.1" # for "gles" example diff --git a/wgpu-hal/src/dx11/command.rs b/wgpu-hal/src/dx11/command.rs index 17cd5a22d2e..3bbdf0a7eed 100644 --- a/wgpu-hal/src/dx11/command.rs +++ b/wgpu-hal/src/dx11/command.rs @@ -96,7 +96,7 @@ impl crate::CommandEncoder for super::CommandEncoder { &mut self, layout: &super::PipelineLayout, stages: wgt::ShaderStages, - offset: u32, + offset_bytes: u32, data: &[u32], ) { todo!() diff --git a/wgpu-hal/src/dx12/command.rs b/wgpu-hal/src/dx12/command.rs index 719e63a36f0..2e3b78e5222 100644 --- a/wgpu-hal/src/dx12/command.rs +++ b/wgpu-hal/src/dx12/command.rs @@ -911,15 +911,16 @@ impl crate::CommandEncoder for super::CommandEncoder { &mut self, layout: &super::PipelineLayout, _stages: wgt::ShaderStages, - offset: u32, + offset_bytes: u32, data: &[u32], ) { + let offset_words = offset_bytes as usize / 4; + let info = layout.shared.root_constant_info.as_ref().unwrap(); self.pass.root_elements[info.root_index as usize] = super::RootElement::Constant; - self.pass.constant_data[(offset as usize)..(offset as usize + data.len())] - .copy_from_slice(data); + self.pass.constant_data[offset_words..(offset_words + data.len())].copy_from_slice(data); if self.pass.layout.signature == layout.shared.signature { self.pass.dirty_root_elements |= 1 << info.root_index; diff --git a/wgpu-hal/src/empty.rs b/wgpu-hal/src/empty.rs index d0f659f4610..64bcf3109be 100644 --- a/wgpu-hal/src/empty.rs +++ b/wgpu-hal/src/empty.rs @@ -327,7 +327,7 @@ impl crate::CommandEncoder for Encoder { &mut self, layout: &Resource, stages: wgt::ShaderStages, - offset: u32, + offset_bytes: u32, data: &[u32], ) { } diff --git a/wgpu-hal/src/gles/command.rs b/wgpu-hal/src/gles/command.rs index 1234b972921..abbbe8d4274 100644 --- a/wgpu-hal/src/gles/command.rs +++ b/wgpu-hal/src/gles/command.rs @@ -8,7 +8,6 @@ struct TextureSlotDesc { sampler_index: Option, } -#[derive(Default)] pub(super) struct State { topology: u32, primitive: super::PrimitiveState, @@ -30,10 +29,41 @@ pub(super) struct State { instance_vbuf_mask: usize, dirty_vbuf_mask: usize, active_first_instance: u32, - push_offset_to_uniform: ArrayVec, + push_constant_descs: ArrayVec, + // The current state of the push constant data block. + current_push_constant_data: [u32; super::MAX_PUSH_CONSTANTS], end_of_pass_timestamp: Option, } +impl Default for State { + fn default() -> Self { + Self { + topology: Default::default(), + primitive: Default::default(), + index_format: Default::default(), + index_offset: Default::default(), + vertex_buffers: Default::default(), + vertex_attributes: Default::default(), + color_targets: Default::default(), + stencil: Default::default(), + depth_bias: Default::default(), + alpha_to_coverage_enabled: Default::default(), + samplers: Default::default(), + texture_slots: Default::default(), + render_size: Default::default(), + resolve_attachments: Default::default(), + invalidate_attachments: Default::default(), + has_pass_label: Default::default(), + instance_vbuf_mask: Default::default(), + dirty_vbuf_mask: Default::default(), + active_first_instance: Default::default(), + push_constant_descs: Default::default(), + current_push_constant_data: [0; super::MAX_PUSH_CONSTANTS], + end_of_pass_timestamp: Default::default(), + } + } +} + impl super::CommandBuffer { fn clear(&mut self) { self.label = None; @@ -176,10 +206,7 @@ impl super::CommandEncoder { fn set_pipeline_inner(&mut self, inner: &super::PipelineInner) { self.cmd_buffer.commands.push(C::SetProgram(inner.program)); - self.state.push_offset_to_uniform.clear(); - self.state - .push_offset_to_uniform - .extend(inner.uniforms.iter().cloned()); + self.state.push_constant_descs = inner.push_constant_descs.clone(); // rebind textures, if needed let mut dirty_textures = 0u32; @@ -729,24 +756,46 @@ impl crate::CommandEncoder for super::CommandEncoder { &mut self, _layout: &super::PipelineLayout, _stages: wgt::ShaderStages, - start_offset: u32, + offset_bytes: u32, data: &[u32], ) { - let range = self.cmd_buffer.add_push_constant_data(data); - - let end = start_offset + data.len() as u32 * 4; - let mut offset = start_offset; - while offset < end { - let uniform = self.state.push_offset_to_uniform[offset as usize / 4].clone(); - let size = uniform.size; - if uniform.location.is_none() { - panic!("No uniform for push constant"); + // There is nothing preventing the user from trying to update a single value within + // a vector or matrix in the set_push_constant call, as to the user, all of this is + // just memory. However OpenGL does not allow parital uniform updates. + // + // As such, we locally keep a copy of the current state of the push constant memory + // block. If the user tries to update a single value, we have the data to update the entirety + // of the uniform. + let start_words = offset_bytes / 4; + let end_words = start_words + data.len() as u32; + self.state.current_push_constant_data[start_words as usize..end_words as usize] + .copy_from_slice(data); + + // We iterate over the uniform list as there may be multiple uniforms that need + // updating from the same push constant memory (one for each shader stage). + // + // Additionally, any statically unused uniform descs will have been removed from this list + // by OpenGL, so the uniform list is not contiguous. + for uniform in self.state.push_constant_descs.iter().cloned() { + let uniform_size_words = uniform.size_bytes / 4; + let uniform_start_words = uniform.offset / 4; + let uniform_end_words = uniform_start_words + uniform_size_words; + + // Is true if any word within the uniform binding was updated + let needs_updating = + start_words < uniform_end_words || uniform_start_words <= end_words; + + if needs_updating { + let uniform_data = &self.state.current_push_constant_data + [uniform_start_words as usize..uniform_end_words as usize]; + + let range = self.cmd_buffer.add_push_constant_data(uniform_data); + + self.cmd_buffer.commands.push(C::SetPushConstants { + uniform, + offset: range.start, + }); } - self.cmd_buffer.commands.push(C::SetPushConstants { - uniform, - offset: range.start + offset, - }); - offset += size; } } diff --git a/wgpu-hal/src/gles/conv.rs b/wgpu-hal/src/gles/conv.rs index c0ad4054d7c..3fb8383a511 100644 --- a/wgpu-hal/src/gles/conv.rs +++ b/wgpu-hal/src/gles/conv.rs @@ -417,108 +417,6 @@ pub(super) fn map_storage_access(access: wgt::StorageTextureAccess) -> u32 { } } -pub(super) fn is_sampler(glsl_uniform_type: u32) -> bool { - match glsl_uniform_type { - glow::INT_SAMPLER_1D - | glow::INT_SAMPLER_1D_ARRAY - | glow::INT_SAMPLER_2D - | glow::INT_SAMPLER_2D_ARRAY - | glow::INT_SAMPLER_2D_MULTISAMPLE - | glow::INT_SAMPLER_2D_MULTISAMPLE_ARRAY - | glow::INT_SAMPLER_2D_RECT - | glow::INT_SAMPLER_3D - | glow::INT_SAMPLER_CUBE - | glow::INT_SAMPLER_CUBE_MAP_ARRAY - | glow::UNSIGNED_INT_SAMPLER_1D - | glow::UNSIGNED_INT_SAMPLER_1D_ARRAY - | glow::UNSIGNED_INT_SAMPLER_2D - | glow::UNSIGNED_INT_SAMPLER_2D_ARRAY - | glow::UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE - | glow::UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY - | glow::UNSIGNED_INT_SAMPLER_2D_RECT - | glow::UNSIGNED_INT_SAMPLER_3D - | glow::UNSIGNED_INT_SAMPLER_CUBE - | glow::UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY - | glow::SAMPLER_1D - | glow::SAMPLER_1D_SHADOW - | glow::SAMPLER_1D_ARRAY - | glow::SAMPLER_1D_ARRAY_SHADOW - | glow::SAMPLER_2D - | glow::SAMPLER_2D_SHADOW - | glow::SAMPLER_2D_ARRAY - | glow::SAMPLER_2D_ARRAY_SHADOW - | glow::SAMPLER_2D_MULTISAMPLE - | glow::SAMPLER_2D_MULTISAMPLE_ARRAY - | glow::SAMPLER_2D_RECT - | glow::SAMPLER_2D_RECT_SHADOW - | glow::SAMPLER_3D - | glow::SAMPLER_CUBE - | glow::SAMPLER_CUBE_MAP_ARRAY - | glow::SAMPLER_CUBE_MAP_ARRAY_SHADOW - | glow::SAMPLER_CUBE_SHADOW => true, - _ => false, - } -} - -pub(super) fn is_image(glsl_uniform_type: u32) -> bool { - match glsl_uniform_type { - glow::INT_IMAGE_1D - | glow::INT_IMAGE_1D_ARRAY - | glow::INT_IMAGE_2D - | glow::INT_IMAGE_2D_ARRAY - | glow::INT_IMAGE_2D_MULTISAMPLE - | glow::INT_IMAGE_2D_MULTISAMPLE_ARRAY - | glow::INT_IMAGE_2D_RECT - | glow::INT_IMAGE_3D - | glow::INT_IMAGE_CUBE - | glow::INT_IMAGE_CUBE_MAP_ARRAY - | glow::UNSIGNED_INT_IMAGE_1D - | glow::UNSIGNED_INT_IMAGE_1D_ARRAY - | glow::UNSIGNED_INT_IMAGE_2D - | glow::UNSIGNED_INT_IMAGE_2D_ARRAY - | glow::UNSIGNED_INT_IMAGE_2D_MULTISAMPLE - | glow::UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY - | glow::UNSIGNED_INT_IMAGE_2D_RECT - | glow::UNSIGNED_INT_IMAGE_3D - | glow::UNSIGNED_INT_IMAGE_CUBE - | glow::UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY - | glow::IMAGE_1D - | glow::IMAGE_1D_ARRAY - | glow::IMAGE_2D - | glow::IMAGE_2D_ARRAY - | glow::IMAGE_2D_MULTISAMPLE - | glow::IMAGE_2D_MULTISAMPLE_ARRAY - | glow::IMAGE_2D_RECT - | glow::IMAGE_3D - | glow::IMAGE_CUBE - | glow::IMAGE_CUBE_MAP_ARRAY => true, - _ => false, - } -} - -pub(super) fn is_atomic_counter(glsl_uniform_type: u32) -> bool { - glsl_uniform_type == glow::UNSIGNED_INT_ATOMIC_COUNTER -} - -pub(super) fn is_opaque_type(glsl_uniform_type: u32) -> bool { - is_sampler(glsl_uniform_type) - || is_image(glsl_uniform_type) - || is_atomic_counter(glsl_uniform_type) -} - -pub(super) fn uniform_byte_size(glsl_uniform_type: u32) -> u32 { - match glsl_uniform_type { - glow::FLOAT | glow::INT => 4, - glow::FLOAT_VEC2 | glow::INT_VEC2 => 8, - glow::FLOAT_VEC3 | glow::INT_VEC3 => 12, - glow::FLOAT_VEC4 | glow::INT_VEC4 => 16, - glow::FLOAT_MAT2 => 16, - glow::FLOAT_MAT3 => 36, - glow::FLOAT_MAT4 => 64, - _ => panic!("Unsupported uniform datatype! {glsl_uniform_type:#X}"), - } -} - pub(super) fn is_layered_target(target: u32) -> bool { match target { glow::TEXTURE_2D | glow::TEXTURE_CUBE_MAP => false, diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index a0048c5ec29..7934c4be01a 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -23,6 +23,7 @@ struct CompilationContext<'a> { layout: &'a super::PipelineLayout, sampler_map: &'a mut super::SamplerBindMap, name_binding_map: &'a mut NameBindingMap, + push_constant_items: &'a mut Vec, multiview: Option, } @@ -53,7 +54,7 @@ impl CompilationContext<'_> { Some(name) => name.clone(), None => continue, }; - log::debug!( + log::trace!( "Rebind buffer: {:?} -> {}, register={:?}, slot={}", var.name.as_ref(), &name, @@ -101,6 +102,8 @@ impl CompilationContext<'_> { naga::ShaderStage::Compute => {} } } + + *self.push_constant_items = reflection_info.push_constant_items; } } @@ -279,7 +282,7 @@ impl super::Device { unsafe fn create_pipeline<'a>( &self, gl: &glow::Context, - shaders: ArrayVec, 3>, + shaders: ArrayVec, { crate::MAX_CONCURRENT_SHADER_STAGES }>, layout: &super::PipelineLayout, #[cfg_attr(target_arch = "wasm32", allow(unused))] label: Option<&str>, multiview: Option, @@ -327,7 +330,7 @@ impl super::Device { unsafe fn create_program<'a>( gl: &glow::Context, - shaders: ArrayVec, 3>, + shaders: ArrayVec, { crate::MAX_CONCURRENT_SHADER_STAGES }>, layout: &super::PipelineLayout, #[cfg_attr(target_arch = "wasm32", allow(unused))] label: Option<&str>, multiview: Option, @@ -348,16 +351,22 @@ impl super::Device { } let mut name_binding_map = NameBindingMap::default(); + let mut push_constant_items = ArrayVec::<_, { crate::MAX_CONCURRENT_SHADER_STAGES }>::new(); let mut sampler_map = [None; super::MAX_TEXTURE_SLOTS]; let mut has_stages = wgt::ShaderStages::empty(); - let mut shaders_to_delete = arrayvec::ArrayVec::<_, 3>::new(); + let mut shaders_to_delete = ArrayVec::<_, { crate::MAX_CONCURRENT_SHADER_STAGES }>::new(); - for (naga_stage, stage) in shaders { + for &(naga_stage, stage) in &shaders { has_stages |= map_naga_stage(naga_stage); + let pc_item = { + push_constant_items.push(Vec::new()); + push_constant_items.last_mut().unwrap() + }; let context = CompilationContext { layout, sampler_map: &mut sampler_map, name_binding_map: &mut name_binding_map, + push_constant_items: pc_item, multiview, }; @@ -409,6 +418,7 @@ impl super::Device { match register { super::BindingRegister::UniformBuffers => { let index = unsafe { gl.get_uniform_block_index(program, name) }.unwrap(); + log::trace!("\tBinding slot {slot} to block index {index}"); unsafe { gl.uniform_block_binding(program, index, slot as _) }; } super::BindingRegister::StorageBuffers => { @@ -429,41 +439,38 @@ impl super::Device { } } - let mut uniforms: [super::UniformDesc; super::MAX_PUSH_CONSTANTS] = - [None; super::MAX_PUSH_CONSTANTS].map(|_: Option<()>| Default::default()); - let count = unsafe { gl.get_active_uniforms(program) }; - let mut offset = 0; - - for uniform in 0..count { - let glow::ActiveUniform { utype, name, .. } = - unsafe { gl.get_active_uniform(program, uniform) }.unwrap(); - - if conv::is_opaque_type(utype) { - continue; - } - - if let Some(location) = unsafe { gl.get_uniform_location(program, &name) } { - if uniforms[offset / 4].location.is_some() { - panic!("Offset already occupied") + let mut uniforms = ArrayVec::new(); + + for (stage_idx, stage_items) in push_constant_items.into_iter().enumerate() { + for item in stage_items { + let naga_module = &shaders[stage_idx].1.module.naga.module; + let type_inner = &naga_module.types[item.ty].inner; + + let location = unsafe { gl.get_uniform_location(program, &item.access_path) }; + + log::trace!( + "push constant item: name={}, ty={:?}, offset={}, location={:?}", + item.access_path, + type_inner, + item.offset, + location, + ); + + if let Some(location) = location { + uniforms.push(super::PushConstantDesc { + location, + offset: item.offset, + size_bytes: type_inner.size(naga_module.to_ctx()), + ty: type_inner.clone(), + }); } - - // `size` will always be 1 so we need to guess the real size from the type - let uniform_size = conv::uniform_byte_size(utype); - - uniforms[offset / 4] = super::UniformDesc { - location: Some(location), - size: uniform_size, - utype, - }; - - offset += uniform_size as usize; } } Ok(Arc::new(super::PipelineInner { program, sampler_map, - uniforms, + push_constant_descs: uniforms, })) } } diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index bfc55e634f7..0af5ad4a6ed 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -108,6 +108,8 @@ const MAX_SAMPLERS: usize = 16; const MAX_VERTEX_ATTRIBUTES: usize = 16; const ZERO_BUFFER_SIZE: usize = 256 << 10; const MAX_PUSH_CONSTANTS: usize = 64; +// We have to account for each push constant may need to be set for every shader. +const MAX_PUSH_CONSTANT_COMMANDS: usize = MAX_PUSH_CONSTANTS * crate::MAX_CONCURRENT_SHADER_STAGES; impl crate::Api for Api { type Instance = Instance; @@ -483,11 +485,12 @@ struct VertexBufferDesc { stride: u32, } -#[derive(Clone, Debug, Default)] -struct UniformDesc { - location: Option, - size: u32, - utype: u32, +#[derive(Clone, Debug)] +struct PushConstantDesc { + location: glow::UniformLocation, + ty: naga::TypeInner, + offset: u32, + size_bytes: u32, } #[cfg(all( @@ -495,13 +498,13 @@ struct UniformDesc { feature = "fragile-send-sync-non-atomic-wasm", not(target_feature = "atomics") ))] -unsafe impl Sync for UniformDesc {} +unsafe impl Sync for PushConstantDesc {} #[cfg(all( target_arch = "wasm32", feature = "fragile-send-sync-non-atomic-wasm", not(target_feature = "atomics") ))] -unsafe impl Send for UniformDesc {} +unsafe impl Send for PushConstantDesc {} /// For each texture in the pipeline layout, store the index of the only /// sampler (in this layout) that the texture is used with. @@ -510,7 +513,7 @@ type SamplerBindMap = [Option; MAX_TEXTURE_SLOTS]; struct PipelineInner { program: glow::Program, sampler_map: SamplerBindMap, - uniforms: [UniformDesc; MAX_PUSH_CONSTANTS], + push_constant_descs: ArrayVec, } #[derive(Clone, Debug)] @@ -882,7 +885,7 @@ enum Command { PushDebugGroup(Range), PopDebugGroup, SetPushConstants { - uniform: UniformDesc, + uniform: PushConstantDesc, /// Offset from the start of the `data_bytes` offset: u32, }, diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index 6125363aa7b..c395a2004a8 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -1441,64 +1441,235 @@ impl super::Queue { ref uniform, offset, } => { - fn get_data(data: &[u8], offset: u32) -> &[T] { - let raw = &data[(offset as usize)..]; - unsafe { - slice::from_raw_parts( - raw.as_ptr() as *const _, - raw.len() / mem::size_of::(), - ) - } + // T must be POD + // + // This function is absolutely sketchy and we really should be using bytemuck. + unsafe fn get_data(data: &[u8], offset: u32) -> &[T; COUNT] { + let data_required = mem::size_of::() * COUNT; + + let raw = &data[(offset as usize)..][..data_required]; + + debug_assert_eq!(data_required, raw.len()); + + let slice: &[T] = + unsafe { slice::from_raw_parts(raw.as_ptr() as *const _, COUNT) }; + + slice.try_into().unwrap() } - let location = uniform.location.as_ref(); + let location = Some(&uniform.location); - match uniform.utype { - glow::FLOAT => { - let data = get_data::(data_bytes, offset)[0]; + match uniform.ty { + // + // --- Float 1-4 Component --- + // + naga::TypeInner::Scalar { + kind: naga::ScalarKind::Float, + width: 4, + } => { + let data = unsafe { get_data::(data_bytes, offset)[0] }; unsafe { gl.uniform_1_f32(location, data) }; } - glow::FLOAT_VEC2 => { - let data = get_data::<[f32; 2]>(data_bytes, offset)[0]; - unsafe { gl.uniform_2_f32_slice(location, &data) }; + naga::TypeInner::Vector { + kind: naga::ScalarKind::Float, + size: naga::VectorSize::Bi, + width: 4, + } => { + let data = unsafe { get_data::(data_bytes, offset) }; + unsafe { gl.uniform_2_f32_slice(location, data) }; } - glow::FLOAT_VEC3 => { - let data = get_data::<[f32; 3]>(data_bytes, offset)[0]; - unsafe { gl.uniform_3_f32_slice(location, &data) }; + naga::TypeInner::Vector { + kind: naga::ScalarKind::Float, + size: naga::VectorSize::Tri, + width: 4, + } => { + let data = unsafe { get_data::(data_bytes, offset) }; + unsafe { gl.uniform_3_f32_slice(location, data) }; } - glow::FLOAT_VEC4 => { - let data = get_data::<[f32; 4]>(data_bytes, offset)[0]; - unsafe { gl.uniform_4_f32_slice(location, &data) }; + naga::TypeInner::Vector { + kind: naga::ScalarKind::Float, + size: naga::VectorSize::Quad, + width: 4, + } => { + let data = unsafe { get_data::(data_bytes, offset) }; + unsafe { gl.uniform_4_f32_slice(location, data) }; } - glow::INT => { - let data = get_data::(data_bytes, offset)[0]; + + // + // --- Int 1-4 Component --- + // + naga::TypeInner::Scalar { + kind: naga::ScalarKind::Sint, + width: 4, + } => { + let data = unsafe { get_data::(data_bytes, offset)[0] }; unsafe { gl.uniform_1_i32(location, data) }; } - glow::INT_VEC2 => { - let data = get_data::<[i32; 2]>(data_bytes, offset)[0]; - unsafe { gl.uniform_2_i32_slice(location, &data) }; + naga::TypeInner::Vector { + kind: naga::ScalarKind::Sint, + size: naga::VectorSize::Bi, + width: 4, + } => { + let data = unsafe { get_data::(data_bytes, offset) }; + unsafe { gl.uniform_2_i32_slice(location, data) }; + } + naga::TypeInner::Vector { + kind: naga::ScalarKind::Sint, + size: naga::VectorSize::Tri, + width: 4, + } => { + let data = unsafe { get_data::(data_bytes, offset) }; + unsafe { gl.uniform_3_i32_slice(location, data) }; } - glow::INT_VEC3 => { - let data = get_data::<[i32; 3]>(data_bytes, offset)[0]; - unsafe { gl.uniform_3_i32_slice(location, &data) }; + naga::TypeInner::Vector { + kind: naga::ScalarKind::Sint, + size: naga::VectorSize::Quad, + width: 4, + } => { + let data = unsafe { get_data::(data_bytes, offset) }; + unsafe { gl.uniform_4_i32_slice(location, data) }; + } + + // + // --- Uint 1-4 Component --- + // + naga::TypeInner::Scalar { + kind: naga::ScalarKind::Uint, + width: 4, + } => { + let data = unsafe { get_data::(data_bytes, offset)[0] }; + unsafe { gl.uniform_1_u32(location, data) }; } - glow::INT_VEC4 => { - let data = get_data::<[i32; 4]>(data_bytes, offset)[0]; - unsafe { gl.uniform_4_i32_slice(location, &data) }; + naga::TypeInner::Vector { + kind: naga::ScalarKind::Uint, + size: naga::VectorSize::Bi, + width: 4, + } => { + let data = unsafe { get_data::(data_bytes, offset) }; + unsafe { gl.uniform_2_u32_slice(location, data) }; } - glow::FLOAT_MAT2 => { - let data = get_data::<[f32; 4]>(data_bytes, offset)[0]; - unsafe { gl.uniform_matrix_2_f32_slice(location, false, &data) }; + naga::TypeInner::Vector { + kind: naga::ScalarKind::Uint, + size: naga::VectorSize::Tri, + width: 4, + } => { + let data = unsafe { get_data::(data_bytes, offset) }; + unsafe { gl.uniform_3_u32_slice(location, data) }; + } + naga::TypeInner::Vector { + kind: naga::ScalarKind::Uint, + size: naga::VectorSize::Quad, + width: 4, + } => { + let data = unsafe { get_data::(data_bytes, offset) }; + unsafe { gl.uniform_4_u32_slice(location, data) }; + } + + // + // --- Matrix 2xR --- + // + naga::TypeInner::Matrix { + columns: naga::VectorSize::Bi, + rows: naga::VectorSize::Bi, + width: 4, + } => { + let data = unsafe { get_data::(data_bytes, offset) }; + unsafe { gl.uniform_matrix_2_f32_slice(location, false, data) }; + } + naga::TypeInner::Matrix { + columns: naga::VectorSize::Bi, + rows: naga::VectorSize::Tri, + width: 4, + } => { + // repack 2 vec3s into 6 values. + let unpacked_data = unsafe { get_data::(data_bytes, offset) }; + #[rustfmt::skip] + let packed_data = [ + unpacked_data[0], unpacked_data[1], unpacked_data[2], + unpacked_data[4], unpacked_data[5], unpacked_data[6], + ]; + unsafe { gl.uniform_matrix_2x3_f32_slice(location, false, &packed_data) }; + } + naga::TypeInner::Matrix { + columns: naga::VectorSize::Bi, + rows: naga::VectorSize::Quad, + width: 4, + } => { + let data = unsafe { get_data::(data_bytes, offset) }; + unsafe { gl.uniform_matrix_2x4_f32_slice(location, false, data) }; + } + + // + // --- Matrix 3xR --- + // + naga::TypeInner::Matrix { + columns: naga::VectorSize::Tri, + rows: naga::VectorSize::Bi, + width: 4, + } => { + let data = unsafe { get_data::(data_bytes, offset) }; + unsafe { gl.uniform_matrix_3x2_f32_slice(location, false, data) }; + } + naga::TypeInner::Matrix { + columns: naga::VectorSize::Tri, + rows: naga::VectorSize::Tri, + width: 4, + } => { + // repack 3 vec3s into 9 values. + let unpacked_data = unsafe { get_data::(data_bytes, offset) }; + #[rustfmt::skip] + let packed_data = [ + unpacked_data[0], unpacked_data[1], unpacked_data[2], + unpacked_data[4], unpacked_data[5], unpacked_data[6], + unpacked_data[8], unpacked_data[9], unpacked_data[10], + ]; + unsafe { gl.uniform_matrix_3_f32_slice(location, false, &packed_data) }; + } + naga::TypeInner::Matrix { + columns: naga::VectorSize::Tri, + rows: naga::VectorSize::Quad, + width: 4, + } => { + let data = unsafe { get_data::(data_bytes, offset) }; + unsafe { gl.uniform_matrix_3x4_f32_slice(location, false, data) }; + } + + // + // --- Matrix 4xR --- + // + naga::TypeInner::Matrix { + columns: naga::VectorSize::Quad, + rows: naga::VectorSize::Bi, + width: 4, + } => { + let data = unsafe { get_data::(data_bytes, offset) }; + unsafe { gl.uniform_matrix_4x2_f32_slice(location, false, data) }; } - glow::FLOAT_MAT3 => { - let data = get_data::<[f32; 9]>(data_bytes, offset)[0]; - unsafe { gl.uniform_matrix_3_f32_slice(location, false, &data) }; + naga::TypeInner::Matrix { + columns: naga::VectorSize::Quad, + rows: naga::VectorSize::Tri, + width: 4, + } => { + // repack 4 vec3s into 12 values. + let unpacked_data = unsafe { get_data::(data_bytes, offset) }; + #[rustfmt::skip] + let packed_data = [ + unpacked_data[0], unpacked_data[1], unpacked_data[2], + unpacked_data[4], unpacked_data[5], unpacked_data[6], + unpacked_data[8], unpacked_data[9], unpacked_data[10], + unpacked_data[12], unpacked_data[13], unpacked_data[14], + ]; + unsafe { gl.uniform_matrix_4x3_f32_slice(location, false, &packed_data) }; } - glow::FLOAT_MAT4 => { - let data = get_data::<[f32; 16]>(data_bytes, offset)[0]; - unsafe { gl.uniform_matrix_4_f32_slice(location, false, &data) }; + naga::TypeInner::Matrix { + columns: naga::VectorSize::Quad, + rows: naga::VectorSize::Quad, + width: 4, + } => { + let data = unsafe { get_data::(data_bytes, offset) }; + unsafe { gl.uniform_matrix_4_f32_slice(location, false, data) }; } - _ => panic!("Unsupported uniform datatype!"), + _ => panic!("Unsupported uniform datatype: {:?}!", uniform.ty), } } } diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index 2e989499e46..6c8e36ab7ce 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -97,6 +97,9 @@ use bitflags::bitflags; use thiserror::Error; use wgt::{WasmNotSend, WasmNotSync}; +// - Vertex + Fragment +// - Compute +pub const MAX_CONCURRENT_SHADER_STAGES: usize = 2; pub const MAX_ANISOTROPY: u8 = 16; pub const MAX_BIND_GROUPS: usize = 8; pub const MAX_VERTEX_BUFFERS: usize = 16; @@ -500,11 +503,19 @@ pub trait CommandEncoder: WasmNotSend + WasmNotSync + fmt::Debug { dynamic_offsets: &[wgt::DynamicOffset], ); + /// Sets a range in push constant data. + /// + /// IMPORTANT: while the data is passed as words, the offset is in bytes! + /// + /// # Safety + /// + /// - `offset_bytes` must be a multiple of 4. + /// - The range of push constants written must be valid for the pipeline layout at draw time. unsafe fn set_push_constants( &mut self, layout: &A::PipelineLayout, stages: wgt::ShaderStages, - offset: u32, + offset_bytes: u32, data: &[u32], ); diff --git a/wgpu-hal/src/metal/command.rs b/wgpu-hal/src/metal/command.rs index c4b37f99325..0fc8043fe4b 100644 --- a/wgpu-hal/src/metal/command.rs +++ b/wgpu-hal/src/metal/command.rs @@ -798,17 +798,17 @@ impl crate::CommandEncoder for super::CommandEncoder { &mut self, layout: &super::PipelineLayout, stages: wgt::ShaderStages, - offset: u32, + offset_bytes: u32, data: &[u32], ) { let state_pc = &mut self.state.push_constants; if state_pc.len() < layout.total_push_constants as usize { state_pc.resize(layout.total_push_constants as usize, 0); } - assert_eq!(offset as usize % WORD_SIZE, 0); + debug_assert_eq!(offset_bytes as usize % WORD_SIZE, 0); - let offset = offset as usize / WORD_SIZE; - state_pc[offset..offset + data.len()].copy_from_slice(data); + let offset_words = offset_bytes as usize / WORD_SIZE; + state_pc[offset_words..offset_words + data.len()].copy_from_slice(data); if stages.contains(wgt::ShaderStages::COMPUTE) { self.state.compute.as_ref().unwrap().set_bytes( diff --git a/wgpu-hal/src/vulkan/command.rs b/wgpu-hal/src/vulkan/command.rs index 391b754d335..dedc054e6be 100644 --- a/wgpu-hal/src/vulkan/command.rs +++ b/wgpu-hal/src/vulkan/command.rs @@ -600,7 +600,7 @@ impl crate::CommandEncoder for super::CommandEncoder { &mut self, layout: &super::PipelineLayout, stages: wgt::ShaderStages, - offset: u32, + offset_bytes: u32, data: &[u32], ) { unsafe { @@ -608,7 +608,7 @@ impl crate::CommandEncoder for super::CommandEncoder { self.active, layout.raw, conv::map_shader_stage(stages), - offset, + offset_bytes, slice::from_raw_parts(data.as_ptr() as _, data.len() * 4), ) }; diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index d88b48ef735..8eb2935a32b 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -1588,7 +1588,7 @@ impl crate::Device for super::Device { multiview: desc.multiview, ..Default::default() }; - let mut stages = ArrayVec::<_, 2>::new(); + let mut stages = ArrayVec::<_, { crate::MAX_CONCURRENT_SHADER_STAGES }>::new(); let mut vertex_buffers = Vec::with_capacity(desc.vertex_buffers.len()); let mut vertex_attributes = Vec::new(); diff --git a/wgpu/src/backend/direct.rs b/wgpu/src/backend/direct.rs index e705d34e928..28040780686 100644 --- a/wgpu/src/backend/direct.rs +++ b/wgpu/src/backend/direct.rs @@ -1217,7 +1217,7 @@ impl crate::Context for Context { if let Some(cause) = error { if let wgc::pipeline::CreateRenderPipelineError::Internal { stage, ref error } = cause { log::error!("Shader translation error for stage {:?}: {}", stage, error); - log::error!("Please report it to https://github.com/gfx-rs/naga"); + log::error!("Please report it to https://github.com/gfx-rs/wgpu"); } self.handle_error( &device_data.error_sink, @@ -1262,12 +1262,12 @@ impl crate::Context for Context { )); if let Some(cause) = error { if let wgc::pipeline::CreateComputePipelineError::Internal(ref error) = cause { - log::warn!( + log::error!( "Shader translation error for stage {:?}: {}", wgt::ShaderStages::COMPUTE, error ); - log::warn!("Please report it to https://github.com/gfx-rs/naga"); + log::error!("Please report it to https://github.com/gfx-rs/wgpu"); } self.handle_error( &device_data.error_sink, From 261cb7c27dbae75af6a1a7d6cf3e2a6d64e574ea Mon Sep 17 00:00:00 2001 From: Teodor Tanasoaia <28601907+teoxoy@users.noreply.github.com> Date: Mon, 6 Nov 2023 13:39:19 +0100 Subject: [PATCH 03/34] Check if `source` is empty when constructing `hal::DebugSource` --- wgpu-core/src/device/resource.rs | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/wgpu-core/src/device/resource.rs b/wgpu-core/src/device/resource.rs index a2160b9ee5e..d61aa2c5a07 100644 --- a/wgpu-core/src/device/resource.rs +++ b/wgpu-core/src/device/resource.rs @@ -1325,18 +1325,19 @@ impl Device { .contains(wgt::DownlevelFlags::CUBE_ARRAY_TEXTURES), ); - let debug_source = if self.instance_flags.contains(wgt::InstanceFlags::DEBUG) { - Some(hal::DebugSource { - file_name: Cow::Owned( - desc.label - .as_ref() - .map_or("shader".to_string(), |l| l.to_string()), - ), - source_code: Cow::Owned(source.clone()), - }) - } else { - None - }; + let debug_source = + if self.instance_flags.contains(wgt::InstanceFlags::DEBUG) && !source.is_empty() { + Some(hal::DebugSource { + file_name: Cow::Owned( + desc.label + .as_ref() + .map_or("shader".to_string(), |l| l.to_string()), + ), + source_code: Cow::Owned(source.clone()), + }) + } else { + None + }; let info = naga::valid::Validator::new(naga::valid::ValidationFlags::all(), caps) .validate(&module) From 1d4fa812ef4daa706fd986b4d85e11666dc968d3 Mon Sep 17 00:00:00 2001 From: Teodor Tanasoaia <28601907+teoxoy@users.noreply.github.com> Date: Mon, 6 Nov 2023 15:30:04 +0100 Subject: [PATCH 04/34] Gate usage of `metal::ComputePassDescriptor` on timestamp query support (#4643) --- wgpu-hal/src/metal/command.rs | 83 +++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 38 deletions(-) diff --git a/wgpu-hal/src/metal/command.rs b/wgpu-hal/src/metal/command.rs index 0fc8043fe4b..5196e0447d4 100644 --- a/wgpu-hal/src/metal/command.rs +++ b/wgpu-hal/src/metal/command.rs @@ -1104,48 +1104,55 @@ impl crate::CommandEncoder for super::CommandEncoder { let raw = self.raw_cmd_buf.as_ref().unwrap(); objc::rc::autoreleasepool(|| { - let descriptor = metal::ComputePassDescriptor::new(); - - let mut sba_index = 0; - let mut next_sba_descriptor = || { - let sba_descriptor = descriptor - .sample_buffer_attachments() - .object_at(sba_index) - .unwrap(); - sba_index += 1; - sba_descriptor - }; + // TimeStamp Queries and ComputePassDescriptor were both introduced in Metal 2.3 (macOS 11, iOS 14) + // and we currently only need ComputePassDescriptor for timestamp queries + let encoder = if self.shared.private_caps.timestamp_query_support.is_empty() { + raw.new_compute_command_encoder() + } else { + let descriptor = metal::ComputePassDescriptor::new(); + + let mut sba_index = 0; + let mut next_sba_descriptor = || { + let sba_descriptor = descriptor + .sample_buffer_attachments() + .object_at(sba_index) + .unwrap(); + sba_index += 1; + sba_descriptor + }; + + for (set, index) in self.state.pending_timer_queries.drain(..) { + let sba_descriptor = next_sba_descriptor(); + sba_descriptor.set_sample_buffer(set.counter_sample_buffer.as_ref().unwrap()); + sba_descriptor.set_start_of_encoder_sample_index(index as _); + sba_descriptor.set_end_of_encoder_sample_index(metal::COUNTER_DONT_SAMPLE); + } - for (set, index) in self.state.pending_timer_queries.drain(..) { - let sba_descriptor = next_sba_descriptor(); - sba_descriptor.set_sample_buffer(set.counter_sample_buffer.as_ref().unwrap()); - sba_descriptor.set_start_of_encoder_sample_index(index as _); - sba_descriptor.set_end_of_encoder_sample_index(metal::COUNTER_DONT_SAMPLE); - } + if let Some(timestamp_writes) = desc.timestamp_writes.as_ref() { + let sba_descriptor = next_sba_descriptor(); + sba_descriptor.set_sample_buffer( + timestamp_writes + .query_set + .counter_sample_buffer + .as_ref() + .unwrap(), + ); - if let Some(timestamp_writes) = desc.timestamp_writes.as_ref() { - let sba_descriptor = next_sba_descriptor(); - sba_descriptor.set_sample_buffer( - timestamp_writes - .query_set - .counter_sample_buffer - .as_ref() - .unwrap(), - ); + sba_descriptor.set_start_of_encoder_sample_index( + timestamp_writes + .beginning_of_pass_write_index + .map_or(metal::COUNTER_DONT_SAMPLE, |i| i as _), + ); + sba_descriptor.set_end_of_encoder_sample_index( + timestamp_writes + .end_of_pass_write_index + .map_or(metal::COUNTER_DONT_SAMPLE, |i| i as _), + ); + } - sba_descriptor.set_start_of_encoder_sample_index( - timestamp_writes - .beginning_of_pass_write_index - .map_or(metal::COUNTER_DONT_SAMPLE, |i| i as _), - ); - sba_descriptor.set_end_of_encoder_sample_index( - timestamp_writes - .end_of_pass_write_index - .map_or(metal::COUNTER_DONT_SAMPLE, |i| i as _), - ); - } + raw.compute_command_encoder_with_descriptor(descriptor) + }; - let encoder = raw.compute_command_encoder_with_descriptor(descriptor); if let Some(label) = desc.label { encoder.set_label(label); } From 7aaf6725769046bd2ffecd1fceee4efe375a8356 Mon Sep 17 00:00:00 2001 From: Brad Werth Date: Mon, 6 Nov 2023 12:53:31 -0800 Subject: [PATCH 05/34] Ensure that pipeline creation errors register layouts as errors also (#4624) Since the pipeline id is provided by the caller, the caller may presume that an implicit pipeline layout id is also created, even in error conditions such as with an invalid device. Since our registry system will panic if asked to retrieve a pipeline layout id that has never been registered, it's dangerous to leave that id unregistered. This ensures that the layout ids also get error values when the pipeline creation returns an error. --- CHANGELOG.md | 7 +++--- wgpu-core/src/device/global.rs | 43 ++++++++++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 898b83e6b28..7b1190c904a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -73,7 +73,7 @@ By @Zoxc in [#4248](https://github.com/gfx-rs/wgpu/pull/4248) Timestamp queries are now supported on both Metal and Desktop OpenGL. On Apple chips on Metal, they only support timestamp queries in command buffers or in the renderpass descriptor, they do not support them inside a pass. -Metal: By @Wumpf in [#4008](https://github.com/gfx-rs/wgpu/pull/4008) +Metal: By @Wumpf in [#4008](https://github.com/gfx-rs/wgpu/pull/4008) OpenGL: By @Zoxc in [#4267](https://github.com/gfx-rs/wgpu/pull/4267) ### Render/Compute Pass Query Writes @@ -196,7 +196,7 @@ let instance = wgpu::Instance::new(InstanceDescriptor { }); ``` -`gles_minor_version`: By @PJB3005 in [#3998](https://github.com/gfx-rs/wgpu/pull/3998) +`gles_minor_version`: By @PJB3005 in [#3998](https://github.com/gfx-rs/wgpu/pull/3998) `flags`: By @nical in [#4230](https://github.com/gfx-rs/wgpu/pull/4230) ### Many New Examples! @@ -242,7 +242,7 @@ By @teoxoy in [#4185](https://github.com/gfx-rs/wgpu/pull/4185) - Add trace-level logging for most entry points in wgpu-core By @nical in [4183](https://github.com/gfx-rs/wgpu/pull/4183) - Add `Rgb10a2Uint` format. By @teoxoy in [4199](https://github.com/gfx-rs/wgpu/pull/4199) - Validate that resources are used on the right device. By @nical in [4207](https://github.com/gfx-rs/wgpu/pull/4207) -- Expose instance flags. +- Expose instance flags. - Add support for the bgra8unorm-storage feature. By @jinleili and @nical in [#4228](https://github.com/gfx-rs/wgpu/pull/4228) - Calls to lost devices now return `DeviceError::Lost` instead of `DeviceError::Invalid`. By @bradwerth in [#4238]([https://github.com/gfx-rs/wgpu/pull/4238]) - Let the `"strict_asserts"` feature enable check that wgpu-core's lock-ordering tokens are unique per thread. By @jimblandy in [#4258]([https://github.com/gfx-rs/wgpu/pull/4258]) @@ -271,6 +271,7 @@ By @teoxoy in [#4185](https://github.com/gfx-rs/wgpu/pull/4185) - Fix `clear` texture views being leaked when `wgpu::SurfaceTexture` is dropped before it is presented. By @rajveermalviya in [#4057](https://github.com/gfx-rs/wgpu/pull/4057). - Add `Feature::SHADER_UNUSED_VERTEX_OUTPUT` to allow unused vertex shader outputs. By @Aaron1011 in [#4116](https://github.com/gfx-rs/wgpu/pull/4116). - Fix a panic in `surface_configure`. By @nical in [#4220](https://github.com/gfx-rs/wgpu/pull/4220) and [#4227](https://github.com/gfx-rs/wgpu/pull/4227) +- Pipelines register their implicit layouts in error cases. By @bradwerth in [#4624](https://github.com/gfx-rs/wgpu/pull/4624) #### Vulkan diff --git a/wgpu-core/src/device/global.rs b/wgpu-core/src/device/global.rs index d8f1c0f5d04..9c2e51cb1a2 100644 --- a/wgpu-core/src/device/global.rs +++ b/wgpu-core/src/device/global.rs @@ -26,7 +26,9 @@ use wgt::{BufferAddress, TextureFormat}; use std::{borrow::Cow, iter, mem, ops::Range, ptr}; -use super::{BufferMapPendingClosure, ImplicitPipelineIds, InvalidDevice, UserClosures}; +use super::{ + BufferMapPendingClosure, ImplicitPipelineIds, InvalidDevice, UserClosures, IMPLICIT_FAILURE, +}; impl Global { pub fn adapter_is_surface_supported( @@ -1849,6 +1851,7 @@ impl Global { let fid = hub.render_pipelines.prepare(id_in); let implicit_context = implicit_pipeline_ids.map(|ipi| ipi.prepare(hub)); + let implicit_error_context = implicit_context.clone(); let (adapter_guard, mut token) = hub.adapters.read(&mut token); let (device_guard, mut token) = hub.devices.read(&mut token); @@ -1897,6 +1900,24 @@ impl Global { }; let id = fid.assign_error(desc.label.borrow_or_default(), &mut token); + + // We also need to assign errors to the implicit pipeline layout and the + // implicit bind group layout. We have to remove any existing entries first. + let (mut pipeline_layout_guard, mut token) = hub.pipeline_layouts.write(&mut token); + let (mut bgl_guard, _token) = hub.bind_group_layouts.write(&mut token); + if let Some(ref ids) = implicit_error_context { + if pipeline_layout_guard.contains(ids.root_id) { + pipeline_layout_guard.remove(ids.root_id); + } + pipeline_layout_guard.insert_error(ids.root_id, IMPLICIT_FAILURE); + for &bgl_id in ids.group_ids.iter() { + if bgl_guard.contains(bgl_id) { + bgl_guard.remove(bgl_id); + } + bgl_guard.insert_error(bgl_id, IMPLICIT_FAILURE); + } + } + (id, Some(error)) } @@ -2022,6 +2043,7 @@ impl Global { let fid = hub.compute_pipelines.prepare(id_in); let implicit_context = implicit_pipeline_ids.map(|ipi| ipi.prepare(hub)); + let implicit_error_context = implicit_context.clone(); let (device_guard, mut token) = hub.devices.read(&mut token); let error = loop { @@ -2041,7 +2063,6 @@ impl Global { implicit_context: implicit_context.clone(), }); } - let pipeline = match device.create_compute_pipeline( device_id, desc, @@ -2066,6 +2087,24 @@ impl Global { }; let id = fid.assign_error(desc.label.borrow_or_default(), &mut token); + + // We also need to assign errors to the implicit pipeline layout and the + // implicit bind group layout. We have to remove any existing entries first. + let (mut pipeline_layout_guard, mut token) = hub.pipeline_layouts.write(&mut token); + let (mut bgl_guard, _token) = hub.bind_group_layouts.write(&mut token); + if let Some(ref ids) = implicit_error_context { + if pipeline_layout_guard.contains(ids.root_id) { + pipeline_layout_guard.remove(ids.root_id); + } + pipeline_layout_guard.insert_error(ids.root_id, IMPLICIT_FAILURE); + for &bgl_id in ids.group_ids.iter() { + if bgl_guard.contains(bgl_id) { + bgl_guard.remove(bgl_id); + } + bgl_guard.insert_error(bgl_id, IMPLICIT_FAILURE); + } + } + (id, Some(error)) } From ba3d6898f18c25bb5a2b8ba18790134b97758e83 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Nov 2023 12:12:05 +0100 Subject: [PATCH 06/34] Bump serde from 1.0.190 to 1.0.191 (#4646) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.190 to 1.0.191. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.190...v1.0.191) --- updated-dependencies: - dependency-name: serde dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- naga/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a241b78fb70..2711db7c5d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3083,9 +3083,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.190" +version = "1.0.191" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7" +checksum = "a834c4821019838224821468552240d4d95d14e751986442c816572d39a080c9" dependencies = [ "serde_derive", ] @@ -3101,9 +3101,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.190" +version = "1.0.191" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" +checksum = "46fa52d5646bce91b680189fe5b1c049d2ea38dabb4e2e7c8d00ca12cfbfbcfd" dependencies = [ "proc-macro2", "quote", diff --git a/naga/Cargo.toml b/naga/Cargo.toml index eb5fb45f41c..3430e37422e 100644 --- a/naga/Cargo.toml +++ b/naga/Cargo.toml @@ -52,7 +52,7 @@ log = "0.4" num-traits = "0.2" spirv = { version = "0.2", optional = true } thiserror = "1.0.21" -serde = { version = "1.0.103", features = ["derive"], optional = true } +serde = { version = "1.0.191", features = ["derive"], optional = true } petgraph = { version = "0.6", optional = true } pp-rs = { version = "0.2.1", optional = true } hexf-parse = { version = "0.2.1", optional = true } From 01cb63c7585ce1c4b15dbed05c4abeda54b92c39 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Nov 2023 09:46:47 +0100 Subject: [PATCH 07/34] Bump serde from 1.0.191 to 1.0.192 (#4652) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.191 to 1.0.192. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.191...v1.0.192) --- updated-dependencies: - dependency-name: serde dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- naga/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2711db7c5d8..f37593cdd30 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3083,9 +3083,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.191" +version = "1.0.192" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a834c4821019838224821468552240d4d95d14e751986442c816572d39a080c9" +checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" dependencies = [ "serde_derive", ] @@ -3101,9 +3101,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.191" +version = "1.0.192" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46fa52d5646bce91b680189fe5b1c049d2ea38dabb4e2e7c8d00ca12cfbfbcfd" +checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" dependencies = [ "proc-macro2", "quote", diff --git a/naga/Cargo.toml b/naga/Cargo.toml index 3430e37422e..e6616455f41 100644 --- a/naga/Cargo.toml +++ b/naga/Cargo.toml @@ -52,7 +52,7 @@ log = "0.4" num-traits = "0.2" spirv = { version = "0.2", optional = true } thiserror = "1.0.21" -serde = { version = "1.0.191", features = ["derive"], optional = true } +serde = { version = "1.0.192", features = ["derive"], optional = true } petgraph = { version = "0.6", optional = true } pp-rs = { version = "0.2.1", optional = true } hexf-parse = { version = "0.2.1", optional = true } From 5f798002443b67339bf7a4a87cfd5e4d1c83c025 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Nov 2023 09:47:18 +0100 Subject: [PATCH 08/34] Bump getrandom from 0.2.10 to 0.2.11 (#4651) Bumps [getrandom](https://github.com/rust-random/getrandom) from 0.2.10 to 0.2.11. - [Changelog](https://github.com/rust-random/getrandom/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-random/getrandom/compare/v0.2.10...v0.2.11) --- updated-dependencies: - dependency-name: getrandom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- examples/repeated-compute/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f37593cdd30..ce034373fac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1530,9 +1530,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ "cfg-if", "js-sys", diff --git a/examples/repeated-compute/Cargo.toml b/examples/repeated-compute/Cargo.toml index 5e26d020eef..2a50037157c 100644 --- a/examples/repeated-compute/Cargo.toml +++ b/examples/repeated-compute/Cargo.toml @@ -14,7 +14,7 @@ path = "src/main.rs" bytemuck.workspace = true env_logger.workspace = true futures-intrusive.workspace = true -getrandom = { version = "0.2.10", features = ["js"] } +getrandom = { version = "0.2.11", features = ["js"] } log.workspace = true pollster.workspace = true wgpu.workspace = true From 4e65eca1e8629f6ded2e160a094b7a8242eb7e13 Mon Sep 17 00:00:00 2001 From: Brad Werth Date: Wed, 8 Nov 2023 13:22:18 -0800 Subject: [PATCH 09/34] More complete implementation of "lose the device". (#4645) * More complete implementation of "lose the device". This provides a way for wgpu-core to specify a callback on "lose the device". It ensures this callback is called at the appropriate times: either after device.destroy has empty queues, or on demand from device.lose. A test has been added to device.rs. * Updated CHANGELOG.md. * Fix conversion to *const c_char. * Use an allow lint to permit trivial_casts. * rustfmt changes. --- CHANGELOG.md | 2 + tests/tests/device.rs | 32 +++++++++++ wgpu-core/src/device/global.rs | 49 +++++++++------- wgpu-core/src/device/life.rs | 8 ++- wgpu-core/src/device/mod.rs | 98 +++++++++++++++++++++++++++++++- wgpu-core/src/device/resource.rs | 35 +++++++++--- wgpu-types/src/lib.rs | 12 ++++ wgpu/src/backend/direct.rs | 23 +++++++- wgpu/src/backend/web.rs | 16 +++++- wgpu/src/context.rs | 54 ++++++++++++++++-- wgpu/src/lib.rs | 39 ++++++++----- 11 files changed, 316 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b1190c904a..d69de7f0c99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -247,6 +247,8 @@ By @teoxoy in [#4185](https://github.com/gfx-rs/wgpu/pull/4185) - Calls to lost devices now return `DeviceError::Lost` instead of `DeviceError::Invalid`. By @bradwerth in [#4238]([https://github.com/gfx-rs/wgpu/pull/4238]) - Let the `"strict_asserts"` feature enable check that wgpu-core's lock-ordering tokens are unique per thread. By @jimblandy in [#4258]([https://github.com/gfx-rs/wgpu/pull/4258]) - Allow filtering labels out before they are passed to GPU drivers by @nical in [https://github.com/gfx-rs/wgpu/pull/4246](4246) +- `DeviceLostClosure` callback mechanism provided so user agents can resolve `GPUDevice.lost` Promises at the appropriate time by @bradwerth in [#4645](https://github.com/gfx-rs/wgpu/pull/4645) + #### Vulkan diff --git a/tests/tests/device.rs b/tests/tests/device.rs index 108c7cc26a6..2288fd0cb65 100644 --- a/tests/tests/device.rs +++ b/tests/tests/device.rs @@ -448,3 +448,35 @@ static DEVICE_DESTROY_THEN_MORE: GpuTestConfiguration = GpuTestConfiguration::ne buffer_for_unmap.unmap(); }); }); + +#[gpu_test] +static DEVICE_DESTROY_THEN_LOST: GpuTestConfiguration = GpuTestConfiguration::new() + .parameters(TestParameters::default()) + .run_sync(|ctx| { + // This test checks that when device.destroy is called, the provided + // DeviceLostClosure is called with reason DeviceLostReason::Destroyed. + let was_called = std::sync::Arc::::new(false.into()); + + // Set a LoseDeviceCallback on the device. + let was_called_clone = was_called.clone(); + let callback = Box::new(move |reason, _m| { + was_called_clone.store(true, std::sync::atomic::Ordering::SeqCst); + assert!( + matches!(reason, wgt::DeviceLostReason::Destroyed), + "Device lost info reason should match DeviceLostReason::Destroyed." + ); + }); + ctx.device.set_device_lost_callback(callback); + + // Destroy the device. + ctx.device.destroy(); + + // Make sure the device queues are empty, which ensures that the closure + // has been called. + assert!(ctx.device.poll(wgpu::Maintain::Wait)); + + assert!( + was_called.load(std::sync::atomic::Ordering::SeqCst), + "Device lost callback should have been called." + ); + }); diff --git a/wgpu-core/src/device/global.rs b/wgpu-core/src/device/global.rs index 9c2e51cb1a2..c05e25f90dd 100644 --- a/wgpu-core/src/device/global.rs +++ b/wgpu-core/src/device/global.rs @@ -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, @@ -2672,6 +2674,21 @@ impl Global { } } + pub fn device_set_device_lost_closure( + &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(&self, device_id: DeviceId) { log::trace!("Device::destroy {device_id:?}"); @@ -2683,36 +2700,26 @@ impl Global { // 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(&self, device_id: DeviceId, reason: Option<&str>) { - log::trace!("Device::lose {device_id:?}"); + pub fn device_mark_lost(&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); } } diff --git a/wgpu-core/src/device/life.rs b/wgpu-core/src/device/life.rs index e1d01ccaba9..cb8dc43b7ea 100644 --- a/wgpu-core/src/device/life.rs +++ b/wgpu-core/src/device/life.rs @@ -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 { /// 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, } impl LifetimeTracker { @@ -326,6 +331,7 @@ impl LifetimeTracker { free_resources: NonReferencedResources::new(), ready_to_map: Vec::new(), work_done_closures: SmallVec::new(), + device_lost_closure: None, } } diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index eca1375604c..1d89d54796e 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -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, 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; +#[cfg(not(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +)))] +pub type DeviceLostCallback = Box; + +#[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, + ) + }, + } } } diff --git a/wgpu-core/src/device/resource.rs b/wgpu-core/src/device/resource.rs index d61aa2c5a07..3d422a8e285 100644 --- a/wgpu-core/src/device/resource.rs +++ b/wgpu-core/src/device/resource.rs @@ -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 Device { 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())) } @@ -3304,17 +3319,23 @@ impl Device { }) } - 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. diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index ce3ca05e6e1..14f08ef2db8 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -6707,3 +6707,15 @@ mod send_sync { )))] impl 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, +} diff --git a/wgpu/src/backend/direct.rs b/wgpu/src/backend/direct.rs index 28040780686..42ab9cbcd39 100644 --- a/wgpu/src/backend/direct.rs +++ b/wgpu/src/backend/direct.rs @@ -22,6 +22,7 @@ use std::{ sync::Arc, }; use wgc::command::{bundle_ffi::*, compute_ffi::*, render_ffi::*}; +use wgc::device::DeviceLostClosure; use wgc::id::TypedId; use wgt::{WasmNotSend, WasmNotSync}; @@ -1455,14 +1456,30 @@ impl crate::Context for Context { wgc::gfx_select!(device => global.device_drop(*device)); } + fn device_set_device_lost_callback( + &self, + device: &Self::DeviceId, + _device_data: &Self::DeviceData, + device_lost_callback: crate::context::DeviceLostCallback, + ) { + let global = &self.0; + let device_lost_closure = DeviceLostClosure::from_rust(device_lost_callback); + wgc::gfx_select!(device => global.device_set_device_lost_closure(*device, device_lost_closure)); + } fn device_destroy(&self, device: &Self::DeviceId, _device_data: &Self::DeviceData) { let global = &self.0; wgc::gfx_select!(device => global.device_destroy(*device)); } - fn device_lose(&self, device: &Self::DeviceId, _device_data: &Self::DeviceData) { - // TODO: accept a reason, and pass it to device_lose. + fn device_mark_lost( + &self, + device: &Self::DeviceId, + _device_data: &Self::DeviceData, + message: &str, + ) { + // We do not provide a reason to device_lose, because all reasons other than + // destroyed (which this is not) are "unknown". let global = &self.0; - wgc::gfx_select!(device => global.device_lose(*device, None)); + wgc::gfx_select!(device => global.device_mark_lost(*device, message)); } fn device_poll( &self, diff --git a/wgpu/src/backend/web.rs b/wgpu/src/backend/web.rs index f07d6f620a6..30d67d8643e 100644 --- a/wgpu/src/backend/web.rs +++ b/wgpu/src/backend/web.rs @@ -1937,12 +1937,26 @@ impl crate::context::Context for Context { device_data.0.destroy(); } - fn device_lose(&self, _device: &Self::DeviceId, _device_data: &Self::DeviceData) { + fn device_mark_lost( + &self, + _device: &Self::DeviceId, + _device_data: &Self::DeviceData, + _message: &str, + ) { // TODO: figure out the GPUDevice implementation of this, including resolving // the device.lost promise, which will require a different invocation pattern // with a callback. } + fn device_set_device_lost_callback( + &self, + _device: &Self::DeviceId, + _device_data: &Self::DeviceData, + _device_lost_callback: crate::context::DeviceLostCallback, + ) { + unimplemented!(); + } + fn device_poll( &self, _device: &Self::DeviceId, diff --git a/wgpu/src/context.rs b/wgpu/src/context.rs index 52fbe14df33..0d1e95f3b99 100644 --- a/wgpu/src/context.rs +++ b/wgpu/src/context.rs @@ -2,7 +2,7 @@ use std::{any::Any, fmt::Debug, future::Future, num::NonZeroU64, ops::Range, pin use wgt::{ strict_assert, strict_assert_eq, AdapterInfo, BufferAddress, BufferSize, Color, - DownlevelCapabilities, DynamicOffset, Extent3d, Features, ImageDataLayout, + DeviceLostReason, DownlevelCapabilities, DynamicOffset, Extent3d, Features, ImageDataLayout, ImageSubresourceRange, IndexFormat, Limits, ShaderStages, SurfaceStatus, TextureFormat, TextureFormatFeatures, WasmNotSend, WasmNotSync, }; @@ -269,8 +269,19 @@ pub trait Context: Debug + WasmNotSend + WasmNotSync + Sized { desc: &RenderBundleEncoderDescriptor, ) -> (Self::RenderBundleEncoderId, Self::RenderBundleEncoderData); fn device_drop(&self, device: &Self::DeviceId, device_data: &Self::DeviceData); + fn device_set_device_lost_callback( + &self, + device: &Self::DeviceId, + device_data: &Self::DeviceData, + device_lost_callback: DeviceLostCallback, + ); fn device_destroy(&self, device: &Self::DeviceId, device_data: &Self::DeviceData); - fn device_lose(&self, device: &Self::DeviceId, device_data: &Self::DeviceData); + fn device_mark_lost( + &self, + device: &Self::DeviceId, + device_data: &Self::DeviceData, + message: &str, + ); fn device_poll( &self, device: &Self::DeviceId, @@ -1199,6 +1210,22 @@ pub type SubmittedWorkDoneCallback = Box; ) )))] pub type SubmittedWorkDoneCallback = Box; +#[cfg(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +))] +pub type DeviceLostCallback = Box; +#[cfg(not(any( + not(target_arch = "wasm32"), + all( + feature = "fragile-send-sync-non-atomic-wasm", + not(target_feature = "atomics") + ) +)))] +pub type DeviceLostCallback = Box; /// An object safe variant of [`Context`] implemented by all types that implement [`Context`]. pub(crate) trait DynContext: Debug + WasmNotSend + WasmNotSync { @@ -1365,8 +1392,14 @@ pub(crate) trait DynContext: Debug + WasmNotSend + WasmNotSync { desc: &RenderBundleEncoderDescriptor, ) -> (ObjectId, Box); fn device_drop(&self, device: &ObjectId, device_data: &crate::Data); + fn device_set_device_lost_callback( + &self, + device: &ObjectId, + device_data: &crate::Data, + device_lost_callback: DeviceLostCallback, + ); fn device_destroy(&self, device: &ObjectId, device_data: &crate::Data); - fn device_lose(&self, device: &ObjectId, device_data: &crate::Data); + fn device_mark_lost(&self, device: &ObjectId, device_data: &crate::Data, message: &str); fn device_poll(&self, device: &ObjectId, device_data: &crate::Data, maintain: Maintain) -> bool; fn device_on_uncaptured_error( @@ -2428,16 +2461,27 @@ where Context::device_drop(self, &device, device_data) } + fn device_set_device_lost_callback( + &self, + device: &ObjectId, + device_data: &crate::Data, + device_lost_callback: DeviceLostCallback, + ) { + let device = ::from(*device); + let device_data = downcast_ref(device_data); + Context::device_set_device_lost_callback(self, &device, device_data, device_lost_callback) + } + fn device_destroy(&self, device: &ObjectId, device_data: &crate::Data) { let device = ::from(*device); let device_data = downcast_ref(device_data); Context::device_destroy(self, &device, device_data) } - fn device_lose(&self, device: &ObjectId, device_data: &crate::Data) { + fn device_mark_lost(&self, device: &ObjectId, device_data: &crate::Data, message: &str) { let device = ::from(*device); let device_data = downcast_ref(device_data); - Context::device_lose(self, &device, device_data) + Context::device_mark_lost(self, &device, device_data, message) } fn device_poll( diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 6c202a04a96..914e234f1da 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -32,19 +32,19 @@ pub use wgt::{ BindingType, BlendComponent, BlendFactor, BlendOperation, BlendState, BufferAddress, BufferBindingType, BufferSize, BufferUsages, Color, ColorTargetState, ColorWrites, CommandBufferDescriptor, CompareFunction, CompositeAlphaMode, DepthBiasState, - DepthStencilState, DeviceType, DownlevelCapabilities, DownlevelFlags, Dx12Compiler, - DynamicOffset, Extent3d, Face, Features, FilterMode, FrontFace, Gles3MinorVersion, - ImageDataLayout, ImageSubresourceRange, IndexFormat, InstanceDescriptor, InstanceFlags, Limits, - MultisampleState, Origin2d, Origin3d, PipelineStatisticsTypes, PolygonMode, PowerPreference, - PredefinedColorSpace, PresentMode, PresentationTimestamp, PrimitiveState, PrimitiveTopology, - PushConstantRange, QueryType, RenderBundleDepthStencil, SamplerBindingType, SamplerBorderColor, - ShaderLocation, ShaderModel, ShaderStages, StencilFaceState, StencilOperation, StencilState, - StorageTextureAccess, SurfaceCapabilities, SurfaceStatus, TextureAspect, TextureDimension, - TextureFormat, TextureFormatFeatureFlags, TextureFormatFeatures, TextureSampleType, - TextureUsages, TextureViewDimension, VertexAttribute, VertexFormat, VertexStepMode, - WasmNotSend, WasmNotSync, COPY_BUFFER_ALIGNMENT, COPY_BYTES_PER_ROW_ALIGNMENT, MAP_ALIGNMENT, - PUSH_CONSTANT_ALIGNMENT, QUERY_RESOLVE_BUFFER_ALIGNMENT, QUERY_SET_MAX_QUERIES, QUERY_SIZE, - VERTEX_STRIDE_ALIGNMENT, + DepthStencilState, DeviceLostReason, DeviceType, DownlevelCapabilities, DownlevelFlags, + Dx12Compiler, DynamicOffset, Extent3d, Face, Features, FilterMode, FrontFace, + Gles3MinorVersion, ImageDataLayout, ImageSubresourceRange, IndexFormat, InstanceDescriptor, + InstanceFlags, Limits, MultisampleState, Origin2d, Origin3d, PipelineStatisticsTypes, + PolygonMode, PowerPreference, PredefinedColorSpace, PresentMode, PresentationTimestamp, + PrimitiveState, PrimitiveTopology, PushConstantRange, QueryType, RenderBundleDepthStencil, + SamplerBindingType, SamplerBorderColor, ShaderLocation, ShaderModel, ShaderStages, + StencilFaceState, StencilOperation, StencilState, StorageTextureAccess, SurfaceCapabilities, + SurfaceStatus, TextureAspect, TextureDimension, TextureFormat, TextureFormatFeatureFlags, + TextureFormatFeatures, TextureSampleType, TextureUsages, TextureViewDimension, VertexAttribute, + VertexFormat, VertexStepMode, WasmNotSend, WasmNotSync, COPY_BUFFER_ALIGNMENT, + COPY_BYTES_PER_ROW_ALIGNMENT, MAP_ALIGNMENT, PUSH_CONSTANT_ALIGNMENT, + QUERY_RESOLVE_BUFFER_ALIGNMENT, QUERY_SET_MAX_QUERIES, QUERY_SIZE, VERTEX_STRIDE_ALIGNMENT, }; #[cfg(any( @@ -2811,6 +2811,19 @@ impl Device { pub fn destroy(&self) { DynContext::device_destroy(&*self.context, &self.id, self.data.as_ref()) } + + /// Set a DeviceLostCallback on this device. + pub fn set_device_lost_callback( + &self, + callback: impl FnOnce(DeviceLostReason, String) + Send + 'static, + ) { + DynContext::device_set_device_lost_callback( + &*self.context, + &self.id, + self.data.as_ref(), + Box::new(callback), + ) + } } impl Drop for Device { From 1dc5347b141f98392fa012ae3416901faf4249a5 Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Thu, 9 Nov 2023 15:48:06 +0100 Subject: [PATCH 10/34] Better handle destroying textures and buffers (#4657) * Better handle destroying textures and buffers Before this commit, explicitly destroying a texture or a buffer (without dropping it) schedules the asynchronous destruction of its raw resources but does not actually mark it as destroyed. This can cause some incorrect behavior, for example mapping a buffer after destroying it does not cause a validation error (and later panics due to the map callback being dropped without being called). This Commit adds `Storage::take_and_mark_destroyed` for use in `destroy` methods. Since it puts the resource in the error state, other methods properly catch that the resource is no longer usable when attempting to access it and raise validation errors. There are other resource types that require similar treatment and will be addressed in followup work. * Add a changelog entry --- CHANGELOG.md | 1 + tests/tests/gpu.rs | 1 + tests/tests/life_cycle.rs | 63 ++++++++++++++++++++++++++++++++++ wgpu-core/src/device/global.rs | 10 +++--- wgpu-core/src/storage.rs | 15 ++++++++ 5 files changed, 85 insertions(+), 5 deletions(-) create mode 100644 tests/tests/life_cycle.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index d69de7f0c99..ea3d15279ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -274,6 +274,7 @@ By @teoxoy in [#4185](https://github.com/gfx-rs/wgpu/pull/4185) - Add `Feature::SHADER_UNUSED_VERTEX_OUTPUT` to allow unused vertex shader outputs. By @Aaron1011 in [#4116](https://github.com/gfx-rs/wgpu/pull/4116). - Fix a panic in `surface_configure`. By @nical in [#4220](https://github.com/gfx-rs/wgpu/pull/4220) and [#4227](https://github.com/gfx-rs/wgpu/pull/4227) - Pipelines register their implicit layouts in error cases. By @bradwerth in [#4624](https://github.com/gfx-rs/wgpu/pull/4624) +- Better handle explicit destruction of textures and buffers. By @nical in [#4657](https://github.com/gfx-rs/wgpu/pull/4657) #### Vulkan diff --git a/tests/tests/gpu.rs b/tests/tests/gpu.rs index c10df13ed73..efa15df60c5 100644 --- a/tests/tests/gpu.rs +++ b/tests/tests/gpu.rs @@ -16,6 +16,7 @@ mod device; mod encoder; mod external_texture; mod instance; +mod life_cycle; mod occlusion_query; mod partially_bounded_arrays; mod pipeline; diff --git a/tests/tests/life_cycle.rs b/tests/tests/life_cycle.rs new file mode 100644 index 00000000000..1622547bc3d --- /dev/null +++ b/tests/tests/life_cycle.rs @@ -0,0 +1,63 @@ +use wgpu_test::{gpu_test, FailureCase, GpuTestConfiguration, TestParameters}; + +#[gpu_test] +static BUFFER_DESTROY: GpuTestConfiguration = GpuTestConfiguration::new() + .parameters(TestParameters::default().expect_fail(FailureCase::always())) + .run_sync(|ctx| { + let buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor { + label: None, + size: 256, + usage: wgpu::BufferUsages::MAP_WRITE | wgpu::BufferUsages::COPY_SRC, + mapped_at_creation: false, + }); + + buffer.destroy(); + + buffer.destroy(); + + ctx.device.poll(wgpu::MaintainBase::Wait); + + buffer + .slice(..) + .map_async(wgpu::MapMode::Write, move |_| {}); + + buffer.destroy(); + + ctx.device.poll(wgpu::MaintainBase::Wait); + + buffer.destroy(); + + buffer.destroy(); + }); + +#[gpu_test] +static TEXTURE_DESTROY: GpuTestConfiguration = GpuTestConfiguration::new().run_sync(|ctx| { + let texture = ctx.device.create_texture(&wgpu::TextureDescriptor { + label: None, + size: wgpu::Extent3d { + width: 128, + height: 128, + depth_or_array_layers: 1, + }, + mip_level_count: 1, + sample_count: 1, // multisampling is not supported for clear + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Rgba8Snorm, + usage: wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::TEXTURE_BINDING, + view_formats: &[], + }); + + texture.destroy(); + + texture.destroy(); + + ctx.device.poll(wgpu::MaintainBase::Wait); + + texture.destroy(); + + ctx.device.poll(wgpu::MaintainBase::Wait); + + texture.destroy(); + + texture.destroy(); +}); diff --git a/wgpu-core/src/device/global.rs b/wgpu-core/src/device/global.rs index c05e25f90dd..ca6b756a52f 100644 --- a/wgpu-core/src/device/global.rs +++ b/wgpu-core/src/device/global.rs @@ -495,8 +495,8 @@ impl Global { log::trace!("Buffer::destroy {buffer_id:?}"); let (mut buffer_guard, _) = hub.buffers.write(&mut token); - let buffer = buffer_guard - .get_mut(buffer_id) + let mut buffer = buffer_guard + .take_and_mark_destroyed(buffer_id) .map_err(|_| resource::DestroyError::Invalid)?; let device = &mut device_guard[buffer.device_id.value]; @@ -506,7 +506,7 @@ impl Global { | &BufferMapState::Init { .. } | &BufferMapState::Active { .. } => { - self.buffer_unmap_inner(buffer_id, buffer, device) + self.buffer_unmap_inner(buffer_id, &mut buffer, device) .unwrap_or(None) } _ => None, @@ -800,8 +800,8 @@ impl Global { let (mut device_guard, mut token) = hub.devices.write(&mut token); let (mut texture_guard, _) = hub.textures.write(&mut token); - let texture = texture_guard - .get_mut(texture_id) + let mut texture = texture_guard + .take_and_mark_destroyed(texture_id) .map_err(|_| resource::DestroyError::Invalid)?; let device = &mut device_guard[texture.device_id.value]; diff --git a/wgpu-core/src/storage.rs b/wgpu-core/src/storage.rs index 07387b01941..2dcec0d3276 100644 --- a/wgpu-core/src/storage.rs +++ b/wgpu-core/src/storage.rs @@ -169,6 +169,21 @@ impl Storage { self.insert_impl(index as usize, Element::Error(epoch, label.to_string())) } + pub(crate) fn take_and_mark_destroyed(&mut self, id: I) -> Result { + let (index, epoch, _) = id.unzip(); + match std::mem::replace( + &mut self.map[index as usize], + Element::Error(epoch, String::new()), + ) { + Element::Vacant => panic!("Cannot mark a vacant resource destroyed"), + Element::Occupied(value, storage_epoch) => { + assert_eq!(epoch, storage_epoch); + Ok(value) + } + _ => 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); From 890825f395230f79677ab4176b17cc4e78485991 Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Thu, 9 Nov 2023 19:00:23 +0100 Subject: [PATCH 11/34] Don't drop command buffers when submitting in wgpu_core (#4660) Since wgpu's submit API consumes command buffers, they are dropped when submitting via wgpu but not when when using wgpu_core. --- wgpu-core/src/device/queue.rs | 8 +++----- wgpu/src/backend/direct.rs | 5 +++++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/wgpu-core/src/device/queue.rs b/wgpu-core/src/device/queue.rs index a49c8f91f85..92396e6e7c7 100644 --- a/wgpu-core/src/device/queue.rs +++ b/wgpu-core/src/device/queue.rs @@ -1111,12 +1111,10 @@ impl Global { used_surface_textures.set_size(texture_guard.len()); #[allow(unused_mut)] - let mut cmdbuf = match hub - .command_buffers - .unregister_locked(cmb_id, &mut *command_buffer_guard) + let mut cmdbuf = match command_buffer_guard.take_and_mark_destroyed(cmb_id) { - Some(cmdbuf) => cmdbuf, - None => continue, + Ok(cmdbuf) => cmdbuf, + Err(_) => continue, }; if cmdbuf.device_id.value.0 != queue_id { diff --git a/wgpu/src/backend/direct.rs b/wgpu/src/backend/direct.rs index 42ab9cbcd39..1a12a5601ed 100644 --- a/wgpu/src/backend/direct.rs +++ b/wgpu/src/backend/direct.rs @@ -2344,6 +2344,11 @@ impl crate::Context for Context { Ok(index) => index, Err(err) => self.handle_error_fatal(err, "Queue::submit"), }; + + for cmdbuf in &temp_command_buffers { + wgc::gfx_select!(*queue => global.command_buffer_drop(*cmdbuf)); + } + (Unused, index) } From ae48566f25fea7975ac2ebcf6995a5e990b9b6a3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Nov 2023 16:59:46 +0100 Subject: [PATCH 12/34] Bump smallvec from 1.11.1 to 1.11.2 (#4664) Bumps [smallvec](https://github.com/servo/rust-smallvec) from 1.11.1 to 1.11.2. - [Release notes](https://github.com/servo/rust-smallvec/releases) - [Commits](https://github.com/servo/rust-smallvec/compare/v1.11.1...v1.11.2) --- updated-dependencies: - dependency-name: smallvec dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ce034373fac..dcc3798fbf0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3204,9 +3204,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.1" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" [[package]] name = "smithay-client-toolkit" From 951ba61300cc5dd2dacd24655fe33cbb3b3928f6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Nov 2023 17:00:16 +0100 Subject: [PATCH 13/34] Bump tokio from 1.33.0 to 1.34.0 (#4663) Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.33.0 to 1.34.0. - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.33.0...tokio-1.34.0) --- updated-dependencies: - dependency-name: tokio dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dcc3798fbf0..672a71af304 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3492,9 +3492,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.33.0" +version = "1.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653" +checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" dependencies = [ "backtrace", "bytes", @@ -3511,9 +3511,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 07a2793307c..21dc5f5bf0e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -171,7 +171,7 @@ deno_url = "0.119.0" deno_web = "0.150.0" deno_webidl = "0.119.0" deno_webgpu = { version = "0.85.0", path = "./deno_webgpu" } -tokio = "1.33.0" +tokio = "1.34.0" termcolor = "1.3.0" [patch."https://github.com/gfx-rs/naga"] From 2e7fd75712bfaacdaaa5538204cfe8b9360f82ca Mon Sep 17 00:00:00 2001 From: Westerbly Snaydley Date: Fri, 10 Nov 2023 12:09:42 -0500 Subject: [PATCH 14/34] vk: Enable FifoRelaxed PresentMode (#4666) --- wgpu-hal/src/vulkan/conv.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/wgpu-hal/src/vulkan/conv.rs b/wgpu-hal/src/vulkan/conv.rs index 71b8a877c9b..c27fdf9f72f 100644 --- a/wgpu-hal/src/vulkan/conv.rs +++ b/wgpu-hal/src/vulkan/conv.rs @@ -451,8 +451,7 @@ pub fn map_vk_present_mode(mode: vk::PresentModeKHR) -> Option } 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 From 406119ff71d88561ec532ff52323c1c4f04dd11f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Nov 2023 10:14:42 -0500 Subject: [PATCH 15/34] Bump env_logger from 0.10.0 to 0.10.1 (#4674) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 672a71af304..c356659ec1b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1221,9 +1221,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" dependencies = [ "humantime", "is-terminal", From f7420511d041a886a34391781a65dd45c70af4d4 Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Mon, 13 Nov 2023 20:04:35 +0100 Subject: [PATCH 16/34] rename/deprecate block_size -> block_copy_size, improve docs (#4647) Co-authored-by: Teodor Tanasoaia <28601907+teoxoy@users.noreply.github.com> --- CHANGELOG.md | 1 + tests/src/image.rs | 12 ++++---- .../tests/zero_init_texture_after_discard.rs | 2 +- wgpu-core/src/command/clear.rs | 2 +- wgpu-core/src/command/transfer.rs | 2 +- wgpu-core/src/device/queue.rs | 2 +- wgpu-hal/src/dx12/command.rs | 2 +- wgpu-hal/src/gles/queue.rs | 4 +-- wgpu-hal/src/vulkan/command.rs | 2 +- wgpu-types/src/lib.rs | 28 +++++++++++++++++-- wgpu/src/util/device.rs | 2 +- 11 files changed, 41 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea3d15279ad..a7afe0a78fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,7 @@ For naga changelogs at or before v0.14.0. See [naga's changelog](naga/CHANGELOG. #### General - Log vulkan validation layer messages during instance creation and destruction: By @exrook in [#4586](https://github.com/gfx-rs/wgpu/pull/4586) +- `TextureFormat::block_size` is deprecated, use `TextureFormat::block_copy_size` instead: By @wumpf in [#4647](https://github.com/gfx-rs/wgpu/pull/4647) ### Bug Fixes diff --git a/tests/src/image.rs b/tests/src/image.rs index 66f6abf16a1..ee8fa941875 100644 --- a/tests/src/image.rs +++ b/tests/src/image.rs @@ -388,7 +388,7 @@ fn copy_texture_to_buffer_with_aspect( aspect: TextureAspect, ) { let (block_width, block_height) = texture.format().block_dimensions(); - let block_size = texture.format().block_size(Some(aspect)).unwrap(); + let block_size = texture.format().block_copy_size(Some(aspect)).unwrap(); let bytes_per_row = align_to( (texture.width() / block_width) * block_size, COPY_BYTES_PER_ROW_ALIGNMENT, @@ -501,7 +501,7 @@ impl ReadbackBuffers { let mut buffer_depth_bytes_per_row = (texture.width() / block_width) * texture .format() - .block_size(Some(TextureAspect::DepthOnly)) + .block_copy_size(Some(TextureAspect::DepthOnly)) .unwrap_or(4); if should_align_buffer_size { buffer_depth_bytes_per_row = @@ -515,7 +515,7 @@ impl ReadbackBuffers { (texture.width() / block_width) * texture .format() - .block_size(Some(TextureAspect::StencilOnly)) + .block_copy_size(Some(TextureAspect::StencilOnly)) .unwrap_or(4), COPY_BYTES_PER_ROW_ALIGNMENT, ); @@ -542,8 +542,8 @@ impl ReadbackBuffers { buffer_stencil: Some(buffer_stencil), } } else { - let mut bytes_per_row = - (texture.width() / block_width) * texture.format().block_size(None).unwrap_or(4); + let mut bytes_per_row = (texture.width() / block_width) + * texture.format().block_copy_size(None).unwrap_or(4); if should_align_buffer_size { bytes_per_row = align_to(bytes_per_row, COPY_BYTES_PER_ROW_ALIGNMENT); } @@ -581,7 +581,7 @@ impl ReadbackBuffers { device.poll(Maintain::Wait); let (block_width, block_height) = self.texture_format.block_dimensions(); let expected_bytes_per_row = (self.texture_width / block_width) - * self.texture_format.block_size(aspect).unwrap_or(4); + * self.texture_format.block_copy_size(aspect).unwrap_or(4); let expected_buffer_size = expected_bytes_per_row * (self.texture_height / block_height) * self.texture_depth_or_array_layers; diff --git a/tests/tests/zero_init_texture_after_discard.rs b/tests/tests/zero_init_texture_after_discard.rs index 584cfdb7b87..82d6ba85d5c 100644 --- a/tests/tests/zero_init_texture_after_discard.rs +++ b/tests/tests/zero_init_texture_after_discard.rs @@ -167,7 +167,7 @@ impl<'ctx> TestCase<'ctx> { }); ctx.queue.submit([encoder.finish()]); } else { - let block_size = format.block_size(None).unwrap(); + let block_size = format.block_copy_size(None).unwrap(); let bytes_per_row = texture.width() * block_size; // Size for tests is chosen so that we don't need to care about buffer alignments. diff --git a/wgpu-core/src/command/clear.rs b/wgpu-core/src/command/clear.rs index 1481dbe1e6f..214060a2953 100644 --- a/wgpu-core/src/command/clear.rs +++ b/wgpu-core/src/command/clear.rs @@ -331,7 +331,7 @@ fn clear_texture_via_buffer_copies( 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); diff --git a/wgpu-core/src/command/transfer.rs b/wgpu-core/src/command/transfer.rs index 10eb80f426d..86c52d11ee0 100644 --- a/wgpu-core/src/command/transfer.rs +++ b/wgpu-core/src/command/transfer.rs @@ -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; diff --git a/wgpu-core/src/device/queue.rs b/wgpu-core/src/device/queue.rs index 92396e6e7c7..31fbd973bf5 100644 --- a/wgpu-core/src/device/queue.rs +++ b/wgpu-core/src/device/queue.rs @@ -697,7 +697,7 @@ impl Global { 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); diff --git a/wgpu-hal/src/dx12/command.rs b/wgpu-hal/src/dx12/command.rs index 2e3b78e5222..2ea6ad4ab27 100644 --- a/wgpu-hal/src/dx12/command.rs +++ b/wgpu-hal/src/dx12/command.rs @@ -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 }); diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index c395a2004a8..5e345421ce6 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -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; diff --git a/wgpu-hal/src/vulkan/command.rs b/wgpu-hal/src/vulkan/command.rs index dedc054e6be..52226f34ebd 100644 --- a/wgpu-hal/src/vulkan/command.rs +++ b/wgpu-hal/src/vulkan/command.rs @@ -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) }), diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 14f08ef2db8..81a9c1eca5a 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -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) -> Option { + 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) -> Option { match *self { Self::R8Unorm | Self::R8Snorm | Self::R8Uint | Self::R8Sint => Some(1), diff --git a/wgpu/src/util/device.rs b/wgpu/src/util/device.rs index 2d6f0ed7fe8..f8e02421eb2 100644 --- a/wgpu/src/util/device.rs +++ b/wgpu/src/util/device.rs @@ -88,7 +88,7 @@ impl DeviceExt for crate::Device { // Will return None only if it's a combined depth-stencil format // If so, default to 4, validation will fail later anyway since the depth or stencil // aspect needs to be written to individually - let block_size = desc.format.block_size(None).unwrap_or(4); + let block_size = desc.format.block_copy_size(None).unwrap_or(4); let (block_width, block_height) = desc.format.block_dimensions(); let layer_iterations = desc.array_layer_count(); From d9b3ffde72bd4afb9742ccab4e79e96d40a2ea66 Mon Sep 17 00:00:00 2001 From: felix sanchez <52932708+fezro@users.noreply.github.com> Date: Mon, 13 Nov 2023 13:17:54 -0600 Subject: [PATCH 17/34] add new line in readme (#4672) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4a560af49dc..e8df5f5ec2f 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ We have a [wiki](https://github.com/gfx-rs/wgpu/wiki) that serves as a knowledge :white_check_mark: = First Class Support :ok: = Downlevel/Best Effort Support -:triangular_ruler: = Requires the [ANGLE](#angle) translation layer (GL ES 3.0 only) +:triangular_ruler: = Requires the [ANGLE](#angle) translation layer (GL ES 3.0 only) :volcano: = Requires the [MoltenVK](https://vulkan.lunarg.com/sdk/home#mac) translation layer :hammer_and_wrench: = Unsupported, though open to contributions From 049cb759765165847fb09bdf40233986fff3571d Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Mon, 13 Nov 2023 14:23:32 -0800 Subject: [PATCH 18/34] [wgpu-test] Fix typo in error message. --- tests/src/native.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/src/native.rs b/tests/src/native.rs index 8c3dd2fb192..2d0fc7c7eea 100644 --- a/tests/src/native.rs +++ b/tests/src/native.rs @@ -82,7 +82,7 @@ pub fn main() -> MainResult { &std::fs::read_to_string(format!("{}/../.gpuconfig", env!("CARGO_MANIFEST_DIR"))) .context("Failed to read .gpuconfig, did you run the tests via `cargo xtask test`?")? }; - let report = GpuReport::from_json(config_text).context("Could not pare .gpuconfig JSON")?; + let report = GpuReport::from_json(config_text).context("Could not parse .gpuconfig JSON")?; let mut test_guard = TEST_LIST.lock(); execute_native(test_guard.drain(..).flat_map(|test| { From 9f91c95c2480bec1dfc76c239a4d23498ca14c8f Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Fri, 10 Nov 2023 12:31:29 -0800 Subject: [PATCH 19/34] [naga] Introduce `Scalar` type to IR. Introduce a new struct type, `Scalar`, combining a `ScalarKind` and a `Bytes` width, and use this whenever such pairs of values are passed around. In particular, use `Scalar` in `TypeInner` variants `Scalar`, `Vector`, `Atomic`, and `ValuePointer`. Introduce associated `Scalar` constants `I32`, `U32`, `F32`, `BOOL` and `F64`, for common cases. Introduce a helper function `Scalar::float` for constructing `Float` scalars of a given width, for dealing with `TypeInner::Matrix`, which only supplies the scalar width of its elements, not a kind. Introduce helper functions on `Literal` and `TypeInner`, to produce the `Scalar` describing elements' values. Use `Scalar` in `wgpu_core::validation::NumericType` as well. --- CHANGELOG.md | 4 + naga/src/back/glsl/features.rs | 14 +- naga/src/back/glsl/mod.rs | 133 ++-- naga/src/back/hlsl/conv.rs | 24 +- naga/src/back/hlsl/help.rs | 12 +- naga/src/back/hlsl/mod.rs | 4 +- naga/src/back/hlsl/storage.rs | 32 +- naga/src/back/hlsl/writer.rs | 43 +- naga/src/back/msl/writer.rs | 185 +++--- naga/src/back/spv/block.rs | 179 ++--- naga/src/back/spv/image.rs | 59 +- naga/src/back/spv/mod.rs | 27 +- naga/src/back/spv/ray.rs | 25 +- naga/src/back/spv/writer.rs | 76 +-- naga/src/back/wgsl/writer.rs | 79 ++- naga/src/compact/types.rs | 4 +- naga/src/front/glsl/builtins.rs | 402 +++++------ naga/src/front/glsl/context.rs | 110 ++- naga/src/front/glsl/functions.rs | 208 +++--- naga/src/front/glsl/offset.rs | 9 +- naga/src/front/glsl/parser/declarations.rs | 27 +- naga/src/front/glsl/parser_tests.rs | 7 +- naga/src/front/glsl/types.rs | 64 +- naga/src/front/glsl/variables.rs | 36 +- naga/src/front/spv/image.rs | 15 +- naga/src/front/spv/mod.rs | 76 +-- naga/src/front/type_gen.rs | 73 +- naga/src/front/wgsl/lower/construction.rs | 43 +- naga/src/front/wgsl/lower/mod.rs | 58 +- naga/src/front/wgsl/mod.rs | 52 +- naga/src/front/wgsl/parse/mod.rs | 50 +- naga/src/lib.rs | 31 +- naga/src/proc/constant_evaluator.rs | 127 ++-- naga/src/proc/layouter.rs | 9 +- naga/src/proc/mod.rs | 128 ++-- naga/src/proc/typifier.rs | 239 +++---- naga/src/valid/analyzer.rs | 7 +- naga/src/valid/compose.rs | 15 +- naga/src/valid/expression.rs | 400 ++++++----- naga/src/valid/function.rs | 44 +- naga/src/valid/handles.rs | 5 +- naga/src/valid/interface.rs | 74 +-- naga/src/valid/mod.rs | 29 +- naga/src/valid/type.rs | 43 +- naga/tests/out/analysis/access.info.ron | 736 +++++++++++++-------- naga/tests/out/analysis/collatz.info.ron | 48 +- naga/tests/out/analysis/shadow.info.ron | 260 ++++---- naga/tests/out/ir/access.compact.ron | 40 +- naga/tests/out/ir/access.ron | 58 +- naga/tests/out/ir/collatz.compact.ron | 10 +- naga/tests/out/ir/collatz.ron | 10 +- naga/tests/out/ir/shadow.compact.ron | 36 +- naga/tests/out/ir/shadow.ron | 40 +- wgpu-core/src/validation.rs | 114 ++-- wgpu-hal/src/gles/queue.rs | 42 +- 55 files changed, 2353 insertions(+), 2322 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a7afe0a78fc..3ea3dcbb58e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,10 @@ For naga changelogs at or before v0.14.0. See [naga's changelog](naga/CHANGELOG. - Log vulkan validation layer messages during instance creation and destruction: By @exrook in [#4586](https://github.com/gfx-rs/wgpu/pull/4586) - `TextureFormat::block_size` is deprecated, use `TextureFormat::block_copy_size` instead: By @wumpf in [#4647](https://github.com/gfx-rs/wgpu/pull/4647) +#### Naga + +- Introduce a new `Scalar` struct type for use in Naga's IR, and update all frontend, middle, and backend code appropriately. By @jimblandy in [#4673](https://github.com/gfx-rs/wgpu/pull/4673). + ### Bug Fixes #### WGL diff --git a/naga/src/back/glsl/features.rs b/naga/src/back/glsl/features.rs index d6f3aae35d9..cbcd9123ec6 100644 --- a/naga/src/back/glsl/features.rs +++ b/naga/src/back/glsl/features.rs @@ -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); } } diff --git a/naga/src/back/glsl/mod.rs b/naga/src/back/glsl/mod.rs index b33c904f305..2ecb421d4db 100644 --- a/naga/src/back/glsl/mod.rs +++ b/naga/src/back/glsl/mod.rs @@ -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) -> 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, Error> { +const fn glsl_scalar(scalar: crate::Scalar) -> Result, 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", diff --git a/naga/src/back/hlsl/conv.rs b/naga/src/back/hlsl/conv.rs index 19bde6926a8..ca84ab5a057 100644 --- a/naga/src/back/hlsl/conv.rs +++ b/naga/src/back/hlsl/conv.rs @@ -13,21 +13,23 @@ impl crate::ScalarKind { Self::Bool => unreachable!(), } } +} +impl crate::Scalar { /// Helper function that returns scalar related strings /// /// - 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, ) -> Result, 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), )), diff --git a/naga/src/back/hlsl/help.rs b/naga/src/back/hlsl/help.rs index fcb9949fe15..ac0ce6740d6 100644 --- a/naga/src/back/hlsl/help.rs +++ b/naga/src/back/hlsl/help.rs @@ -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)?; diff --git a/naga/src/back/hlsl/mod.rs b/naga/src/back/hlsl/mod.rs index f3a6f9106c2..37ddbd3d675 100644 --- a/naga/src/back/hlsl/mod.rs +++ b/naga/src/back/hlsl/mod.rs @@ -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}")] diff --git a/naga/src/back/hlsl/storage.rs b/naga/src/back/hlsl/storage.rs index 1e02e9e5026..24389074e0b 100644 --- a/naga/src/back/hlsl/storage.rs +++ b/naga/src/back/hlsl/storage.rs @@ -157,25 +157,21 @@ impl 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 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 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 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 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 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 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 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!(), }; diff --git a/naga/src/back/hlsl/writer.rs b/naga/src/back/hlsl/writer.rs index f26604476a7..dc618055680 100644 --- a/naga/src/back/hlsl/writer.rs +++ b/naga/src/back/hlsl/writer.rs @@ -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, "))")?; diff --git a/naga/src/back/msl/writer.rs b/naga/src/back/msl/writer.rs index d93ad650623..5e36949fe0e 100644 --- a/naga/src/back/msl/writer.rs +++ b/naga/src/back/msl/writer.rs @@ -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 { struct_member_pads: FastHashSet<(Handle, 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 { +) -> Option { 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, - ) -> Option { + fn get_packed_vec_kind(&self, expr_handle: Handle) -> Option { match self.function.expressions[expr_handle] { crate::Expression::AccessIndex { base, index } => { let ty = match *self.resolve_type(base) { @@ -673,7 +681,8 @@ impl Writer { 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 Writer { ) -> 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 Writer { }; 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 Writer { } } 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 Writer { 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 Writer { } } crate::TypeInner::Vector { - kind: crate::ScalarKind::Bool, + scalar: + crate::Scalar { + kind: crate::ScalarKind::Bool, + .. + }, .. } => { write!(self.out, "{NAMESPACE}::select(")?; @@ -1687,7 +1700,7 @@ impl Writer { 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 Writer { // 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 Writer { // 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 Writer { 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 Writer { 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 Writer { 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 Writer { // 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 Writer { }; 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 Writer { // 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 Writer { // 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; } } } diff --git a/naga/src/back/spv/block.rs b/naga/src/back/spv/block.rs index 0471d957f04..db480dab4d1 100644 --- a/naga/src/back/spv/block.rs +++ b/naga/src/back/spv/block.rs @@ -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, })); diff --git a/naga/src/back/spv/image.rs b/naga/src/back/spv/image.rs index 1630dc0ddbc..fb9d44e7f07 100644 --- a/naga/src/back/spv/image.rs +++ b/naga/src/back/spv/image.rs @@ -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(); diff --git a/naga/src/back/spv/mod.rs b/naga/src/back/spv/mod.rs index ac7281fc6b4..bfa6e613fa0 100644 --- a/naga/src/back/spv/mod.rs +++ b/naga/src/back/spv/mod.rs @@ -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, - kind: crate::ScalarKind, - width: crate::Bytes, + scalar: crate::Scalar, pointer_space: Option, }, /// A matrix of floating-point values. @@ -355,18 +354,14 @@ struct LookupFunctionType { fn make_local(inner: &crate::TypeInner) -> Option { 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 { }, 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 { diff --git a/naga/src/back/spv/ray.rs b/naga/src/back/spv/ray.rs index ed61129f929..bc2c4ce3c62 100644 --- a/naga/src/back/spv/ray.rs +++ b/naga/src/back/spv/ray.rs @@ -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, 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( diff --git a/naga/src/back/spv/writer.rs b/naga/src/back/spv/writer.rs index 24cb14a1614..b977b757a1f 100644 --- a/naga/src/back/spv/writer.rs +++ b/naga/src/back/spv/writer.rs @@ -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 { 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, }, diff --git a/naga/src/back/wgsl/writer.rs b/naga/src/back/wgsl/writer.rs index 075d85558cc..2a398e8845a 100644 --- a/naga/src/back/wgsl/writer.rs +++ b/naga/src/back/wgsl/writer.rs @@ -426,11 +426,11 @@ impl Writer { /// 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 Writer { 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 Writer { 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, @@ -552,13 +552,12 @@ impl Writer { } 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 Writer { } TypeInner::ValuePointer { size: Some(size), - kind, - width, + scalar, space, } => { let (address, maybe_access) = address_space_str(space); @@ -582,7 +580,7 @@ impl Writer { "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 Writer { 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 Writer { 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>")?; } } - 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!(), } } diff --git a/naga/src/compact/types.rs b/naga/src/compact/types.rs index d11ab8a7310..3314919cd7e 100644 --- a/naga/src/compact/types.rs +++ b/naga/src/compact/types.rs @@ -54,10 +54,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 { .. } diff --git a/naga/src/front/glsl/builtins.rs b/naga/src/front/glsl/builtins.rs index c68370645cd..0b01204dac3 100644 --- a/naga/src/front/glsl/builtins.rs +++ b/naga/src/front/glsl/builtins.rs @@ -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 ty = || TypeInner::Vector { size, kind, width }; + 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, 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 width = if let Sk::Bool = kind { - crate::BOOL_WIDTH - } else { - width - }; - - let ty = || TypeInner::Vector { size, kind, width }; + 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 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,18 @@ fn inject_common_builtin( _ => unreachable!(), }; - let second_kind = if fun == MacroCall::MathFunction(MathFunction::Ldexp) { - Sk::Sint + let second_scalar = if fun == MacroCall::MathFunction(MathFunction::Ldexp) { + Scalar { + kind: Sk::Sint, + width: float_width, + } } else { - Sk::Float + float_scalar }; declaration .overloads - .push(module.add_builtin(vec![ty(Sk::Float), ty(second_kind)], fun)) + .push(module.add_builtin(vec![ty(Scalar::F32), ty(second_scalar)], fun)) } } "transpose" => { @@ -1389,13 +1338,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 +1359,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 +1390,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 +1417,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 +1446,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 +1475,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 +1729,7 @@ impl MacroCall { name: None, inner: TypeInner::Vector { size, - kind: crate::ScalarKind::Uint, - width: 4, + scalar: Scalar::U32, }, }, Span::default(), @@ -2100,7 +2018,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( diff --git a/naga/src/front/glsl/context.rs b/naga/src/front/glsl/context.rs index a54e718aa9c..b683ec00862 100644 --- a/naga/src/front/glsl/context.rs +++ b/naga/src/front/glsl/context.rs @@ -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, meta: Span, - ) -> Result> { + ) -> Result> { 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, meta: Span) -> Result> { 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, 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, 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, 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)?; } } } diff --git a/naga/src/front/glsl/functions.rs b/naga/src/front/glsl/functions.rs index 8bbef9162d8..fce097e97f5 100644 --- a/naga/src/front/glsl/functions.rs +++ b/naga/src/front/glsl/functions.rs @@ -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, /// An optional conversion to be applied - convert: Option<(ScalarKind, crate::Bytes)>, + convert: Option, } 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, size: crate::VectorSize, - kind: ScalarKind, - width: crate::Bytes, + scalar: Scalar, args: &[(Handle, Span)], meta: Span, ) -> Result> { 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 { 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,63 @@ fn conversion(target: &TypeInner, source: &TypeInner) -> Option { 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 { + kind: Float, + width: tgt_width, + }, + Scalar { + kind: Float, + width: 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 { + kind: Float, + width: 8, + }, + Scalar { + kind: Float, + width: 4, + }, + ) => Conversion::FloatToDouble, + // A conversion from an integer to a float is special + ( + Scalar { + kind: Float, + width: 4, + }, + Scalar { + kind: Sint | Uint, + width: _, + }, + ) => Conversion::IntToFloat, + // A conversion from an integer to a double is special + ( + Scalar { + kind: Float, + width: 8, + }, + Scalar { + kind: Sint | Uint, + width: _, + }, + ) => Conversion::IntToDouble, + _ => Conversion::Other, + }) } /// Helper method returning all the non standard builtin variations needed @@ -1581,10 +1605,10 @@ fn builtin_required_variations<'a>(args: impl Iterator) -> 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.kind == ScalarKind::Float && scalar.width == 8 { variations |= BuiltinVariations::DOUBLE } } diff --git a/naga/src/front/glsl/offset.rs b/naga/src/front/glsl/offset.rs index 2d41778522a..56b20f5246e 100644 --- a/naga/src/front/glsl/offset.rs +++ b/naga/src/front/glsl/offset.rs @@ -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, ), diff --git a/naga/src/front/glsl/parser/declarations.rs b/naga/src/front/glsl/parser/declarations.rs index 02ee2bedea4..961c6d832a2 100644 --- a/naga/src/front/glsl/parser/declarations.rs +++ b/naga/src/front/glsl/parser/declarations.rs @@ -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 { 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,10 @@ fn element_or_member_type( name: None, inner: TypeInner::Vector { size: rows, - kind: ScalarKind::Float, - width, + scalar: Scalar { + kind: ScalarKind::Float, + width, + }, }, }, Default::default(), @@ -156,8 +158,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 +235,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 +510,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(), diff --git a/naga/src/front/glsl/parser_tests.rs b/naga/src/front/glsl/parser_tests.rs index 1813a4ce49d..0f4fbab22fe 100644 --- a/naga/src/front/glsl/parser_tests.rs +++ b/naga/src/front/glsl/parser_tests.rs @@ -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) } ); diff --git a/naga/src/front/glsl/types.rs b/naga/src/front/glsl/types.rs index ffa879506e0..541fd6ca301 100644 --- a/naga/src/front/glsl/types.rs +++ b/naga/src/front/glsl/types.rs @@ -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 { 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 { }, }), word => { - fn kind_width_parse(ty: &str) -> Option<(ScalarKind, u8)> { + fn kind_width_parse(ty: &str) -> Option { 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 { 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 { 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,24 @@ pub fn parse_type(type_name: &str) -> Option { } } -pub const fn scalar_components(ty: &TypeInner) -> Option<(ScalarKind, Bytes)> { +pub const fn scalar_components(ty: &TypeInner) -> Option { 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 { + kind: ScalarKind::Float, + width, + }), _ => None, } } -pub const fn type_power(kind: ScalarKind, width: Bytes) -> Option { - Some(match kind { +pub const fn type_power(scalar: Scalar) -> Option { + 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, }) diff --git a/naga/src/front/glsl/variables.rs b/naga/src/front/glsl/variables.rs index 794f181b56c..5af2b228f03 100644 --- a/naga/src/front/glsl/variables.rs +++ b/naga/src/front/glsl/variables.rs @@ -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, diff --git a/naga/src/front/spv/image.rs b/naga/src/front/spv/image.rs index ee58c7ba140..0f25dd626b0 100644 --- a/naga/src/front/spv/image.rs +++ b/naga/src/front/spv/image.rs @@ -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, Option>) { 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`!") diff --git a/naga/src/front/spv/mod.rs b/naga/src/front/spv/mod.rs index 083205a45ba..7a8ba3c1cfb 100644 --- a/naga/src/front/spv/mod.rs +++ b/naga/src/front/spv/mod.rs @@ -2829,22 +2829,22 @@ impl> Frontend { 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> Frontend { 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> Frontend { 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> Frontend { 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> Frontend { 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> Frontend { 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> Frontend { 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> Frontend { 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> Frontend { 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> Frontend { 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> Frontend { | 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, }; diff --git a/naga/src/front/type_gen.rs b/naga/src/front/type_gen.rs index 0c608504c91..efab3d64afa 100644 --- a/naga/src/front/type_gen.rs +++ b/naga/src/front/type_gen.rs @@ -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, diff --git a/naga/src/front/wgsl/lower/construction.rs b/naga/src/front/wgsl/lower/construction.rs index 1393022f8b6..992f9af6a41 100644 --- a/naga/src/front/wgsl/lower/construction.rs +++ b/naga/src/front/wgsl/lower/construction.rs @@ -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 }, diff --git a/naga/src/front/wgsl/lower/mod.rs b/naga/src/front/wgsl/lower/mod.rs index 567360b5d82..ed1992ea7fd 100644 --- a/naga/src/front/wgsl/lower/mod.rs +++ b/naga/src/front/wgsl/lower/mod.rs @@ -1413,22 +1413,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 +1605,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,9 +1672,9 @@ 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); return Err(Error::BadTypeCast { @@ -1694,7 +1687,7 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { Typed::Plain(crate::Expression::As { expr, - kind, + kind: element_scalar.kind, convert: None, }) } @@ -1785,10 +1778,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 +1821,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 +1973,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, } diff --git a/naga/src/front/wgsl/mod.rs b/naga/src/front/wgsl/mod.rs index c1d263ee69c..2e212d8ab17 100644 --- a/naga/src/front/wgsl/mod.rs +++ b/naga/src/front/wgsl/mod.rs @@ -17,6 +17,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, @@ -104,9 +105,8 @@ impl crate::TypeInner { 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 }; + Ti::Scalar(scalar) => scalar.to_wgsl(), + Ti::Vector { size, scalar } => { format!("vec{}<{}>", size as u32, scalar.to_wgsl()) } Ti::Matrix { @@ -118,23 +118,19 @@ impl crate::TypeInner { "mat{}x{}<{}>", columns as u32, rows as u32, - Scalar { - kind: crate::ScalarKind::Float, - width - } - .to_wgsl(), + Scalar::float(width).to_wgsl(), ) } - Ti::Atomic { kind, width } => { - format!("atomic<{}>", Scalar { kind, 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 { kind, width, .. } => { - format!("ptr<{}>", Scalar { kind, width }.to_wgsl()) + Ti::ValuePointer { scalar, .. } => { + format!("ptr<{}>", scalar.to_wgsl()) } Ti::Array { base, size, .. } => { let member_type = &gctx.types[base]; @@ -292,16 +288,6 @@ mod type_inner_tests { } } -/// 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. /// @@ -315,26 +301,4 @@ impl Scalar { }; 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, - } - } } diff --git a/naga/src/front/wgsl/parse/mod.rs b/naga/src/front/wgsl/parse/mod.rs index bd635b9189e..51fc2f013b1 100644 --- a/naga/src/front/wgsl/parse/mod.rs +++ b/naga/src/front/wgsl/parse/mod.rs @@ -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)? diff --git a/naga/src/lib.rs b/naga/src/lib.rs index 300c6e48201..b23630d9993 100644 --- a/naga/src/lib.rs +++ b/naga/src/lib.rs @@ -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, - 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, width: Bytes, diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index a65bbf52021..c6702538038 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -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, 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, 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: crate::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: crate::ScalarKind::Float, + .. + }, .. } ) => @@ -831,10 +832,10 @@ impl<'a> ConstantEvaluator<'a> { Expression::ZeroValue(ty) if matches!( self.types[ty].inner, - crate::TypeInner::Scalar { + crate::TypeInner::Scalar(crate::Scalar { kind: crate::ScalarKind::Uint, .. - } + }) ) => { Ok(0) @@ -873,18 +874,17 @@ impl<'a> ConstantEvaluator<'a> { span: Span, ) -> Result, 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,10 @@ impl<'a> ConstantEvaluator<'a> { name: None, inner: TypeInner::Vector { size: rows, - kind: ScalarKind::Float, - width, + scalar: crate::Scalar { + kind: ScalarKind::Float, + width, + }, }, }, span, @@ -943,43 +945,57 @@ 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, - kind: ScalarKind, - target_width: crate::Bytes, + target: crate::Scalar, span: Span, ) -> Result, ConstantEvaluatorError> { + use crate::Scalar as Sc; + use crate::ScalarKind as Sk; + 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 { + kind: Sk::Sint, + width: 4, + } => 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 { + kind: Sk::Uint, + width: 4, + } => 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 { + kind: Sk::Float, + width: 4, + } => 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 { + kind: Sk::Bool, + width: crate::BOOL_WIDTH, + } => Literal::Bool(match literal { Literal::I32(v) => v != 0, Literal::U32(v) => v != 0, Literal::F32(v) => v != 0.0, @@ -997,20 +1013,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 +1320,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 +1330,10 @@ mod tests { name: None, inner: TypeInner::Vector { size: VectorSize::Bi, - kind: ScalarKind::Sint, - width: 4, + scalar: crate::Scalar { + kind: ScalarKind::Sint, + width: 4, + }, }, }, Default::default(), @@ -1441,10 +1455,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 +1520,10 @@ mod tests { name: None, inner: TypeInner::Vector { size: VectorSize::Tri, - kind: ScalarKind::Float, - width: 4, + scalar: crate::Scalar { + kind: ScalarKind::Float, + width: 4, + }, }, }, Default::default(), @@ -1649,10 +1662,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 +1672,10 @@ mod tests { name: None, inner: TypeInner::Vector { size: VectorSize::Bi, - kind: ScalarKind::Sint, - width: 4, + scalar: crate::Scalar { + kind: ScalarKind::Sint, + width: 4, + }, }, }, Default::default(), @@ -1733,10 +1745,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 +1755,10 @@ mod tests { name: None, inner: TypeInner::Vector { size: VectorSize::Bi, - kind: ScalarKind::Sint, - width: 4, + scalar: crate::Scalar { + kind: ScalarKind::Sint, + width: 4, + }, }, }, Default::default(), diff --git a/naga/src/proc/layouter.rs b/naga/src/proc/layouter.rs index 4c52e5ec81e..9ac8d069433 100644 --- a/naga/src/proc/layouter.rs +++ b/naga/src/proc/layouter.rs @@ -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, diff --git a/naga/src/proc/mod.rs b/naga/src/proc/mod.rs index 8a67610587f..f58573f746b 100644 --- a/naga/src/proc/mod.rs +++ b/naga/src/proc/mod.rs @@ -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 { - match (value, kind, width) { + pub const fn new(value: u8, scalar: crate::Scalar) -> Option { + 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::new(0, kind, width) + pub const fn zero(scalar: crate::Scalar) -> Option { + Self::new(0, scalar) } - pub const fn one(kind: crate::ScalarKind, width: crate::Bytes) -> Option { - Self::new(1, kind, width) + pub const fn one(scalar: crate::Scalar) -> Option { + 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, + crate::Literal::F64(_) => crate::Scalar::F64, + crate::Literal::F32(_) => crate::Scalar::F32, + crate::Literal::U32(_) => crate::Scalar::U32, + crate::Literal::I32(_) => crate::Scalar::I32, + crate::Literal::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 { + pub const fn scalar(&self) -> Option { + 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 { - // 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 { + self.scalar().map(|scalar| scalar.kind) + } + + pub fn scalar_width(&self) -> Option { + self.scalar().map(|scalar| scalar.width * 8) } pub const fn pointer_space(&self) -> Option { @@ -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 { 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, diff --git a/naga/src/proc/typifier.rs b/naga/src/proc/typifier.rs index ad9eec94d2a..a111cc844f6 100644 --- a/naga/src/proc/typifier.rs +++ b/naga/src/proc/typifier.rs @@ -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), + width, + }) => (None, width), &Ti::Vector { - kind: crate::ScalarKind::Float, + scalar: crate::Scalar { + kind: crate::ScalarKind::Float, + width, + }, size, - width, } => (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 diff --git a/naga/src/valid/analyzer.rs b/naga/src/valid/analyzer.rs index ff1db071c81..b96e482934d 100644 --- a/naga/src/valid/analyzer.rs +++ b/naga/src/valid/analyzer.rs @@ -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(), diff --git a/naga/src/valid/compose.rs b/naga/src/valid/compose.rs index 87bc2352ceb..b392de57b01 100644 --- a/naga/src/valid/compose.rs +++ b/naga/src/valid/compose.rs @@ -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 { diff --git a/naga/src/valid/expression.rs b/naga/src/valid/expression.rs index f77844b4b1e..dc70c2e6102 100644 --- a/naga/src/valid/expression.rs +++ b/naga/src/valid/expression.rs @@ -221,7 +221,7 @@ impl super::Validator { info: &FunctionInfo, mod_info: &ModuleInfo, ) -> Result { - 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(()) diff --git a/naga/src/valid/function.rs b/naga/src/valid/function.rs index d967f4b1f38..12649377815 100644 --- a/naga/src/valid/function.rs +++ b/naga/src/valid/function.rs @@ -345,9 +345,9 @@ impl super::Validator { context: &BlockContext, ) -> Result<(), WithSpan> { 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, + }, } } _ => { diff --git a/naga/src/valid/handles.rs b/naga/src/valid/handles.rs index c68ded074bd..ec6dd240c05 100644 --- a/naga/src/valid/handles.rs +++ b/naga/src/valid/handles.rs @@ -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, ); diff --git a/naga/src/valid/interface.rs b/naga/src/valid/interface.rs index 6c41ece81f3..2e50f671606 100644 --- a/naga/src/valid/interface.rs +++ b/naga/src/valid/interface.rs @@ -142,9 +142,7 @@ impl VaryingContext<'_> { ty: Handle, 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, }, ), }; diff --git a/naga/src/valid/mod.rs b/naga/src/valid/mod.rs index 2fb0a727754..011e90fbc23 100644 --- a/naga/src/valid/mod.rs +++ b/naga/src/valid/mod.rs @@ -264,19 +264,25 @@ impl crate::TypeInner { #[cfg(feature = "validate")] const fn image_storage_coordinates(&self) -> Option { 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) } diff --git a/naga/src/valid/type.rs b/naga/src/valid/type.rs index a5321178c17..12d5663f40e 100644 --- a/naga/src/valid/type.rs +++ b/naga/src/valid/type.rs @@ -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 { 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 diff --git a/naga/tests/out/analysis/access.info.ron b/naga/tests/out/analysis/access.info.ron index 93eda7f396a..d59fb2a5098 100644 --- a/naga/tests/out/analysis/access.info.ron +++ b/naga/tests/out/analysis/access.info.ron @@ -55,10 +55,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Sint, width: 4, - )), + ))), ), ( uniformity: ( @@ -79,10 +79,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Sint, width: 4, - )), + ))), ), ( uniformity: ( @@ -168,8 +168,10 @@ assignable_global: Some(3), ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -182,8 +184,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -228,8 +232,10 @@ assignable_global: Some(3), ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -242,8 +248,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -279,8 +287,10 @@ assignable_global: Some(3), ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -293,8 +303,10 @@ assignable_global: Some(3), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -305,10 +317,10 @@ ), ref_count: 0, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -343,8 +355,10 @@ assignable_global: Some(3), ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -366,8 +380,10 @@ assignable_global: Some(3), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -378,10 +394,10 @@ ), ref_count: 0, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -425,8 +441,10 @@ assignable_global: Some(3), ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -439,8 +457,10 @@ assignable_global: Some(3), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -451,10 +471,10 @@ ), ref_count: 0, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -498,8 +518,10 @@ assignable_global: Some(3), ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -521,8 +543,10 @@ assignable_global: Some(3), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -533,10 +557,10 @@ ), ref_count: 0, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -545,10 +569,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -559,8 +583,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -570,10 +596,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -584,8 +610,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -595,10 +623,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -609,8 +637,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -650,10 +680,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Sint, width: 4, - )), + ))), ), ( uniformity: ( @@ -692,10 +722,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -706,8 +736,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -717,10 +749,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -731,8 +763,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -742,10 +776,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -756,8 +790,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -790,8 +826,10 @@ assignable_global: None, ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -802,10 +840,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -816,8 +854,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -850,8 +890,10 @@ assignable_global: None, ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -862,10 +904,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -876,8 +918,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -901,8 +945,10 @@ assignable_global: None, ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -915,8 +961,10 @@ assignable_global: None, ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -927,10 +975,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -953,8 +1001,10 @@ assignable_global: None, ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -976,8 +1026,10 @@ assignable_global: None, ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -988,10 +1040,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1023,8 +1075,10 @@ assignable_global: None, ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -1037,8 +1091,10 @@ assignable_global: None, ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -1049,10 +1105,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1084,8 +1140,10 @@ assignable_global: None, ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -1107,8 +1165,10 @@ assignable_global: None, ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -1119,10 +1179,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ], sampling: [], @@ -1152,10 +1212,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Sint, width: 4, - )), + ))), ), ( uniformity: ( @@ -1176,10 +1236,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Sint, width: 4, - )), + ))), ), ( uniformity: ( @@ -1322,8 +1382,10 @@ assignable_global: Some(5), ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -1336,8 +1398,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -1394,8 +1458,10 @@ assignable_global: Some(5), ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -1408,8 +1474,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -1457,8 +1525,10 @@ assignable_global: Some(5), ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -1471,8 +1541,10 @@ assignable_global: Some(5), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -1483,10 +1555,10 @@ ), ref_count: 0, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1533,8 +1605,10 @@ assignable_global: Some(5), ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -1556,8 +1630,10 @@ assignable_global: Some(5), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -1568,10 +1644,10 @@ ), ref_count: 0, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1627,8 +1703,10 @@ assignable_global: Some(5), ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -1641,8 +1719,10 @@ assignable_global: Some(5), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -1653,10 +1733,10 @@ ), ref_count: 0, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1712,8 +1792,10 @@ assignable_global: Some(5), ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -1735,8 +1817,10 @@ assignable_global: Some(5), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Uniform, )), ), @@ -1747,10 +1831,10 @@ ), ref_count: 0, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1789,10 +1873,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Sint, width: 4, - )), + ))), ), ( uniformity: ( @@ -1864,10 +1948,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1878,8 +1962,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -1889,10 +1975,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1903,8 +1989,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -1914,10 +2002,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1928,8 +2016,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -1939,10 +2029,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1953,8 +2043,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -1999,8 +2091,10 @@ assignable_global: None, ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -2011,10 +2105,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -2025,8 +2119,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -2071,8 +2167,10 @@ assignable_global: None, ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -2083,10 +2181,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -2097,8 +2195,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -2134,8 +2234,10 @@ assignable_global: None, ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -2148,8 +2250,10 @@ assignable_global: None, ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -2160,10 +2264,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -2198,8 +2302,10 @@ assignable_global: None, ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -2221,8 +2327,10 @@ assignable_global: None, ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -2233,10 +2341,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -2280,8 +2388,10 @@ assignable_global: None, ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -2294,8 +2404,10 @@ assignable_global: None, ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -2306,10 +2418,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -2353,8 +2465,10 @@ assignable_global: None, ty: Value(ValuePointer( size: Some(Bi), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -2376,8 +2490,10 @@ assignable_global: None, ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Function, )), ), @@ -2388,10 +2504,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ], sampling: [], @@ -2517,10 +2633,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ], sampling: [], @@ -2559,10 +2675,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -2573,8 +2689,10 @@ assignable_global: None, ty: Value(Vector( size: Quad, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -2584,10 +2702,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -2598,8 +2716,10 @@ assignable_global: None, ty: Value(Vector( size: Quad, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -2650,10 +2770,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -2683,10 +2803,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -2769,10 +2889,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -2811,8 +2931,10 @@ assignable_global: Some(2), ty: Value(ValuePointer( size: Some(Tri), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Storage( access: ("LOAD | STORE"), ), @@ -2827,8 +2949,10 @@ assignable_global: Some(2), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Storage( access: ("LOAD | STORE"), ), @@ -2841,10 +2965,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -2909,10 +3033,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -2921,10 +3045,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -2933,10 +3057,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -3070,10 +3194,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Sint, width: 4, - )), + ))), ), ( uniformity: ( @@ -3082,10 +3206,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Sint, width: 4, - )), + ))), ), ( uniformity: ( @@ -3094,10 +3218,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Sint, width: 4, - )), + ))), ), ( uniformity: ( @@ -3106,10 +3230,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Sint, width: 4, - )), + ))), ), ( uniformity: ( @@ -3139,10 +3263,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -3172,10 +3296,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Sint, width: 4, - )), + ))), ), ( uniformity: ( @@ -3225,8 +3349,10 @@ assignable_global: None, ty: Value(Vector( size: Quad, - kind: Sint, - width: 4, + scalar: ( + kind: Sint, + width: 4, + ), )), ), ( @@ -3238,8 +3364,10 @@ assignable_global: None, ty: Value(Vector( size: Quad, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -3251,8 +3379,10 @@ assignable_global: None, ty: Value(Vector( size: Tri, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -3262,10 +3392,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -3334,8 +3464,10 @@ assignable_global: Some(2), ty: Value(ValuePointer( size: Some(Tri), - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Storage( access: ("LOAD | STORE"), ), @@ -3350,8 +3482,10 @@ assignable_global: Some(2), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Storage( access: ("LOAD | STORE"), ), @@ -3364,10 +3498,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -3404,10 +3538,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -3418,8 +3552,10 @@ assignable_global: None, ty: Value(Vector( size: Tri, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -3429,10 +3565,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -3443,8 +3579,10 @@ assignable_global: None, ty: Value(Vector( size: Tri, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -3454,10 +3592,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -3468,8 +3606,10 @@ assignable_global: None, ty: Value(Vector( size: Tri, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -3479,10 +3619,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -3493,8 +3633,10 @@ assignable_global: None, ty: Value(Vector( size: Tri, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -3541,10 +3683,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -3555,8 +3697,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Uint, - width: 4, + scalar: ( + kind: Uint, + width: 4, + ), )), ), ( @@ -3566,10 +3710,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -3580,8 +3724,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Uint, - width: 4, + scalar: ( + kind: Uint, + width: 4, + ), )), ), ( @@ -3656,10 +3802,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Sint, width: 4, - )), + ))), ), ( uniformity: ( @@ -3691,10 +3837,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -3705,8 +3851,10 @@ assignable_global: None, ty: Value(Vector( size: Quad, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ], @@ -3737,10 +3885,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -3761,10 +3909,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -3775,8 +3923,10 @@ assignable_global: None, ty: Value(Vector( size: Quad, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -3786,10 +3936,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -3800,8 +3950,10 @@ assignable_global: None, ty: Value(Vector( size: Quad, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -3831,27 +3983,27 @@ ), ], const_expression_types: [ - Value(Scalar( + Value(Scalar(( kind: Uint, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Uint, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Uint, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Uint, width: 4, - )), + ))), Handle(2), - Value(Scalar( + Value(Scalar(( kind: Sint, width: 4, - )), + ))), Handle(4), ], ) \ No newline at end of file diff --git a/naga/tests/out/analysis/collatz.info.ron b/naga/tests/out/analysis/collatz.info.ron index 5b32bf44ad4..040e71c7e7e 100644 --- a/naga/tests/out/analysis/collatz.info.ron +++ b/naga/tests/out/analysis/collatz.info.ron @@ -47,10 +47,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -80,10 +80,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -92,10 +92,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Bool, width: 1, - )), + ))), ), ( uniformity: ( @@ -113,10 +113,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -134,10 +134,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -146,10 +146,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Bool, width: 1, - )), + ))), ), ( uniformity: ( @@ -167,10 +167,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -188,10 +188,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -218,10 +218,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -248,10 +248,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -334,10 +334,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -388,10 +388,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( diff --git a/naga/tests/out/analysis/shadow.info.ron b/naga/tests/out/analysis/shadow.info.ron index 3553f9030b8..bd46d9187fe 100644 --- a/naga/tests/out/analysis/shadow.info.ron +++ b/naga/tests/out/analysis/shadow.info.ron @@ -119,10 +119,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -131,10 +131,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Bool, width: 1, - )), + ))), ), ( uniformity: ( @@ -143,10 +143,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -155,10 +155,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -194,10 +194,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -226,8 +226,10 @@ assignable_global: None, ty: Value(Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -246,10 +248,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -258,10 +260,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -270,10 +272,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Sint, width: 4, - )), + ))), ), ( uniformity: ( @@ -282,10 +284,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -303,10 +305,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -315,10 +317,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -345,10 +347,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -357,10 +359,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -378,10 +380,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -390,10 +392,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Sint, width: 4, - )), + ))), ), ( uniformity: ( @@ -402,10 +404,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ], sampling: [], @@ -695,8 +697,10 @@ assignable_global: Some(3), ty: Value(ValuePointer( size: None, - kind: Uint, - width: 4, + scalar: ( + kind: Uint, + width: 4, + ), space: Uniform, )), ), @@ -707,10 +711,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -719,10 +723,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Uint, width: 4, - )), + ))), ), ( uniformity: ( @@ -731,10 +735,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Bool, width: 1, - )), + ))), ), ( uniformity: ( @@ -832,8 +836,10 @@ assignable_global: None, ty: Value(Vector( size: Quad, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), )), ), ( @@ -923,8 +929,10 @@ assignable_global: Some(4), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Storage( access: ("LOAD"), ), @@ -937,10 +945,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1002,8 +1010,10 @@ assignable_global: Some(4), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Storage( access: ("LOAD"), ), @@ -1016,10 +1026,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1081,8 +1091,10 @@ assignable_global: Some(4), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Storage( access: ("LOAD"), ), @@ -1095,10 +1107,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1118,8 +1130,10 @@ assignable_global: Some(5), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Private, )), ), @@ -1130,10 +1144,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1144,8 +1158,10 @@ assignable_global: Some(5), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Private, )), ), @@ -1156,10 +1172,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1170,8 +1186,10 @@ assignable_global: Some(5), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Private, )), ), @@ -1182,10 +1200,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1221,10 +1239,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1304,8 +1322,10 @@ assignable_global: Some(4), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Storage( access: ("LOAD"), ), @@ -1318,10 +1338,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1383,8 +1403,10 @@ assignable_global: Some(4), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Storage( access: ("LOAD"), ), @@ -1397,10 +1419,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1462,8 +1484,10 @@ assignable_global: Some(4), ty: Value(ValuePointer( size: None, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), space: Storage( access: ("LOAD"), ), @@ -1476,10 +1500,10 @@ ), ref_count: 1, assignable_global: None, - ty: Value(Scalar( + ty: Value(Scalar(( kind: Float, width: 4, - )), + ))), ), ( uniformity: ( @@ -1643,81 +1667,81 @@ ), ], const_expression_types: [ - Value(Scalar( + Value(Scalar(( kind: Float, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Float, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Float, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Float, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Float, width: 4, - )), + ))), Handle(1), Handle(1), Handle(1), Handle(2), - Value(Scalar( + Value(Scalar(( kind: Uint, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Uint, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Uint, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Sint, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Sint, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Sint, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Sint, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Sint, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Sint, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Sint, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Sint, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Sint, width: 4, - )), - Value(Scalar( + ))), + Value(Scalar(( kind: Sint, width: 4, - )), + ))), ], ) \ No newline at end of file diff --git a/naga/tests/out/ir/access.compact.ron b/naga/tests/out/ir/access.compact.ron index 65f9622f2e3..2f668786e22 100644 --- a/naga/tests/out/ir/access.compact.ron +++ b/naga/tests/out/ir/access.compact.ron @@ -2,25 +2,27 @@ types: [ ( name: None, - inner: Scalar( + inner: Scalar(( kind: Uint, width: 4, - ), + )), ), ( name: None, inner: Vector( size: Tri, - kind: Uint, - width: 4, + scalar: ( + kind: Uint, + width: 4, + ), ), ), ( name: None, - inner: Scalar( + inner: Scalar(( kind: Sint, width: 4, - ), + )), ), ( name: Some("GlobalConst"), @@ -88,10 +90,10 @@ ), ( name: None, - inner: Atomic( + inner: Atomic(( kind: Sint, width: 4, - ), + )), ), ( name: None, @@ -105,8 +107,10 @@ name: None, inner: Vector( size: Bi, - kind: Uint, - width: 4, + scalar: ( + kind: Uint, + width: 4, + ), ), ), ( @@ -195,8 +199,10 @@ name: None, inner: Vector( size: Bi, - kind: Sint, - width: 4, + scalar: ( + kind: Sint, + width: 4, + ), ), ), ( @@ -231,10 +237,10 @@ ), ( name: None, - inner: Scalar( + inner: Scalar(( kind: Float, width: 4, - ), + )), ), ( name: None, @@ -263,8 +269,10 @@ name: None, inner: Vector( size: Quad, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), ), ), ( diff --git a/naga/tests/out/ir/access.ron b/naga/tests/out/ir/access.ron index 77d95dd58fa..f484189bf48 100644 --- a/naga/tests/out/ir/access.ron +++ b/naga/tests/out/ir/access.ron @@ -2,25 +2,27 @@ types: [ ( name: None, - inner: Scalar( + inner: Scalar(( kind: Uint, width: 4, - ), + )), ), ( name: None, inner: Vector( size: Tri, - kind: Uint, - width: 4, + scalar: ( + kind: Uint, + width: 4, + ), ), ), ( name: None, - inner: Scalar( + inner: Scalar(( kind: Sint, width: 4, - ), + )), ), ( name: Some("GlobalConst"), @@ -88,10 +90,10 @@ ), ( name: None, - inner: Atomic( + inner: Atomic(( kind: Sint, width: 4, - ), + )), ), ( name: None, @@ -105,8 +107,10 @@ name: None, inner: Vector( size: Bi, - kind: Uint, - width: 4, + scalar: ( + kind: Uint, + width: 4, + ), ), ), ( @@ -195,16 +199,20 @@ name: None, inner: Vector( size: Bi, - kind: Sint, - width: 4, + scalar: ( + kind: Sint, + width: 4, + ), ), ), ( name: None, inner: Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), ), ), ( @@ -239,10 +247,10 @@ ), ( name: None, - inner: Scalar( + inner: Scalar(( kind: Float, width: 4, - ), + )), ), ( name: None, @@ -271,8 +279,10 @@ name: None, inner: Vector( size: Quad, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), ), ), ( @@ -296,16 +306,20 @@ name: None, inner: Vector( size: Quad, - kind: Sint, - width: 4, + scalar: ( + kind: Sint, + width: 4, + ), ), ), ( name: None, inner: Vector( size: Tri, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), ), ), ( diff --git a/naga/tests/out/ir/collatz.compact.ron b/naga/tests/out/ir/collatz.compact.ron index 7cad54b713d..cfc3bfa0ee4 100644 --- a/naga/tests/out/ir/collatz.compact.ron +++ b/naga/tests/out/ir/collatz.compact.ron @@ -2,10 +2,10 @@ types: [ ( name: None, - inner: Scalar( + inner: Scalar(( kind: Uint, width: 4, - ), + )), ), ( name: None, @@ -33,8 +33,10 @@ name: None, inner: Vector( size: Tri, - kind: Uint, - width: 4, + scalar: ( + kind: Uint, + width: 4, + ), ), ), ], diff --git a/naga/tests/out/ir/collatz.ron b/naga/tests/out/ir/collatz.ron index 8146909c1ec..effde120a50 100644 --- a/naga/tests/out/ir/collatz.ron +++ b/naga/tests/out/ir/collatz.ron @@ -2,10 +2,10 @@ types: [ ( name: None, - inner: Scalar( + inner: Scalar(( kind: Uint, width: 4, - ), + )), ), ( name: None, @@ -33,8 +33,10 @@ name: None, inner: Vector( size: Tri, - kind: Uint, - width: 4, + scalar: ( + kind: Uint, + width: 4, + ), ), ), ], diff --git a/naga/tests/out/ir/shadow.compact.ron b/naga/tests/out/ir/shadow.compact.ron index 9ca6799c212..9cda0a4940e 100644 --- a/naga/tests/out/ir/shadow.compact.ron +++ b/naga/tests/out/ir/shadow.compact.ron @@ -2,40 +2,46 @@ types: [ ( name: None, - inner: Scalar( + inner: Scalar(( kind: Float, width: 4, - ), + )), ), ( name: None, inner: Vector( size: Tri, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), ), ), ( name: None, - inner: Scalar( + inner: Scalar(( kind: Uint, width: 4, - ), + )), ), ( name: None, inner: Vector( size: Quad, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), ), ), ( name: None, inner: Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), ), ), ( @@ -50,17 +56,19 @@ ), ( name: None, - inner: Scalar( + inner: Scalar(( kind: Sint, width: 4, - ), + )), ), ( name: None, inner: Vector( size: Quad, - kind: Uint, - width: 4, + scalar: ( + kind: Uint, + width: 4, + ), ), ), ( diff --git a/naga/tests/out/ir/shadow.ron b/naga/tests/out/ir/shadow.ron index 07bf66fcc8b..b045750a293 100644 --- a/naga/tests/out/ir/shadow.ron +++ b/naga/tests/out/ir/shadow.ron @@ -2,47 +2,53 @@ types: [ ( name: None, - inner: Scalar( + inner: Scalar(( kind: Float, width: 4, - ), + )), ), ( name: None, inner: Vector( size: Tri, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), ), ), ( name: None, - inner: Scalar( + inner: Scalar(( kind: Uint, width: 4, - ), + )), ), ( name: None, inner: Vector( size: Quad, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), ), ), ( name: None, - inner: Scalar( + inner: Scalar(( kind: Bool, width: 1, - ), + )), ), ( name: None, inner: Vector( size: Bi, - kind: Float, - width: 4, + scalar: ( + kind: Float, + width: 4, + ), ), ), ( @@ -63,10 +69,10 @@ ), ( name: None, - inner: Scalar( + inner: Scalar(( kind: Sint, width: 4, - ), + )), ), ( name: None, @@ -86,8 +92,10 @@ name: None, inner: Vector( size: Quad, - kind: Uint, - width: 4, + scalar: ( + kind: Uint, + width: 4, + ), ), ), ( diff --git a/wgpu-core/src/validation.rs b/wgpu-core/src/validation.rs index 1bf318bbaa5..a9c88edf126 100644 --- a/wgpu-core/src/validation.rs +++ b/wgpu-core/src/validation.rs @@ -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, ) { 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 { diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index 5e345421ce6..3b87ae7b729 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -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::(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::(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::(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::(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::(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::(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::(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::(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::(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::(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::(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::(data_bytes, offset) }; unsafe { gl.uniform_4_u32_slice(location, data) }; From a697e4352ca8fe033f75c7487dee7fbc76984395 Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Tue, 14 Nov 2023 15:23:23 +0100 Subject: [PATCH 20/34] Keep the value in its storage after destroy (#4678) * Keep the value in its storage after destroy in #4657 the destroy implementation was made to remove the value from the storage and leave an error variant in its place. Unfortunately this causes some issues with the tracking code which expects the ID to be unregistered after the value has been fully destroyed, even if the latter is not in storage anymore. To work around that, this commit adds a `Destroyed` variant in storage which keeps the value so that the tracking behavior is preserved while still making sure that most accesses to the destroyed resource lead to validation errors. ... Except for submitted command buffers that need to be consumed right away. These are replaced with `Element::Error` like before this commit. Co-authored-by: Teodor Tanasoaia <28601907+teoxoy@users.noreply.github.com> --- tests/tests/life_cycle.rs | 66 +++++++++++++++++++++++-------- wgpu-core/src/device/global.rs | 14 +++---- wgpu-core/src/device/queue.rs | 5 ++- wgpu-core/src/storage.rs | 71 +++++++++++++++++++++++++++++----- 4 files changed, 121 insertions(+), 35 deletions(-) diff --git a/tests/tests/life_cycle.rs b/tests/tests/life_cycle.rs index 1622547bc3d..c838dea1431 100644 --- a/tests/tests/life_cycle.rs +++ b/tests/tests/life_cycle.rs @@ -1,34 +1,66 @@ -use wgpu_test::{gpu_test, FailureCase, GpuTestConfiguration, TestParameters}; +use wgpu_test::{fail, gpu_test, GpuTestConfiguration}; #[gpu_test] -static BUFFER_DESTROY: GpuTestConfiguration = GpuTestConfiguration::new() - .parameters(TestParameters::default().expect_fail(FailureCase::always())) - .run_sync(|ctx| { - let buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor { - label: None, - size: 256, - usage: wgpu::BufferUsages::MAP_WRITE | wgpu::BufferUsages::COPY_SRC, - mapped_at_creation: false, - }); +static BUFFER_DESTROY: GpuTestConfiguration = GpuTestConfiguration::new().run_sync(|ctx| { + let buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor { + label: None, + size: 256, + usage: wgpu::BufferUsages::MAP_WRITE | wgpu::BufferUsages::COPY_SRC, + mapped_at_creation: false, + }); - buffer.destroy(); + buffer.destroy(); - buffer.destroy(); + buffer.destroy(); - ctx.device.poll(wgpu::MaintainBase::Wait); + ctx.device.poll(wgpu::MaintainBase::Wait); + fail(&ctx.device, || { buffer .slice(..) .map_async(wgpu::MapMode::Write, move |_| {}); + }); - buffer.destroy(); + buffer.destroy(); - ctx.device.poll(wgpu::MaintainBase::Wait); + ctx.device.poll(wgpu::MaintainBase::Wait); - buffer.destroy(); + buffer.destroy(); + buffer.destroy(); + + let descriptor = wgpu::BufferDescriptor { + label: None, + size: 256, + usage: wgpu::BufferUsages::MAP_WRITE | wgpu::BufferUsages::COPY_SRC, + mapped_at_creation: false, + }; + + // Scopes to mix up the drop/poll ordering. + { + let buffer = ctx.device.create_buffer(&descriptor); buffer.destroy(); - }); + let buffer = ctx.device.create_buffer(&descriptor); + buffer.destroy(); + } + let buffer = ctx.device.create_buffer(&descriptor); + buffer.destroy(); + ctx.device.poll(wgpu::MaintainBase::Wait); + let buffer = ctx.device.create_buffer(&descriptor); + buffer.destroy(); + { + let buffer = ctx.device.create_buffer(&descriptor); + buffer.destroy(); + let buffer = ctx.device.create_buffer(&descriptor); + buffer.destroy(); + let buffer = ctx.device.create_buffer(&descriptor); + ctx.device.poll(wgpu::MaintainBase::Wait); + buffer.destroy(); + } + let buffer = ctx.device.create_buffer(&descriptor); + buffer.destroy(); + ctx.device.poll(wgpu::MaintainBase::Wait); +}); #[gpu_test] static TEXTURE_DESTROY: GpuTestConfiguration = GpuTestConfiguration::new().run_sync(|ctx| { diff --git a/wgpu-core/src/device/global.rs b/wgpu-core/src/device/global.rs index ca6b756a52f..29432aae923 100644 --- a/wgpu-core/src/device/global.rs +++ b/wgpu-core/src/device/global.rs @@ -495,8 +495,8 @@ impl Global { log::trace!("Buffer::destroy {buffer_id:?}"); let (mut buffer_guard, _) = hub.buffers.write(&mut token); - let mut buffer = buffer_guard - .take_and_mark_destroyed(buffer_id) + let buffer = buffer_guard + .get_and_mark_destroyed(buffer_id) .map_err(|_| resource::DestroyError::Invalid)?; let device = &mut device_guard[buffer.device_id.value]; @@ -506,7 +506,7 @@ impl Global { | &BufferMapState::Init { .. } | &BufferMapState::Active { .. } => { - self.buffer_unmap_inner(buffer_id, &mut buffer, device) + self.buffer_unmap_inner(buffer_id, buffer, device) .unwrap_or(None) } _ => None, @@ -551,7 +551,7 @@ impl Global { 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(buffer_id) { Ok(buffer) => { let ref_count = buffer.life_guard.ref_count.take().unwrap(); let last_submit_index = buffer.life_guard.life_count(); @@ -800,8 +800,8 @@ impl Global { let (mut device_guard, mut token) = hub.devices.write(&mut token); let (mut texture_guard, _) = hub.textures.write(&mut token); - let mut texture = texture_guard - .take_and_mark_destroyed(texture_id) + let texture = texture_guard + .get_and_mark_destroyed(texture_id) .map_err(|_| resource::DestroyError::Invalid)?; let device = &mut device_guard[texture.device_id.value]; @@ -855,7 +855,7 @@ impl Global { 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(texture_id) { Ok(texture) => { let ref_count = texture.life_guard.ref_count.take().unwrap(); let last_submit_index = texture.life_guard.life_count(); diff --git a/wgpu-core/src/device/queue.rs b/wgpu-core/src/device/queue.rs index 31fbd973bf5..213d5cdea60 100644 --- a/wgpu-core/src/device/queue.rs +++ b/wgpu-core/src/device/queue.rs @@ -1110,9 +1110,10 @@ impl Global { // 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 command_buffer_guard.take_and_mark_destroyed(cmb_id) - { + let mut cmdbuf = match command_buffer_guard.replace_with_error(cmb_id) { Ok(cmdbuf) => cmdbuf, Err(_) => continue, }; diff --git a/wgpu-core/src/storage.rs b/wgpu-core/src/storage.rs index 2dcec0d3276..bff267ff923 100644 --- a/wgpu-core/src/storage.rs +++ b/wgpu-core/src/storage.rs @@ -14,6 +14,10 @@ pub(crate) enum Element { /// 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 Storage { 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 Storage { 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 Storage { 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,29 @@ impl Storage { 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 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, @@ -137,7 +169,7 @@ impl Storage { 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,13 +201,13 @@ impl Storage { self.insert_impl(index as usize, Element::Error(epoch, label.to_string())) } - pub(crate) fn take_and_mark_destroyed(&mut self, id: I) -> Result { + pub(crate) fn replace_with_error(&mut self, id: I) -> Result { let (index, epoch, _) = id.unzip(); match std::mem::replace( &mut self.map[index as usize], Element::Error(epoch, String::new()), ) { - Element::Vacant => panic!("Cannot mark a vacant resource destroyed"), + Element::Vacant => panic!("Cannot access vacant resource"), Element::Occupied(value, storage_epoch) => { assert_eq!(epoch, storage_epoch); Ok(value) @@ -184,6 +216,27 @@ impl Storage { } } + 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); @@ -192,7 +245,7 @@ impl Storage { pub(crate) fn remove(&mut self, id: I) -> Option { 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) } @@ -239,7 +292,7 @@ impl Storage { }; 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, } From 734e246e87a43387a5a026af66522d5f987a74e0 Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Thu, 9 Nov 2023 16:18:20 -0800 Subject: [PATCH 21/34] [naga] Improve algorithm for Module compaction. Identify reachable function expressions, constant expressions, and types using a single pass over each arena, taking advantage of the fact that expressions and types may only refer to other entries that precede them within their arena. Only walking the statement tree still requires a worklist/recursion. In addition to presumably being faster, this change slightly reduces the number of non-comment lines of code in `src/compact`. --- CHANGELOG.md | 6 +- naga/src/compact/expressions.rs | 177 ++++++++++++++--------------- naga/src/compact/functions.rs | 41 +++---- naga/src/compact/handle_set_map.rs | 22 +++- naga/src/compact/mod.rs | 53 +++++---- naga/src/compact/statements.rs | 50 ++++---- naga/src/compact/types.rs | 31 +++-- 7 files changed, 202 insertions(+), 178 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ea3dcbb58e..4c5d6b85108 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -59,7 +59,11 @@ For naga changelogs at or before v0.14.0. See [naga's changelog](naga/CHANGELOG. - Create a hidden window per `wgpu::Instance` instead of sharing a global one. -#### Naga MSL-OUT +#### Naga + +- Improve algorithm used by module compaction. By @jimblandy in [#4662](https://github.com/gfx-rs/wgpu/pull/4662). + +##### MSL-OUT - Fix issue where local variables were sometimes using variable names from previous functions. diff --git a/naga/src/compact/expressions.rs b/naga/src/compact/expressions.rs index c1326e92bef..301bbe32405 100644 --- a/naga/src/compact/expressions.rs +++ b/naga/src/compact/expressions.rs @@ -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, pub constants: &'tracer Arena, /// 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, - /// The constant expression arena and its used map, if we haven't - /// switched to tracing constant expressions yet. - pub const_expressions: Option<( - &'tracer Arena, - &'tracer mut HandleSet, - )>, + /// 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>, } impl<'tracer> ExpressionTracer<'tracer> { - pub fn trace_expression(&mut self, expr: Handle) { + /// 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) { - 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) { - self.as_const_expression().trace_expression(const_expr); - } } impl ModuleMap { diff --git a/naga/src/compact/functions.rs b/naga/src/compact/functions.rs index 752c3eb7f18..b0d08c7e96e 100644 --- a/naga/src/compact/functions.rs +++ b/naga/src/compact/functions.rs @@ -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, pub types_used: &'a mut HandleSet, pub constants_used: &'a mut HandleSet, @@ -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) { - self.as_type().trace_type(ty) - } - pub fn trace_expression(&mut self, expr: Handle) { - 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), } } } diff --git a/naga/src/compact/handle_set_map.rs b/naga/src/compact/handle_set_map.rs index bf74d3f0b9d..c716ca82949 100644 --- a/naga/src/compact/handle_set_map.rs +++ b/naga/src/compact/handle_set_map.rs @@ -26,13 +26,23 @@ impl HandleSet { } /// 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) -> bool { + pub fn insert(&mut self, handle: Handle) { + // Note that, oddly, `Handle::index` does not return a 1-based + // `Index`, but rather a zero-based `usize`. + self.members.insert(handle.index()); + } + + /// Add handles from `iter` to the set. + pub fn insert_iter(&mut self, iter: impl IntoIterator>) { + for handle in iter { + self.insert(handle); + } + } + + pub fn contains(&self, handle: Handle) -> bool { // 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.contains(handle.index()) } } @@ -148,6 +158,8 @@ impl HandleMap { // 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 { diff --git a/naga/src/compact/mod.rs b/naga/src/compact/mod.rs index 137f3bbe30c..6f6fe3d9da7 100644 --- a/naga/src/compact/mod.rs +++ b/naga/src/compact/mod.rs @@ -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 = 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, diff --git a/naga/src/compact/statements.rs b/naga/src/compact/statements.rs index 4c627710238..0698b57258e 100644 --- a/naga/src/compact/statements.rs +++ b/naga/src/compact/statements.rs @@ -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 => {} } } diff --git a/naga/src/compact/types.rs b/naga/src/compact/types.rs index 3314919cd7e..b78619d9a80 100644 --- a/naga/src/compact/types.rs +++ b/naga/src/compact/types.rs @@ -7,16 +7,25 @@ pub struct TypeTracer<'a> { } impl<'a> TypeTracer<'a> { - pub fn trace_type(&mut self, ty: Handle) { - 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), } } } From a6aa3cd30d3a3c0efde5d81fb5435d1c281a0ab1 Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Tue, 14 Nov 2023 11:12:00 -0800 Subject: [PATCH 22/34] [naga] Follow-ups to #4763, Introduce `Scalar` type to IR. Clean up some things that should have been taken care of in the original PR: - Use `Scalar::float` helper. - Use `Scalar` associated constants in match patterns. - Use `Scalar`'s `PartialEq` implementation. - Clean up identifier paths. --- naga/src/front/glsl/functions.rs | 36 +++------------ naga/src/front/glsl/parser/declarations.rs | 5 +-- naga/src/front/glsl/types.rs | 5 +-- naga/src/proc/constant_evaluator.rs | 52 +++++----------------- naga/src/proc/mod.rs | 10 ++--- 5 files changed, 26 insertions(+), 82 deletions(-) diff --git a/naga/src/front/glsl/functions.rs b/naga/src/front/glsl/functions.rs index fce097e97f5..b7e184afd7f 100644 --- a/naga/src/front/glsl/functions.rs +++ b/naga/src/front/glsl/functions.rs @@ -1539,16 +1539,9 @@ fn conversion(target: &TypeInner, source: &TypeInner) -> Option { columns: src_cols, width: src_width, }, - ) if tgt_cols == src_cols && tgt_rows == src_rows => ( - Scalar { - kind: Float, - width: tgt_width, - }, - Scalar { - kind: Float, - width: src_width, - }, - ), + ) if tgt_cols == src_cols && tgt_rows == src_rows => { + (Scalar::float(tgt_width), Scalar::float(src_width)) + } _ => return None, }; @@ -1562,22 +1555,10 @@ fn conversion(target: &TypeInner, source: &TypeInner) -> Option { Some(match (target_scalar, source_scalar) { // A conversion from a float to a double is special - ( - Scalar { - kind: Float, - width: 8, - }, - Scalar { - kind: Float, - width: 4, - }, - ) => Conversion::FloatToDouble, + (Scalar::F64, Scalar::F32) => Conversion::FloatToDouble, // A conversion from an integer to a float is special ( - Scalar { - kind: Float, - width: 4, - }, + Scalar::F32, Scalar { kind: Sint | Uint, width: _, @@ -1585,10 +1566,7 @@ fn conversion(target: &TypeInner, source: &TypeInner) -> Option { ) => Conversion::IntToFloat, // A conversion from an integer to a double is special ( - Scalar { - kind: Float, - width: 8, - }, + Scalar::F64, Scalar { kind: Sint | Uint, width: _, @@ -1608,7 +1586,7 @@ fn builtin_required_variations<'a>(args: impl Iterator) -> TypeInner::ValuePointer { scalar, .. } | TypeInner::Scalar(scalar) | TypeInner::Vector { scalar, .. } => { - if scalar.kind == ScalarKind::Float && scalar.width == 8 { + if scalar == Scalar::F64 { variations |= BuiltinVariations::DOUBLE } } diff --git a/naga/src/front/glsl/parser/declarations.rs b/naga/src/front/glsl/parser/declarations.rs index 961c6d832a2..fff56a60699 100644 --- a/naga/src/front/glsl/parser/declarations.rs +++ b/naga/src/front/glsl/parser/declarations.rs @@ -48,10 +48,7 @@ fn element_or_member_type( name: None, inner: TypeInner::Vector { size: rows, - scalar: Scalar { - kind: ScalarKind::Float, - width, - }, + scalar: Scalar::float(width), }, }, Default::default(), diff --git a/naga/src/front/glsl/types.rs b/naga/src/front/glsl/types.rs index 541fd6ca301..953c4a98edb 100644 --- a/naga/src/front/glsl/types.rs +++ b/naga/src/front/glsl/types.rs @@ -194,10 +194,7 @@ pub const fn scalar_components(ty: &TypeInner) -> Option { TypeInner::Scalar(scalar) | TypeInner::Vector { scalar, .. } | TypeInner::ValuePointer { scalar, .. } => Some(scalar), - TypeInner::Matrix { width, .. } => Some(Scalar { - kind: ScalarKind::Float, - width, - }), + TypeInner::Matrix { width, .. } => Some(Scalar::float(width)), _ => None, } } diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index c6702538038..b9247b3c857 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -607,7 +607,7 @@ impl<'a> ConstantEvaluator<'a> { self.types[ty0].inner, crate::TypeInner::Vector { scalar: crate::Scalar { - kind: crate::ScalarKind::Float, + kind: ScalarKind::Float, .. }, .. @@ -708,7 +708,7 @@ impl<'a> ConstantEvaluator<'a> { self.types[ty0].inner, crate::TypeInner::Vector { scalar: crate::Scalar { - kind: crate::ScalarKind::Float, + kind: ScalarKind::Float, .. }, .. @@ -833,7 +833,7 @@ impl<'a> ConstantEvaluator<'a> { if matches!( self.types[ty].inner, crate::TypeInner::Scalar(crate::Scalar { - kind: crate::ScalarKind::Uint, + kind: ScalarKind::Uint, .. }) ) => @@ -905,10 +905,7 @@ impl<'a> ConstantEvaluator<'a> { name: None, inner: TypeInner::Vector { size: rows, - scalar: crate::Scalar { - kind: ScalarKind::Float, - width, - }, + scalar: crate::Scalar::float(width), }, }, span, @@ -955,47 +952,34 @@ impl<'a> ConstantEvaluator<'a> { span: Span, ) -> Result, ConstantEvaluatorError> { use crate::Scalar as Sc; - use crate::ScalarKind as Sk; let expr = self.eval_zero_value_and_splat(expr, span)?; let expr = match self.expressions[expr] { Expression::Literal(literal) => { let literal = match target { - Sc { - kind: Sk::Sint, - width: 4, - } => Literal::I32(match literal { + 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), }), - Sc { - kind: Sk::Uint, - width: 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), }), - Sc { - kind: Sk::Float, - width: 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), }), - Sc { - kind: Sk::Bool, - width: 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, @@ -1330,10 +1314,7 @@ mod tests { name: None, inner: TypeInner::Vector { size: VectorSize::Bi, - scalar: crate::Scalar { - kind: ScalarKind::Sint, - width: 4, - }, + scalar: crate::Scalar::I32, }, }, Default::default(), @@ -1520,10 +1501,7 @@ mod tests { name: None, inner: TypeInner::Vector { size: VectorSize::Tri, - scalar: crate::Scalar { - kind: ScalarKind::Float, - width: 4, - }, + scalar: crate::Scalar::F32, }, }, Default::default(), @@ -1672,10 +1650,7 @@ mod tests { name: None, inner: TypeInner::Vector { size: VectorSize::Bi, - scalar: crate::Scalar { - kind: ScalarKind::Sint, - width: 4, - }, + scalar: crate::Scalar::I32, }, }, Default::default(), @@ -1755,10 +1730,7 @@ mod tests { name: None, inner: TypeInner::Vector { size: VectorSize::Bi, - scalar: crate::Scalar { - kind: ScalarKind::Sint, - width: 4, - }, + scalar: crate::Scalar::I32, }, }, Default::default(), diff --git a/naga/src/proc/mod.rs b/naga/src/proc/mod.rs index f58573f746b..89d49528a74 100644 --- a/naga/src/proc/mod.rs +++ b/naga/src/proc/mod.rs @@ -193,11 +193,11 @@ impl crate::Literal { } pub const fn scalar(&self) -> crate::Scalar { match *self { - crate::Literal::F64(_) => crate::Scalar::F64, - crate::Literal::F32(_) => crate::Scalar::F32, - crate::Literal::U32(_) => crate::Scalar::U32, - crate::Literal::I32(_) => crate::Scalar::I32, - crate::Literal::Bool(_) => crate::Scalar::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 { From cbb59c7bf37b88c5a2e043fbd053675f5fd0cd62 Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Tue, 14 Nov 2023 14:36:32 -0800 Subject: [PATCH 23/34] [naga wgsl-in] Move all `to_wgsl` functions into their own module. This is code motion only, with minor doc fixes. There should be no changes to the code. --- naga/src/front/wgsl/mod.rs | 257 +-------------------------------- naga/src/front/wgsl/to_wgsl.rs | 256 ++++++++++++++++++++++++++++++++ 2 files changed, 257 insertions(+), 256 deletions(-) create mode 100644 naga/src/front/wgsl/to_wgsl.rs diff --git a/naga/src/front/wgsl/mod.rs b/naga/src/front/wgsl/mod.rs index 2e212d8ab17..b6151fe1c03 100644 --- a/naga/src/front/wgsl/mod.rs +++ b/naga/src/front/wgsl/mod.rs @@ -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; @@ -46,259 +47,3 @@ impl Frontend { pub fn parse_str(source: &str) -> Result { 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`. - /// - /// 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(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, - 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 = 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"); - - let mat = crate::TypeInner::Matrix { - rows: crate::VectorSize::Quad, - columns: crate::VectorSize::Bi, - width: 8, - }; - assert_eq!(mat.to_wgsl(gctx), "mat2x4"); - - let ptr = crate::TypeInner::Pointer { - base: mytype2, - space: crate::AddressSpace::Storage { - access: crate::StorageAccess::default(), - }, - }; - assert_eq!(ptr.to_wgsl(gctx), "ptr"); - - 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"); - - 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"); - } -} - -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) - } -} diff --git a/naga/src/front/wgsl/to_wgsl.rs b/naga/src/front/wgsl/to_wgsl.rs new file mode 100644 index 00000000000..6682e295cac --- /dev/null +++ b/naga/src/front/wgsl/to_wgsl.rs @@ -0,0 +1,256 @@ +impl crate::TypeInner { + /// Formats the type as it is written in wgsl. + /// + /// For example `vec3`. + /// + /// 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: crate::proc::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"); + + let mat = crate::TypeInner::Matrix { + rows: crate::VectorSize::Quad, + columns: crate::VectorSize::Bi, + width: 8, + }; + assert_eq!(mat.to_wgsl(gctx), "mat2x4"); + + let ptr = crate::TypeInner::Pointer { + base: mytype2, + space: crate::AddressSpace::Storage { + access: crate::StorageAccess::default(), + }, + }; + assert_eq!(ptr.to_wgsl(gctx), "ptr"); + + 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"); + + 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"); + } +} From 941cd2e25c91644ecd5c5d5dd41d967fe5008712 Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Tue, 14 Nov 2023 14:44:41 -0800 Subject: [PATCH 24/34] [naga wgsl-in] Let TypeInner::to_wgsl take the context by reference. --- naga/src/front/wgsl/lower/mod.rs | 6 +++--- naga/src/front/wgsl/to_wgsl.rs | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/naga/src/front/wgsl/lower/mod.rs b/naga/src/front/wgsl/lower/mod.rs index ed1992ea7fd..fbd51646710 100644 --- a/naga/src/front/wgsl/lower/mod.rs +++ b/naga/src/front/wgsl/lower/mod.rs @@ -633,7 +633,7 @@ impl<'source, 'temp, 'out> ExpressionContext<'source, 'temp, 'out> { } fn format_typeinner(&self, inner: &crate::TypeInner) -> String { - inner.to_wgsl(self.module.to_ctx()) + inner.to_wgsl(&self.module.to_ctx()) } fn format_type(&self, handle: Handle) -> String { @@ -929,13 +929,13 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { let expected = ty .name .clone() - .unwrap_or_else(|| ty.inner.to_wgsl(ctx.module.to_ctx())); + .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())); + .unwrap_or_else(|| ty.inner.to_wgsl(&ctx.module.to_ctx())); return Err(Error::InitializationTypeMismatch { name: c.name.span, diff --git a/naga/src/front/wgsl/to_wgsl.rs b/naga/src/front/wgsl/to_wgsl.rs index 6682e295cac..88dbf575f2b 100644 --- a/naga/src/front/wgsl/to_wgsl.rs +++ b/naga/src/front/wgsl/to_wgsl.rs @@ -6,7 +6,7 @@ impl crate::TypeInner { /// 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: crate::proc::GlobalCtx) -> String { + pub fn to_wgsl(&self, gctx: &crate::proc::GlobalCtx) -> String { use crate::TypeInner as Ti; match *self { @@ -206,14 +206,14 @@ mod tests { stride: 4, size: crate::ArraySize::Constant(unsafe { NonZeroU32::new_unchecked(32) }), }; - assert_eq!(array.to_wgsl(gctx), "array"); + assert_eq!(array.to_wgsl(&gctx), "array"); let mat = crate::TypeInner::Matrix { rows: crate::VectorSize::Quad, columns: crate::VectorSize::Bi, width: 8, }; - assert_eq!(mat.to_wgsl(gctx), "mat2x4"); + assert_eq!(mat.to_wgsl(&gctx), "mat2x4"); let ptr = crate::TypeInner::Pointer { base: mytype2, @@ -221,7 +221,7 @@ mod tests { access: crate::StorageAccess::default(), }, }; - assert_eq!(ptr.to_wgsl(gctx), "ptr"); + assert_eq!(ptr.to_wgsl(&gctx), "ptr"); let img1 = crate::TypeInner::Image { dim: crate::ImageDimension::D2, @@ -231,26 +231,26 @@ mod tests { multi: true, }, }; - assert_eq!(img1.to_wgsl(gctx), "texture_multisampled_2d"); + assert_eq!(img1.to_wgsl(&gctx), "texture_multisampled_2d"); 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"); + 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"); + 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"); + assert_eq!(array.to_wgsl(&gctx), "binding_array"); } } From cf2405ca393f704c9a22c9219de1be07571a0b2b Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Tue, 14 Nov 2023 15:00:46 -0800 Subject: [PATCH 25/34] [naga wgsl-in] Use `to_wgsl` functions everywhere appropriate. Replace `ExpressionContext`'s methods `format_typeinner`, `format_type`, and `format_type_resolution` with more `to_wgsl` methods in the `naga::front::wgsl::to_wgsl` module. --- naga/src/front/wgsl/lower/construction.rs | 4 +- naga/src/front/wgsl/lower/mod.rs | 55 +++++++---------------- naga/src/front/wgsl/to_wgsl.rs | 29 +++++++++++- 3 files changed, 45 insertions(+), 43 deletions(-) diff --git a/naga/src/front/wgsl/lower/construction.rs b/naga/src/front/wgsl/lower/construction.rs index 992f9af6a41..7c06f1804ee 100644 --- a/naga/src/front/wgsl/lower/construction.rs +++ b/naga/src/front/wgsl/lower/construction.rs @@ -65,7 +65,7 @@ impl Constructor<(Handle, &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()), } } } @@ -455,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, diff --git a/naga/src/front/wgsl/lower/mod.rs b/naga/src/front/wgsl/lower/mod.rs index fbd51646710..684ba7ab0be 100644 --- a/naga/src/front/wgsl/lower/mod.rs +++ b/naga/src/front/wgsl/lower/mod.rs @@ -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) -> 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 { 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 @@ -1677,10 +1651,11 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { 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), }); } }; diff --git a/naga/src/front/wgsl/to_wgsl.rs b/naga/src/front/wgsl/to_wgsl.rs index 88dbf575f2b..7af3debc4c4 100644 --- a/naga/src/front/wgsl/to_wgsl.rs +++ b/naga/src/front/wgsl/to_wgsl.rs @@ -1,3 +1,30 @@ +//! 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 { + /// Formats the type as it is written in wgsl. + /// + /// For example `vec3`. + 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. /// @@ -6,7 +33,7 @@ impl crate::TypeInner { /// 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: &crate::proc::GlobalCtx) -> String { + pub fn to_wgsl(&self, gctx: &GlobalCtx) -> String { use crate::TypeInner as Ti; match *self { From 324ec4a5ec138dd3ac2cd40dd04fcc64f4b560eb Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Tue, 14 Nov 2023 09:38:03 -0800 Subject: [PATCH 26/34] [naga glsl-in] Fix double overload for dot/reflect/distance/ldexp. The first argument of the `dot`, `reflect`, `distance`, and `ldexp` GLSL builtin functions may be either a float or a double, and thus the argument type registered by `inject_common_builtin` must depend on the `float_width` argument; it cannot simply be `Scalar::F32`. Introduced by #4673. --- naga/src/front/glsl/builtins.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/naga/src/front/glsl/builtins.rs b/naga/src/front/glsl/builtins.rs index 0b01204dac3..96e01e21f6b 100644 --- a/naga/src/front/glsl/builtins.rs +++ b/naga/src/front/glsl/builtins.rs @@ -1257,7 +1257,7 @@ fn inject_common_builtin( declaration .overloads - .push(module.add_builtin(vec![ty(Scalar::F32), ty(second_scalar)], fun)) + .push(module.add_builtin(vec![ty(float_scalar), ty(second_scalar)], fun)) } } "transpose" => { From 721e611b792898b9d8ec93e20ac5cc9da68ac740 Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Tue, 14 Nov 2023 09:49:17 -0800 Subject: [PATCH 27/34] [naga glsl-in] Fix type of double ldexp's second arg. The second argument of the GLSL `ldexp` builtin is always a 32-bit integer or a vector of such, never a 64-bit integer. In `inject_common_builtin`, that argument's type should not be influenced by `float_width`. Fixes #4680. --- naga/src/front/glsl/builtins.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/naga/src/front/glsl/builtins.rs b/naga/src/front/glsl/builtins.rs index 96e01e21f6b..afe404a7eb9 100644 --- a/naga/src/front/glsl/builtins.rs +++ b/naga/src/front/glsl/builtins.rs @@ -1246,13 +1246,9 @@ fn inject_common_builtin( _ => unreachable!(), }; - let second_scalar = if fun == MacroCall::MathFunction(MathFunction::Ldexp) { - Scalar { - kind: Sk::Sint, - width: float_width, - } - } else { - float_scalar + let second_scalar = match fun { + MacroCall::MathFunction(MathFunction::Ldexp) => Scalar::I32, + _ => float_scalar, }; declaration From 16965f64e5274e6f43150d878050d84706d2da8d Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Tue, 14 Nov 2023 09:55:35 -0800 Subject: [PATCH 28/34] [naga wgsl-out] Correctly include width in matrix constructions. When generating WGSL for an `Expression::Compose` constructing a matrix, consult `TypeInner::Matrix::width` when writing the type name in the construction expression, rather than just always writing `matNxM`. Fixes #4681. --- naga/src/back/wgsl/writer.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/naga/src/back/wgsl/writer.rs b/naga/src/back/wgsl/writer.rs index 2a398e8845a..cd9ae076f30 100644 --- a/naga/src/back/wgsl/writer.rs +++ b/naga/src/back/wgsl/writer.rs @@ -524,14 +524,14 @@ impl Writer { TypeInner::Matrix { columns, rows, - width: _, + width, } => { write!( self.out, - //TODO: Can matrix be other than f32? - "mat{}x{}", + "mat{}x{}<{}>", back::vector_size_str(columns), back::vector_size_str(rows), + scalar_kind_str(crate::Scalar::float(width)) )?; } TypeInner::Pointer { base, space } => { From ecb522e4e37d5d3698ebcb1f329a2116d3a65c3f Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Tue, 14 Nov 2023 09:57:42 -0800 Subject: [PATCH 29/34] [naga] New tests for GLSL double-precision builtin functions. --- naga/tests/in/glsl/double-math-functions.frag | 34 ++++++ .../out/wgsl/double-math-functions.frag.wgsl | 107 ++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 naga/tests/in/glsl/double-math-functions.frag create mode 100644 naga/tests/out/wgsl/double-math-functions.frag.wgsl diff --git a/naga/tests/in/glsl/double-math-functions.frag b/naga/tests/in/glsl/double-math-functions.frag new file mode 100644 index 00000000000..78f53f9ef65 --- /dev/null +++ b/naga/tests/in/glsl/double-math-functions.frag @@ -0,0 +1,34 @@ +#version 450 + +void main() { + dvec4 a = dvec4(1.0); + dvec4 b = dvec4(2.0); + dmat4 m = dmat4(a, b, a, b); + int i = 5; + + dvec4 ceilOut = ceil(a); + dvec4 roundOut = round(a); + dvec4 floorOut = floor(a); + dvec4 fractOut = fract(a); + dvec4 truncOut = trunc(a); + dvec4 absOut = abs(a); + dvec4 sqrtOut = sqrt(a); + dvec4 inversesqrtOut = inversesqrt(a); + dvec4 signOut = sign(a); + dmat4 transposeOut = transpose(m); + dvec4 normalizeOut = normalize(a); + double lengthOut = length(a); + double determinantOut = determinant(m); + double modOut = mod(a.x, b.x); + double dotOut = dot(a, b); + dvec4 maxOut = max(a, b); + dvec4 minOut = min(a, b); + dvec4 reflectOut = reflect(a, b); + dvec3 crossOut = cross(a.xyz, b.xyz); + double distanceOut = distance(a, b); + dvec4 stepOut = step(a, b); + double ldexpOut = ldexp(a.x, i); + double smoothStepScalar = smoothstep(0.0, 1.0, 0.5); + dvec4 smoothStepVector = smoothstep(dvec4(0.0), dvec4(1.0), dvec4(0.5)); + dvec4 smoothStepMixed = smoothstep(0.0, 1.0, dvec4(0.5)); +} diff --git a/naga/tests/out/wgsl/double-math-functions.frag.wgsl b/naga/tests/out/wgsl/double-math-functions.frag.wgsl new file mode 100644 index 00000000000..d21d99f4de8 --- /dev/null +++ b/naga/tests/out/wgsl/double-math-functions.frag.wgsl @@ -0,0 +1,107 @@ +fn main_1() { + var a: vec4; + var b: vec4; + var m: mat4x4; + var i: i32 = 5; + var ceilOut: vec4; + var roundOut: vec4; + var floorOut: vec4; + var fractOut: vec4; + var truncOut: vec4; + var absOut: vec4; + var sqrtOut: vec4; + var inversesqrtOut: vec4; + var signOut: vec4; + var transposeOut: mat4x4; + var normalizeOut: vec4; + var lengthOut: f64; + var determinantOut: f64; + var modOut: f64; + var dotOut: f64; + var maxOut: vec4; + var minOut: vec4; + var reflectOut: vec4; + var crossOut: vec3; + var distanceOut: f64; + var stepOut: vec4; + var ldexpOut: f64; + var smoothStepScalar: f64; + var smoothStepVector: vec4; + var smoothStepMixed: vec4; + + a = vec4(f64(1.0)); + b = vec4(f64(2.0)); + let _e8 = a; + let _e9 = b; + let _e10 = a; + let _e11 = b; + m = mat4x4(vec4(_e8.x, _e8.y, _e8.z, _e8.w), vec4(_e9.x, _e9.y, _e9.z, _e9.w), vec4(_e10.x, _e10.y, _e10.z, _e10.w), vec4(_e11.x, _e11.y, _e11.z, _e11.w)); + let _e37 = a; + ceilOut = ceil(_e37); + let _e41 = a; + roundOut = round(_e41); + let _e45 = a; + floorOut = floor(_e45); + let _e49 = a; + fractOut = fract(_e49); + let _e53 = a; + truncOut = trunc(_e53); + let _e57 = a; + absOut = abs(_e57); + let _e61 = a; + sqrtOut = sqrt(_e61); + let _e65 = a; + inversesqrtOut = inverseSqrt(_e65); + let _e69 = a; + signOut = sign(_e69); + let _e73 = m; + transposeOut = transpose(_e73); + let _e77 = a; + normalizeOut = normalize(_e77); + let _e81 = a; + lengthOut = length(_e81); + let _e85 = m; + determinantOut = determinant(_e85); + let _e88 = a; + let _e90 = b; + let _e92 = a; + let _e94 = b; + modOut = (_e92.x - (floor((_e92.x / _e94.x)) * _e94.x)); + let _e103 = a; + let _e104 = b; + dotOut = dot(_e103, _e104); + let _e109 = a; + let _e110 = b; + maxOut = max(_e109, _e110); + let _e115 = a; + let _e116 = b; + minOut = min(_e115, _e116); + let _e121 = a; + let _e122 = b; + reflectOut = reflect(_e121, _e122); + let _e125 = a; + let _e127 = b; + let _e129 = a; + let _e131 = b; + crossOut = cross(_e129.xyz, _e131.xyz); + let _e137 = a; + let _e138 = b; + distanceOut = distance(_e137, _e138); + let _e143 = a; + let _e144 = b; + stepOut = step(_e143, _e144); + let _e147 = a; + let _e150 = a; + let _e152 = i; + ldexpOut = ldexp(_e150.x, _e152); + smoothStepScalar = f64(smoothstep(0.0, 1.0, 0.5)); + smoothStepVector = smoothstep(vec4(f64(0.0)), vec4(f64(1.0)), vec4(f64(0.5))); + smoothStepMixed = smoothstep(vec4(f64(0.0)), vec4(f64(1.0)), vec4(f64(0.5))); + return; +} + +@fragment +fn main() { + main_1(); + return; +} From 611471c4bc8b1adab4d7d96fd2ba8bae82dccb28 Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Tue, 14 Nov 2023 10:09:39 -0800 Subject: [PATCH 30/34] Update CHANGELOG.md. --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c5d6b85108..273587eb52c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -63,9 +63,9 @@ For naga changelogs at or before v0.14.0. See [naga's changelog](naga/CHANGELOG. - Improve algorithm used by module compaction. By @jimblandy in [#4662](https://github.com/gfx-rs/wgpu/pull/4662). -##### MSL-OUT +- In Metal Shading Language output, fix issue where local variables were sometimes using variable names from previous functions. -- Fix issue where local variables were sometimes using variable names from previous functions. +- When reading GLSL, fix the argument types of the double-precision floating-point overloads of the `dot`, `reflect`, `distance`, and `ldexp` builtin functions. Correct the WGSL generated for constructing 64-bit floating-point matrices. Add tests for all the above. By @jimblandy in [#4684](https://github.com/gfx-rs/wgpu/pull/4684). ## v0.18.0 (2023-10-25) From f5665f73bd56b16044e5d8eca439a1d2b4895a30 Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Wed, 15 Nov 2023 10:40:03 +0100 Subject: [PATCH 31/34] Prevent panic in untrack if a resource is already destroyed --- wgpu-core/src/device/global.rs | 4 +- wgpu-core/src/device/resource.rs | 64 ++++++++++++++++++++++++++++---- wgpu-core/src/storage.rs | 19 +++++++++- 3 files changed, 76 insertions(+), 11 deletions(-) diff --git a/wgpu-core/src/device/global.rs b/wgpu-core/src/device/global.rs index 29432aae923..1d9f48ead03 100644 --- a/wgpu-core/src/device/global.rs +++ b/wgpu-core/src/device/global.rs @@ -551,7 +551,7 @@ impl Global { let (ref_count, last_submit_index, device_id) = { let (mut buffer_guard, _) = hub.buffers.write(&mut token); - match buffer_guard.get_occupied_or_destroyed(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(); @@ -855,7 +855,7 @@ impl Global { let (ref_count, last_submit_index, device_id) = { let (mut texture_guard, _) = hub.textures.write(&mut token); - match texture_guard.get_occupied_or_destroyed(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(); diff --git a/wgpu-core/src/device/resource.rs b/wgpu-core/src/device/resource.rs index 3d422a8e285..de84baacf39 100644 --- a/wgpu-core/src/device/resource.rs +++ b/wgpu-core/src/device/resource.rs @@ -357,42 +357,90 @@ impl Device { 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); } } diff --git a/wgpu-core/src/storage.rs b/wgpu-core/src/storage.rs index bff267ff923..09d93d637d0 100644 --- a/wgpu-core/src/storage.rs +++ b/wgpu-core/src/storage.rs @@ -149,7 +149,7 @@ impl Storage { /// 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 self, id: I) -> Result<&mut T, InvalidId> { + 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)) @@ -165,6 +165,23 @@ impl Storage { 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, + "{}[{}] is no longer alive", + self.kind, index + ); + result + } + pub(crate) unsafe fn get_unchecked(&self, id: u32) -> &T { match self.map[id as usize] { Element::Occupied(ref v, _) => v, From b47fe3b413bf09fe885c430cef91b9a113e74e5f Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Wed, 15 Nov 2023 12:41:52 +0100 Subject: [PATCH 32/34] Prevent panic in buffer mapping logic if the buffer is already destroyed. --- wgpu-core/src/device/life.rs | 39 +++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/wgpu-core/src/device/life.rs b/wgpu-core/src/device/life.rs index cb8dc43b7ea..dc27bc43e03 100644 --- a/wgpu-core/src/device/life.rs +++ b/wgpu-core/src/device/life.rs @@ -840,21 +840,22 @@ impl LifetimeTracker { for stored in self.mapped.drain(..) { let resource_id = stored.value; - let buf = &buffer_guard[resource_id]; - - 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); + // 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) + ); + + self.active + .iter_mut() + .find(|a| a.index == submit_index) + .map_or(&mut self.ready_to_map, |a| &mut a.mapped) + .push(resource_id); + } } } @@ -879,7 +880,13 @@ impl LifetimeTracker { 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; From 8870a085a8613a029f0b118e882c514c7b7ae380 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Nov 2023 12:27:05 -0500 Subject: [PATCH 33/34] Bump termcolor from 1.3.0 to 1.4.0 (#4688) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- naga/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c356659ec1b..f215b26d796 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3379,9 +3379,9 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" +checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" dependencies = [ "winapi-util", ] diff --git a/Cargo.toml b/Cargo.toml index 21dc5f5bf0e..ddd0c319060 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -172,7 +172,7 @@ deno_web = "0.150.0" deno_webidl = "0.119.0" deno_webgpu = { version = "0.85.0", path = "./deno_webgpu" } tokio = "1.34.0" -termcolor = "1.3.0" +termcolor = "1.4.0" [patch."https://github.com/gfx-rs/naga"] diff --git a/naga/Cargo.toml b/naga/Cargo.toml index e6616455f41..9729adf709d 100644 --- a/naga/Cargo.toml +++ b/naga/Cargo.toml @@ -41,7 +41,7 @@ harness = false arbitrary = { version = "1.3", features = ["derive"], optional = true } bitflags = "2.2" bit-set = "0.5" -termcolor = { version = "1.0.4", optional = true } +termcolor = { version = "1.4.0", optional = true } # remove termcolor dep when updating to the next version of codespan-reporting # termcolor minimum version was wrong and was fixed in # https://github.com/brendanzab/codespan/commit/e99c867339a877731437e7ee6a903a3d03b5439e From acaeb8d9b137870436342e81b2621de5638f39f3 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Wed, 15 Nov 2023 16:40:12 -0500 Subject: [PATCH 34/34] Backport 0.18.1 changelog (#4694) --- CHANGELOG.md | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 273587eb52c..804ce9e57f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,8 +40,6 @@ Bottom level categories: ## Unreleased -For naga changelogs at or before v0.14.0. See [naga's changelog](naga/CHANGELOG.md). - ### Changes #### General @@ -63,12 +61,30 @@ For naga changelogs at or before v0.14.0. See [naga's changelog](naga/CHANGELOG. - Improve algorithm used by module compaction. By @jimblandy in [#4662](https://github.com/gfx-rs/wgpu/pull/4662). -- In Metal Shading Language output, fix issue where local variables were sometimes using variable names from previous functions. - - When reading GLSL, fix the argument types of the double-precision floating-point overloads of the `dot`, `reflect`, `distance`, and `ldexp` builtin functions. Correct the WGSL generated for constructing 64-bit floating-point matrices. Add tests for all the above. By @jimblandy in [#4684](https://github.com/gfx-rs/wgpu/pull/4684). +## v0.18.1 (2023-11-15) + +(naga version 0.14.1) + +### Bug Fixes + +#### General +- Fix panic in `Surface::configure` in debug builds. By @cwfitzgerald in [#4635](https://github.com/gfx-rs/wgpu/pull/4635) +- Fix crash when all the following are true: By @teoxoy in #[#4642](https://github.com/gfx-rs/wgpu/pull/4642) + - Passing a naga module directly to `Device::create_shader_module`. + - `InstanceFlags::DEBUG` is enabled. + +#### DX12 +- Always use HLSL 2018 when using DXC to compile HLSL shaders. By @daxpedda in [#4629](https://github.com/gfx-rs/wgpu/pull/4629) + +#### Metal +- In Metal Shading Language output, fix issue where local variables were sometimes using variable names from previous functions. By @DJMcNab in [#4594](https://github.com/gfx-rs/wgpu/pull/4594) + ## v0.18.0 (2023-10-25) +For naga changelogs at or before v0.14.0. See [naga's changelog](naga/CHANGELOG.md). + ### Desktop OpenGL 3.3+ Support on Windows We now support OpenGL on Windows! This brings support for a vast majority of the hardware that used to be covered by our DX11 backend. As of this writing we support OpenGL 3.3+, though there are efforts to reduce that further.