Skip to content

Commit c84b675

Browse files
diag(wgsl-in): enable-extensions: let user choose "unrecognized" instead of "unsupported"
For WebGPU environments like Firefox, it's important to withhold information that's not necessary for an app author using JS to know. This prevents things like fingerprinting, and makes it easier for uniform developer experience across implementations of WebGPU. Our current diagnostic noting that an extension is unsupported is helpful, but ultimately is a minor leak of information that WebGPU is better without. Let WebGPU environments pick what approach they'd like by adding a "treat missing capabilities as unknown" flag.
1 parent 2aa2541 commit c84b675

6 files changed

Lines changed: 67 additions & 18 deletions

File tree

naga-cli/src/bin/naga.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use anyhow::{anyhow, Context as _};
2+
use naga::front::wgsl::TreatMissingCapabiltiesAsUnknown;
23
use std::fs;
34
use std::{error::Error, fmt, io::Read, path::Path, str::FromStr};
45

@@ -152,6 +153,11 @@ struct Args {
152153
/// "67108864"), the string "none", or the string "all".
153154
#[argh(option, default = "CapabilitiesArg(naga::valid::Capabilities::all())")]
154155
capabilities: CapabilitiesArg,
156+
157+
/// whether diagnostics should recognize enable-extensions whose capabilities are missing, or
158+
/// pretend that such an extension is unknown.
159+
#[argh(switch)]
160+
treat_missing_capabilities_as_unknown: bool,
155161
}
156162

157163
/// Newtype so we can implement [`FromStr`] for `BoundsCheckPolicy`.
@@ -390,7 +396,7 @@ struct Parameters<'a> {
390396
shader_stage: Option<ShaderStage>,
391397
defines: FastHashMap<String, String>,
392398
capabilities: naga::valid::Capabilities,
393-
399+
treat_missing_capabilities_as_unknown: bool,
394400
/// We use this copy of `args.compact` to know whether we should pass the
395401
/// entrypoint to `process_overrides`, which will result in removal from
396402
/// the module of anything not reachable from that entry point.
@@ -543,7 +549,7 @@ fn run() -> anyhow::Result<()> {
543549
);
544550

545551
params.compact = args.compact;
546-
params.capabilities = args.capabilities.0;
552+
(??)
547553

