Skip to content

Commit

Permalink
feat(wgsl-in): create skeleton for enable directives
Browse files Browse the repository at this point in the history
Co-Authored-By: FL33TW00D <chris@fleetwood.dev>
  • Loading branch information
ErichDonGubler and FL33TW00D committed Oct 18, 2024
1 parent b3f665b commit 685e73c
Show file tree
Hide file tree
Showing 7 changed files with 202 additions and 20 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ By @bradwerth [#6216](https://github.com/gfx-rs/wgpu/pull/6216).
- Support local `const` declarations in WGSL. By @sagudev in [#6156](https://github.com/gfx-rs/wgpu/pull/6156).
- Implemented `const_assert` in WGSL. By @sagudev in [#6198](https://github.com/gfx-rs/wgpu/pull/6198).
- Support polyfilling `inverse` in WGSL. By @chyyran in [#6385](https://github.com/gfx-rs/wgpu/pull/6385).
- Add an internal skeleton for parsing `requires`, `enable`, and `diagnostic` directives that don't yet do anything besides emit nicer errors. By @ErichDonGubler in [#6352](https://github.com/gfx-rs/wgpu/pull/6352).
- Add an internal skeleton for parsing `requires`, `enable`, and `diagnostic` directives that don't yet do anything besides emit nicer errors. By @ErichDonGubler in [#6352](https://github.com/gfx-rs/wgpu/pull/6352), [#6424](https://github.com/gfx-rs/wgpu/pull/6424).

#### General

Expand Down
38 changes: 38 additions & 0 deletions naga/src/front/wgsl/error.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
use crate::front::wgsl::parse::directive::enable_extension::{
EnableExtension, UnimplementedEnableExtension,
};
use crate::front::wgsl::parse::directive::{DirectiveKind, UnimplementedDirectiveKind};
use crate::front::wgsl::parse::lexer::Token;
use crate::front::wgsl::Scalar;
Expand Down Expand Up @@ -184,6 +187,7 @@ pub(crate) enum Error<'a> {
UnknownType(Span),
UnknownStorageFormat(Span),
UnknownConservativeDepth(Span),
UnknownEnableExtension(Span, &'a str),
SizeAttributeTooLow(Span, u32),
AlignAttributeTooLow(Span, Alignment),
NonPowerOfTwoAlignAttribute(Span),
Expand Down Expand Up @@ -273,6 +277,10 @@ pub(crate) enum Error<'a> {
DirectiveAfterFirstGlobalDecl {
directive_span: Span,
},
EnableExtensionNotYetImplemented {
kind: UnimplementedEnableExtension,
span: Span,
},
}

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -517,6 +525,14 @@ impl<'a> Error<'a> {
labels: vec![(bad_span, "unknown type".into())],
notes: vec![],
},
Error::UnknownEnableExtension(span, word) => ParseError {
message: format!("unknown enable-extension `{}`", word),
labels: vec![(span, "".into())],
notes: vec![
"See available extensions at <https://www.w3.org/TR/WGSL/#enable-extension>."
.into(),
],
},
Error::SizeAttributeTooLow(bad_span, min_size) => ParseError {
message: format!("struct member size must be at least {min_size}"),
labels: vec![(bad_span, format!("must be at least {min_size}").into())],
Expand Down Expand Up @@ -899,6 +915,28 @@ impl<'a> Error<'a> {
)
.into()],
},
Error::EnableExtensionNotYetImplemented { kind, span } => ParseError {
message: format!(
"the `{}` extension is not yet supported (sorry!)",
EnableExtension::Unimplemented(kind).to_ident()
),
labels: vec![(
span,
concat!(
"this extension specifies standard functionality ",
"which is not yet implemented in Naga"
)
.into(),
)],
notes: vec![format!(
concat!(
"Let Naga maintainers know that you ran into this at ",
"<https://github.com/gfx-rs/wgpu/issues/{}>, ",
"so they can prioritize it!"
),
kind.tracking_issue_num()
)],
},
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions naga/src/front/wgsl/parse/ast.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use crate::front::wgsl::parse::directive::enable_extension::EnableExtensions;
use crate::front::wgsl::parse::number::Number;
use crate::front::wgsl::Scalar;
use crate::{Arena, FastIndexSet, Handle, Span};
use std::hash::Hash;

#[derive(Debug, Default)]
pub struct TranslationUnit<'a> {
pub enable_extensions: EnableExtensions,
pub decls: Arena<GlobalDecl<'a>>,
/// The common expressions arena for the entire translation unit.
///
Expand Down
25 changes: 7 additions & 18 deletions naga/src/front/wgsl/parse/directive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@
//!
//! See also <https://www.w3.org/TR/WGSL/#directives>.
pub mod enable_extension;

/// A parsed sentinel word indicating the type of directive to be parsed next.
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
pub enum DirectiveKind {
/// An [`enable_extension`].
Enable,
Unimplemented(UnimplementedDirectiveKind),
}

Expand All @@ -17,7 +21,7 @@ impl DirectiveKind {
pub fn from_ident(s: &str) -> Option<Self> {
Some(match s {
Self::DIAGNOSTIC => Self::Unimplemented(UnimplementedDirectiveKind::Diagnostic),
Self::ENABLE => Self::Unimplemented(UnimplementedDirectiveKind::Enable),
Self::ENABLE => Self::Enable,
Self::REQUIRES => Self::Unimplemented(UnimplementedDirectiveKind::Requires),
_ => return None,
})
Expand All @@ -26,9 +30,9 @@ impl DirectiveKind {
/// Maps this [`DirectiveKind`] into the sentinel word associated with it in WGSL.
pub const fn to_ident(self) -> &'static str {
match self {
Self::Enable => Self::ENABLE,
Self::Unimplemented(kind) => match kind {
UnimplementedDirectiveKind::Diagnostic => Self::DIAGNOSTIC,
UnimplementedDirectiveKind::Enable => Self::ENABLE,
UnimplementedDirectiveKind::Requires => Self::REQUIRES,
},
}
Expand All @@ -47,7 +51,6 @@ impl DirectiveKind {
#[cfg_attr(test, derive(strum::EnumIter))]
pub enum UnimplementedDirectiveKind {
Diagnostic,
Enable,
Requires,
}

Expand All @@ -56,7 +59,6 @@ impl UnimplementedDirectiveKind {
match self {
Self::Diagnostic => 5320,
Self::Requires => 6350,
Self::Enable => 5476,
}
}
}
Expand Down Expand Up @@ -86,19 +88,6 @@ error: `diagnostic` is not yet implemented
= note: Let Naga maintainers know that you ran into this at <https://github.com/gfx-rs/wgpu/issues/5320>, so they can prioritize it!
";
}
UnimplementedDirectiveKind::Enable => {
shader = "enable f16;";
expected_msg = "\
error: `enable` is not yet implemented
┌─ wgsl:1:1
1 │ enable f16;
│ ^^^^^^ this global directive is standard, but not yet implemented
= note: Let Naga maintainers know that you ran into this at <https://github.com/gfx-rs/wgpu/issues/5476>, so they can prioritize it!
";
}
UnimplementedDirectiveKind::Requires => {
Expand Down Expand Up @@ -139,7 +128,7 @@ error: expected global declaration, but found a global directive
";
}
DirectiveKind::Unimplemented(UnimplementedDirectiveKind::Enable) => {
DirectiveKind::Enable => {
directive = "enable f16";
expected_msg = "\
error: expected global declaration, but found a global directive
Expand Down
112 changes: 112 additions & 0 deletions naga/src/front/wgsl/parse/directive/enable_extension.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
//! `enable …;` extensions in WGSL.
//!
//! The focal point of this module is the [`EnableExtension`] API.
use crate::{front::wgsl::error::Error, Span};

/// Tracks the status of every enable extension known to Naga.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct EnableExtensions {}

impl EnableExtensions {
pub(crate) const fn empty() -> Self {
Self {}
}

/// Add an enable extension to the set requested by a module.
#[allow(unreachable_code)]
pub(crate) fn add(&mut self, ext: ImplementedEnableExtension) {
let _field: &mut bool = match ext {};
*_field = true;
}

/// Query whether an enable extension tracked here has been requested.
#[allow(unused)]
pub(crate) const fn contains(&self, ext: ImplementedEnableExtension) -> bool {
match ext {}
}
}

impl Default for EnableExtensions {
fn default() -> Self {
Self::empty()
}
}

/// A shader language extension not guaranteed to be present in all environments.
///
/// WGSL spec.: <https://www.w3.org/TR/WGSL/#enable-extensions-sec>
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
pub enum EnableExtension {
#[allow(unused)]
Implemented(ImplementedEnableExtension),
Unimplemented(UnimplementedEnableExtension),
}

impl EnableExtension {
const F16: &'static str = "f16";
const CLIP_DISTANCES: &'static str = "clip_distances";
const DUAL_SOURCE_BLENDING: &'static str = "dual_source_blending";

/// Convert from a sentinel word in WGSL into its associated [`EnableExtension`], if possible.
pub(crate) fn from_ident(word: &str, span: Span) -> Result<Self, Error<'_>> {
Ok(match word {
Self::F16 => Self::Unimplemented(UnimplementedEnableExtension::F16),
Self::CLIP_DISTANCES => {
Self::Unimplemented(UnimplementedEnableExtension::ClipDistances)
}
Self::DUAL_SOURCE_BLENDING => {
Self::Unimplemented(UnimplementedEnableExtension::DualSourceBlending)
}
_ => return Err(Error::UnknownEnableExtension(span, word)),
})
}

/// Maps this [`EnableExtension`] into the sentinel word associated with it in WGSL.
pub fn to_ident(self) -> &'static str {
match self {
Self::Implemented(kind) => match kind {},
Self::Unimplemented(kind) => match kind {
UnimplementedEnableExtension::F16 => Self::F16,
UnimplementedEnableExtension::ClipDistances => todo!(),
UnimplementedEnableExtension::DualSourceBlending => todo!(),
},
}
}
}

/// A variant of [`EnableExtension::Implemented`].
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
pub enum ImplementedEnableExtension {}

/// A variant of [`EnableExtension::Unimplemented`].
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
pub enum UnimplementedEnableExtension {
/// Enables `f16`/`half` primitive support in all shader languages.
///
/// In the WGSL standard, this corresponds to [`enable f16;`].
///
/// [`enable f16;`]: https://www.w3.org/TR/WGSL/#extension-f16
F16,
/// Enables the `clip_distances` variable in WGSL.
///
/// In the WGSL standard, this corresponds to [`enable clip_distances;`].
///
/// [`enable clip_distances;`]: https://www.w3.org/TR/WGSL/#extension-f16
ClipDistances,
/// Enables the `blend_src` attribute in WGSL.
///
/// In the WGSL standard, this corresponds to [`enable dual_source_blending;`].
///
/// [`enable dual_source_blending;`]: https://www.w3.org/TR/WGSL/#extension-f16
DualSourceBlending,
}

impl UnimplementedEnableExtension {
pub(crate) const fn tracking_issue_num(self) -> u16 {
match self {
Self::F16 => 4384,
Self::ClipDistances => 6236,
Self::DualSourceBlending => 6402,
}
}
}
4 changes: 4 additions & 0 deletions naga/src/front/wgsl/parse/lexer.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::{number::consume_number, Error, ExpectedToken};
use crate::front::wgsl::error::NumberError;
use crate::front::wgsl::parse::directive::enable_extension::EnableExtensions;
use crate::front::wgsl::parse::{conv, Number};
use crate::front::wgsl::Scalar;
use crate::Span;
Expand Down Expand Up @@ -204,6 +205,8 @@ pub(in crate::front::wgsl) struct Lexer<'a> {
pub(in crate::front::wgsl) source: &'a str,
// The byte offset of the end of the last non-trivia token.
last_end_offset: usize,
#[allow(dead_code)]
pub(in crate::front::wgsl) enable_extensions: EnableExtensions,
}

impl<'a> Lexer<'a> {
Expand All @@ -212,6 +215,7 @@ impl<'a> Lexer<'a> {
input,
source: input,
last_end_offset: 0,
enable_extensions: EnableExtensions::empty(),
}
}

Expand Down
39 changes: 38 additions & 1 deletion naga/src/front/wgsl/parse/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use crate::front::wgsl::error::{Error, ExpectedToken};
use crate::front::wgsl::parse::directive::enable_extension::{
EnableExtension, EnableExtensions, ImplementedEnableExtension,
};
use crate::front::wgsl::parse::directive::DirectiveKind;
use crate::front::wgsl::parse::lexer::{Lexer, Token};
use crate::front::wgsl::parse::number::Number;
Expand Down Expand Up @@ -2258,6 +2261,23 @@ impl Parser {
Ok(fun)
}

/// Parses an `enable` extension.
#[allow(unused, unreachable_code)]
fn enable_extension_ident<'a>(
&self,
lexer: &mut Lexer<'a>,
) -> Result<ImplementedEnableExtension, Error<'a>> {
let (ident, span) = lexer.next_ident_with_span()?;
let kind = EnableExtension::from_ident(ident, span)?;
let extension = match kind {
EnableExtension::Implemented(kind) => kind,
EnableExtension::Unimplemented(kind) => {
return Err(Error::EnableExtensionNotYetImplemented { kind, span })
}
};
Ok(extension)
}

fn global_decl<'a>(
&mut self,
lexer: &mut Lexer<'a>,
Expand Down Expand Up @@ -2480,14 +2500,28 @@ impl Parser {

let mut lexer = Lexer::new(source);
let mut tu = ast::TranslationUnit::default();
let mut enable_extensions = EnableExtensions::empty();

// Parse directives.
#[allow(clippy::never_loop, unreachable_code)]
while let Ok((ident, span)) = lexer.peek_ident_with_span() {
if let Some(kind) = DirectiveKind::from_ident(ident) {
self.push_rule_span(Rule::Directive, &mut lexer);
let _ = lexer.next_ident_with_span().unwrap();
match kind {
DirectiveKind::Enable => {
enable_extensions.add(self.enable_extension_ident(&mut lexer)?);
while lexer.skip(Token::Separator(',')) {
enable_extensions.add(self.enable_extension_ident(&mut lexer)?);
}

let semicolon = Token::Separator(';');
if !lexer.skip(semicolon) {
return Err(Error::Unexpected(
lexer.next().1,
ExpectedToken::Token(semicolon),
));
}
}
DirectiveKind::Unimplemented(kind) => {
return Err(Error::DirectiveNotYetImplemented { kind, span })
}
Expand All @@ -2498,6 +2532,9 @@ impl Parser {
}
}

lexer.enable_extensions = enable_extensions.clone();
tu.enable_extensions = enable_extensions;

loop {
match self.global_decl(&mut lexer, &mut tu) {
Err(error) => return Err(error),
Expand Down

0 comments on commit 685e73c

Please sign in to comment.