Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[wgsl-in, wgsl-out, glsl-in] WebGPU compliant dual source blending feature #7146

Open
wants to merge 10 commits into
base: trunk
Choose a base branch
from
Prev Previous commit
Next Next commit
Naga implementation of WebGPU style dual source blending
  • Loading branch information
Wumpf authored and ErichDonGubler committed Feb 28, 2025
commit 253f193cdf1ddd246da566e612b9e74bcbd2f49f
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ By @brodycj in [#6924](https://github.com/gfx-rs/wgpu/pull/6924).
#### WebGPU

- Improve efficiency of dropping read-only buffer mappings. By @kpreid in [#7007](https://github.com/gfx-rs/wgpu/pull/7007).
- `wgpu::Features::DUAL_SOURCE_BLENDING` is now available on WebGPU. By @wumpf in [#????](https://github.com/gfx-rs/wgpu/pull/????).
- `wgpu::Features::DUAL_SOURCE_BLENDING` is now available on WebGPU. By @wumpf in [#????](https://github.com/gfx-rs/wgpu/pull/????). TODO: not the full story, not a WebGPU thing, it's a Naga/general thing.

### Performance

Expand Down
4 changes: 2 additions & 2 deletions naga/src/back/glsl/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -604,15 +604,15 @@ impl<W> Writer<'_, W> {
location: _,
interpolation,
sampling,
second_blend_source,
blend_src,
} => {
if interpolation == Some(Interpolation::Linear) {
self.features.request(Features::NOPERSPECTIVE_QUALIFIER);
}
if sampling == Some(Sampling::Sample) {
self.features.request(Features::SAMPLE_QUALIFIER);
}
if second_blend_source {
if blend_src.is_some() {
self.features.request(Features::DUAL_SOURCE_BLENDING);
}
}
Expand Down
20 changes: 11 additions & 9 deletions naga/src/back/glsl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -455,8 +455,7 @@ impl fmt::Display for VaryingName<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self.binding {
crate::Binding::Location {
second_blend_source: true,
..
blend_src: Some(1), ..
} => {
write!(f, "_fs2p_location1",)
}
Expand Down Expand Up @@ -1491,13 +1490,13 @@ impl<'a, W: Write> Writer<'a, W> {
Some(binding) => binding,
};

let (location, interpolation, sampling, second_blend_source) = match *binding {
let (location, interpolation, sampling, blend_src) = match *binding {
crate::Binding::Location {
location,
interpolation,
sampling,
second_blend_source,
} => (location, interpolation, sampling, second_blend_source),
blend_src,
} => (location, interpolation, sampling, blend_src),
crate::Binding::BuiltIn(built_in) => {
if let crate::BuiltIn::Position { invariant: true } = built_in {
match (self.options.version, self.entry_point.stage) {
Expand Down Expand Up @@ -1544,16 +1543,19 @@ impl<'a, W: Write> Writer<'a, W> {
|| !emit_interpolation_and_auxiliary
{
if self.options.version.supports_io_locations() {
if second_blend_source {
write!(self.out, "layout(location = {location}, index = 1) ")?;
if let Some(blend_src) = blend_src {
write!(
self.out,
"layout(location = {location}, index = {blend_src}) "
)?;
} else {
write!(self.out, "layout(location = {location}) ")?;
}
None
} else {
Some(VaryingLocation {
location,
index: second_blend_source as u32,
index: blend_src.unwrap_or(0),
})
}
} else {
Expand Down Expand Up @@ -1594,7 +1596,7 @@ impl<'a, W: Write> Writer<'a, W> {
location,
interpolation: None,
sampling: None,
second_blend_source,
blend_src,
},
stage: self.entry_point.stage,
options: VaryingOptions::from_writer_options(self.options, output),
Expand Down
9 changes: 2 additions & 7 deletions naga/src/back/hlsl/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -528,16 +528,11 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
write!(self.out, " : {builtin_str}")?;
}
Some(crate::Binding::Location {
second_blend_source: true,
..
blend_src: Some(1), ..
}) => {
write!(self.out, " : SV_Target1")?;
}
Some(crate::Binding::Location {
location,
second_blend_source: false,
..
}) => {
Some(crate::Binding::Location { location, .. }) => {
if stage == Some((ShaderStage::Fragment, Io::Output)) {
write!(self.out, " : SV_Target{location}")?;
} else {
Expand Down
18 changes: 8 additions & 10 deletions naga/src/back/msl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ enum ResolvedBinding {
Attribute(u32),
Color {
location: u32,
second_blend_source: bool,
blend_src: Option<u32>,
},
User {
prefix: &'static str,
Expand Down Expand Up @@ -459,18 +459,16 @@ impl Options {
location,
interpolation,
sampling,
second_blend_source,
blend_src,
} => match mode {
LocationMode::VertexInput => Ok(ResolvedBinding::Attribute(location)),
LocationMode::FragmentOutput => {
if second_blend_source && self.lang_version < (1, 2) {
return Err(Error::UnsupportedAttribute(
"second_blend_source".to_string(),
));
if blend_src.is_some() && self.lang_version < (1, 2) {
return Err(Error::UnsupportedAttribute("blend_src".to_string()));
}
Ok(ResolvedBinding::Color {
location,
second_blend_source,
blend_src,
})
}
LocationMode::VertexOutput | LocationMode::FragmentInput => {
Expand Down Expand Up @@ -632,10 +630,10 @@ impl ResolvedBinding {
Self::Attribute(index) => write!(out, "attribute({index})")?,
Self::Color {
location,
second_blend_source,
blend_src,
} => {
if second_blend_source {
write!(out, "color({location}) index(1)")?
if let Some(blend_src) = blend_src {
write!(out, "color({location}) index({blend_src})")?
} else {
write!(out, "color({location})")?
}
Expand Down
6 changes: 3 additions & 3 deletions naga/src/back/spv/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1745,7 +1745,7 @@ impl Writer {
location,
interpolation,
sampling,
second_blend_source,
blend_src,
} => {
self.decorate(id, Decoration::Location, &[location]);

Expand Down Expand Up @@ -1790,8 +1790,8 @@ impl Writer {
}
}
}
if second_blend_source {
self.decorate(id, Decoration::Index, &[1]);
if let Some(blend_src) = blend_src {
self.decorate(id, Decoration::Index, &[blend_src]);
}
}
crate::Binding::BuiltIn(built_in) => {
Expand Down
10 changes: 5 additions & 5 deletions naga/src/back/wgsl/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ enum Attribute {
Invariant,
Interpolate(Option<crate::Interpolation>, Option<crate::Sampling>),
Location(u32),
SecondBlendSource,
BlendSrc(u32),
Stage(ShaderStage),
WorkGroupSize([u32; 3]),
}
Expand Down Expand Up @@ -340,7 +340,7 @@ impl<W: Write> Writer<W> {
for attribute in attributes {
match *attribute {
Attribute::Location(id) => write!(self.out, "@location({id}) ")?,
Attribute::SecondBlendSource => write!(self.out, "@second_blend_source ")?,
Attribute::BlendSrc(blend_src) => write!(self.out, "@blend_src({blend_src}) ")?,
Attribute::BuiltIn(builtin_attrib) => {
let builtin = builtin_str(builtin_attrib)?;
write!(self.out, "@builtin({builtin}) ")?;
Expand Down Expand Up @@ -2166,7 +2166,7 @@ fn map_binding_to_attribute(binding: &crate::Binding) -> Vec<Attribute> {
location,
interpolation,
sampling,
second_blend_source: false,
blend_src: None,
} => vec![
Attribute::Location(location),
Attribute::Interpolate(interpolation, sampling),
Expand All @@ -2175,10 +2175,10 @@ fn map_binding_to_attribute(binding: &crate::Binding) -> Vec<Attribute> {
location,
interpolation,
sampling,
second_blend_source: true,
blend_src: Some(blend_src),
} => vec![
Attribute::Location(location),
Attribute::SecondBlendSource,
Attribute::BlendSrc(blend_src),
Attribute::Interpolate(interpolation, sampling),
],
}
Expand Down
4 changes: 2 additions & 2 deletions naga/src/front/glsl/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1442,7 +1442,7 @@ impl Context<'_> {
location,
interpolation,
sampling: None,
second_blend_source: false,
blend_src: None,
};
location += 1;

Expand Down Expand Up @@ -1478,7 +1478,7 @@ impl Context<'_> {
location,
interpolation,
sampling: None,
second_blend_source: false,
blend_src: None,
};
location += 1;
binding
Expand Down
2 changes: 1 addition & 1 deletion naga/src/front/glsl/variables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ impl Frontend {
location,
interpolation,
sampling,
second_blend_source: false,
blend_src: None,
},
handle,
storage,
Expand Down
2 changes: 1 addition & 1 deletion naga/src/front/interpolator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ impl crate::Binding {
location: _,
interpolation: ref mut interpolation @ None,
ref mut sampling,
second_blend_source: _,
blend_src: _,
} = *self
{
match ty.scalar_kind() {
Expand Down
2 changes: 1 addition & 1 deletion naga/src/front/spv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ impl Decoration {
location,
interpolation,
sampling,
second_blend_source: false,
blend_src: None,
}),
_ => Err(Error::MissingDecoration(spirv::Decoration::Location)),
}
Expand Down
10 changes: 8 additions & 2 deletions naga/src/front/wgsl/lower/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3367,15 +3367,21 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
Some(ast::Binding::BuiltIn(b)) => Some(crate::Binding::BuiltIn(b)),
Some(ast::Binding::Location {
location,
second_blend_source,
interpolation,
sampling,
blend_src,
}) => {
let blend_src = if let Some(blend_src) = blend_src {
Some(self.const_u32(blend_src, &mut ctx.as_const())?.0)
} else {
None
};

let mut binding = crate::Binding::Location {
location: self.const_u32(location, &mut ctx.as_const())?.0,
second_blend_source,
interpolation,
sampling,
blend_src,
};
binding.apply_default_interpolation(&ctx.module.types[ty].inner);
Some(binding)
Expand Down
2 changes: 1 addition & 1 deletion naga/src/front/wgsl/parse/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,9 @@ pub enum Binding<'a> {
BuiltIn(crate::BuiltIn),
Location {
location: Handle<Expression<'a>>,
second_blend_source: bool,
interpolation: Option<crate::Interpolation>,
sampling: Option<crate::Sampling>,
blend_src: Option<Handle<Expression<'a>>>,
},
}

Expand Down
43 changes: 26 additions & 17 deletions naga/src/front/wgsl/parse/directive/enable_extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,31 @@ 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 {}
pub struct EnableExtensions {
dual_source_blending: bool,
}

impl EnableExtensions {
pub(crate) const fn empty() -> Self {
Self {}
Self {
dual_source_blending: false,
}
}

/// 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;
let field: &mut bool = match ext {
ImplementedEnableExtension::DualSourceBlending => &mut self.dual_source_blending,
};
*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 {}
match ext {
ImplementedEnableExtension::DualSourceBlending => self.dual_source_blending,
}
}
}

Expand Down Expand Up @@ -55,7 +62,7 @@ impl EnableExtension {
Self::Unimplemented(UnimplementedEnableExtension::ClipDistances)
}
Self::DUAL_SOURCE_BLENDING => {
Self::Unimplemented(UnimplementedEnableExtension::DualSourceBlending)
Self::Implemented(ImplementedEnableExtension::DualSourceBlending)
}
_ => return Err(Error::UnknownEnableExtension(span, word)),
})
Expand All @@ -64,19 +71,28 @@ impl EnableExtension {
/// Maps this [`EnableExtension`] into the sentinel word associated with it in WGSL.
pub const fn to_ident(self) -> &'static str {
match self {
Self::Implemented(kind) => match kind {},
Self::Implemented(kind) => match kind {
ImplementedEnableExtension::DualSourceBlending => Self::DUAL_SOURCE_BLENDING,
},

Self::Unimplemented(kind) => match kind {
UnimplementedEnableExtension::F16 => Self::F16,
UnimplementedEnableExtension::ClipDistances => Self::CLIP_DISTANCES,
UnimplementedEnableExtension::DualSourceBlending => Self::DUAL_SOURCE_BLENDING,
},
}
}
}

/// A variant of [`EnableExtension::Implemented`].
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
pub enum ImplementedEnableExtension {}
pub enum ImplementedEnableExtension {
/// 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,
}

/// A variant of [`EnableExtension::Unimplemented`].
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
Expand All @@ -93,20 +109,13 @@ pub enum UnimplementedEnableExtension {
///
/// [`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,
}
}
}
Loading