548554
if args.bulk_validate {
549555
return bulk_validate(&args, &params);
@@ -721,12 +727,7 @@ fn parse_input(input_path: &Path, input: Vec<u8>, params: &Parameters) -> anyhow
721727
},
722728
InputKind::Wgsl => {
723729
let input = String::from_utf8(input)?;
724-
let options = naga::front::wgsl::Options {
725-
parse_doc_comments: false,
726-
capabilities: params.capabilities,
727-
};
728-
let mut frontend = naga::front::wgsl::Frontend::new_with_options(options);
729-
let result = frontend.parse(&input);
730+
(??) let result = naga::front::wgsl::parse_str(&input);
730731
match result {
731732
Ok(v) => Parsed {
732733
module: v,

naga-test/src/lib.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use std::{
99
path::{Path, PathBuf},
1010
};
1111

12-
use naga::compact::KeepUnused;
12+
use naga::{compact::KeepUnused, front::wgsl::TreatMissingCapabiltiesAsUnknown};
1313
use ron::de;
1414

1515
bitflags::bitflags! {
@@ -79,12 +79,16 @@ where
7979
#[serde(default)]
8080
pub struct WgslInParameters {
8181
pub parse_doc_comments: bool,
82+
pub treat_missing_capabilities_as_unknown: bool,
8283
}
8384
impl From<&WgslInParameters> for naga::front::wgsl::Options {
8485
fn from(value: &WgslInParameters) -> Self {
8586
Self {
8687
parse_doc_comments: value.parse_doc_comments,
8788
capabilities: naga::valid::Capabilities::all(),
89+
treat_missing_capabilities_as_unknown: TreatMissingCapabiltiesAsUnknown::from_bool(
90+
value.treat_missing_capabilities_as_unknown,
91+
),
8892
}
8993
}
9094
}

naga/src/front/wgsl/error.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -479,10 +479,14 @@ impl From<EnableExtensionNotAvailableError> for Error<'_> {
479479
kind: extension,
480480
}
481481
}
482-
EnableExtensionNotAvailableErrorReason::NotSupported => {
483-
Error::EnableExtensionNotSupported {
484-
span,
485-
kind: extension,
482+
EnableExtensionNotAvailableErrorReason::NotSupported { treat_as_unknown } => {
483+
if treat_as_unknown {
484+
Error::UnknownEnableExtension(span, extension.to_ident())
485+
} else {
486+
Error::EnableExtensionNotSupported {
487+
span,
488+
kind: extension,
489+
}
486490
}
487491
}
488492
}

naga/src/front/wgsl/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ mod parse;
1212
mod tests;
1313

1414
pub use parse::directive::enable_extension::{
15-
EnableExtension, ImplementedEnableExtension, UnimplementedEnableExtension,
15+
EnableExtension, ImplementedEnableExtension, TreatMissingCapabiltiesAsUnknown,
16+
UnimplementedEnableExtension,
1617
};
1718

1819
pub use crate::front::wgsl::error::ParseError;

naga/src/front/wgsl/parse/directive/enable_extension.rs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ impl EnableExtensions {
4949
span: Span,
5050
extension: ImplementedEnableExtension,
5151
capabilities: Capabilities,
52+
treat_missing_capabilities_as_unknown: TreatMissingCapabiltiesAsUnknown,
5253
) -> core::result::Result<(), EnableExtensionNotAvailableError> {
5354
let field = match extension {
5455
ImplementedEnableExtension::WgpuMeshShader => &mut self.wgpu_mesh_shader,
@@ -69,10 +70,11 @@ impl EnableExtensions {
6970
// Check if the required capability is supported
7071
let required_capability = extension.capability();
7172
if !capabilities.contains(required_capability) {
73+
let treat_as_unknown = treat_missing_capabilities_as_unknown.to_bool();
7274
return Err(EnableExtensionNotAvailableError {
7375
extension,
7476
span,
75-
reason: EnableExtensionNotAvailableErrorReason::NotSupported,
77+
reason: EnableExtensionNotAvailableErrorReason::NotSupported { treat_as_unknown },
7678
});
7779
}
7880

@@ -128,7 +130,32 @@ pub struct EnableExtensionNotAvailableError {
128130
#[derive(Clone, Debug, Eq, PartialEq)]
129131
pub enum EnableExtensionNotAvailableErrorReason {
130132
NotEnabled,
131-
NotSupported,
133+
NotSupported { treat_as_unknown: bool },
134+
}
135+
136+
/// Whether calls to [`EnableExtensions::add`] should hide or inform the user of an unsupported
137+
/// capability behind an [`ImplementedEnableExtension`] when converted to an [`Error`].
138+
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
139+
pub enum TreatMissingCapabiltiesAsUnknown {
140+
Yes,
141+
#[default]
142+
No,
143+
}
144+
145+
impl TreatMissingCapabiltiesAsUnknown {
146+
pub const fn to_bool(self) -> bool {
147+
match self {
148+
Self::Yes => true,
149+
Self::No => false,
150+
}
151+
}
152+
153+
pub const fn from_bool(value: bool) -> Self {
154+
match value {
155+
true => Self::Yes,
156+
false => Self::No,
157+
}
158+
}
132159
}
133160

134161
/// An enable-extension not guaranteed to be present in all environments.

naga/src/front/wgsl/parse/mod.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ use crate::diagnostic_filter::{
66
ShouldConflictOnFullDuplicate, StandardFilterableTriggeringRule,
77
};
88
use crate::front::wgsl::error::{DiagnosticAttributeNotSupportedPosition, Error, ExpectedToken};
9-
use crate::front::wgsl::parse::directive::enable_extension::{EnableExtension, EnableExtensions};
9+
use crate::front::wgsl::parse::directive::enable_extension::{
10+
self, EnableExtension, EnableExtensions,
11+
};
1012
use crate::front::wgsl::parse::directive::language_extension::LanguageExtension;
1113
use crate::front::wgsl::parse::directive::DirectiveKind;
1214
use crate::front::wgsl::parse::lexer::{Lexer, Token, TokenSpan};
@@ -275,6 +277,9 @@ impl<'a> BindingParser<'a> {
275277
pub struct Options {
276278
/// Controls whether the parser should parse doc comments.
277279
pub parse_doc_comments: bool,
280+
/// Whether an unknown or unsupported diagnostic should be emitted for enable-extensions whose
281+
/// capability is disabled.
282+
pub treat_missing_capabilities_as_unknown: enable_extension::TreatMissingCapabiltiesAsUnknown,
278283
/// Capabilities to enable during parsing.
279284
pub capabilities: crate::valid::Capabilities,
280285
}
@@ -285,6 +290,8 @@ impl Options {
285290
Options {
286291
parse_doc_comments: false,
287292
capabilities: crate::valid::Capabilities::all(),
293+
treat_missing_capabilities_as_unknown:
294+
enable_extension::TreatMissingCapabiltiesAsUnknown::No,
288295
}
289296
}
290297
}
@@ -2247,7 +2254,12 @@ impl Parser {
22472254
span,
22482255
}));
22492256
}
2250-
enable_extensions.add(span, extension, options.capabilities)?;
2257+
enable_extensions.add(
2258+
span,
2259+
extension,
2260+
options.capabilities,
2261+
options.treat_missing_capabilities_as_unknown,
2262+
)?;
22512263
Ok(())
22522264
})?;
22532265
}

0 commit comments

Comments
 (0)