From 406726c533bda8bce9df1f224809c4ac1ec2a262 Mon Sep 17 00:00:00 2001 From: Andy Leiserson Date: Mon, 12 Jan 2026 11:21:26 -0800 Subject: [PATCH] fix(naga): Support dual-source blending for SPIR-V shaders Fixes #8864 --- CHANGELOG.md | 6 ++++ naga/src/front/spv/mod.rs | 17 +++++++++ naga/tests/in/spv/dual-source-blending.spvasm | 35 +++++++++++++++++++ naga/tests/in/spv/dual-source-blending.toml | 1 + .../out/wgsl/spv-dual-source-blending.wgsl | 23 ++++++++++++ 5 files changed, 82 insertions(+) create mode 100644 naga/tests/in/spv/dual-source-blending.spvasm create mode 100644 naga/tests/in/spv/dual-source-blending.toml create mode 100644 naga/tests/out/wgsl/spv-dual-source-blending.wgsl diff --git a/CHANGELOG.md b/CHANGELOG.md index c4dc55f9a61..65f522d78d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,9 +43,15 @@ Bottom level categories: ### New Features +#### General + - Added support for cooperative load/store operations in shaders. Currently only WGSL on the input and SPIR-V, METAL, and WGSL on the output are supported. By @kvark in [#8251](https://github.com/gfx-rs/wgpu/issues/8251). - Added support for obtaining `AdapterInfo` from `Device`. By @sagudev in [#8807](https://github.com/gfx-rs/wgpu/pull/8807). +#### naga + +- Added support for dual-source blending in SPIR-V shaders. By @andyleiserson in [#8865](https://github.com/gfx-rs/wgpu/pull/8865). + ### Bug Fixes #### General diff --git a/naga/src/front/spv/mod.rs b/naga/src/front/spv/mod.rs index 83ff1b5dfca..fa20a6d5f1a 100644 --- a/naga/src/front/spv/mod.rs +++ b/naga/src/front/spv/mod.rs @@ -215,6 +215,7 @@ struct Decoration { name: Option, built_in: Option, location: Option, + index: Option, desc_set: Option, desc_index: Option, specialization_constant_id: Option, @@ -256,6 +257,18 @@ impl Decoration { invariant, .. } => Ok(crate::Binding::BuiltIn(map_builtin(built_in, invariant)?)), + Decoration { + built_in: None, + location: Some(location), + index: Some(index), + .. + } => Ok(crate::Binding::Location { + location, + interpolation: None, + sampling: None, + blend_src: Some(index), + per_primitive: false, + }), Decoration { built_in: None, location: Some(location), @@ -746,6 +759,10 @@ impl> Frontend { inst.expect(base_words + 2)?; dec.location = Some(self.next()?); } + spirv::Decoration::Index => { + inst.expect(base_words + 2)?; + dec.index = Some(self.next()?); + } spirv::Decoration::DescriptorSet => { inst.expect(base_words + 2)?; dec.desc_set = Some(self.next()?); diff --git a/naga/tests/in/spv/dual-source-blending.spvasm b/naga/tests/in/spv/dual-source-blending.spvasm new file mode 100644 index 00000000000..a26c2fd4347 --- /dev/null +++ b/naga/tests/in/spv/dual-source-blending.spvasm @@ -0,0 +1,35 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos SPIR-V Tools Assembler; 0 +; Bound: 22 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %output0 %output1 + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 450 + OpName %main "main" + OpName %output0 "output0" + OpName %output1 "output1" + OpDecorate %output0 Location 0 + OpDecorate %output0 Index 0 + OpDecorate %output1 Location 0 + OpDecorate %output1 Index 1 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %output0 = OpVariable %_ptr_Output_v4float Output + %float_1 = OpConstant %float 1 + %float_0 = OpConstant %float 0 + %13 = OpConstantComposite %v4float %float_1 %float_0 %float_1 %float_0 + %output1 = OpVariable %_ptr_Output_v4float Output + %15 = OpConstantComposite %v4float %float_0 %float_1 %float_0 %float_1 + %main = OpFunction %void None %3 + %5 = OpLabel + OpStore %output0 %13 + OpStore %output1 %15 + OpReturn + OpFunctionEnd diff --git a/naga/tests/in/spv/dual-source-blending.toml b/naga/tests/in/spv/dual-source-blending.toml new file mode 100644 index 00000000000..da745b55ac8 --- /dev/null +++ b/naga/tests/in/spv/dual-source-blending.toml @@ -0,0 +1 @@ +capabilities = "DUAL_SOURCE_BLENDING" diff --git a/naga/tests/out/wgsl/spv-dual-source-blending.wgsl b/naga/tests/out/wgsl/spv-dual-source-blending.wgsl new file mode 100644 index 00000000000..8a88c01ea7e --- /dev/null +++ b/naga/tests/out/wgsl/spv-dual-source-blending.wgsl @@ -0,0 +1,23 @@ +enable dual_source_blending; + +struct FragmentOutput { + @location(0) @blend_src(0) member: vec4, + @location(0) @blend_src(1) member_1: vec4, +} + +var output0_: vec4; +var output1_: vec4; + +fn main_1() { + output0_ = vec4(1f, 0f, 1f, 0f); + output1_ = vec4(0f, 1f, 0f, 1f); + return; +} + +@fragment +fn main() -> FragmentOutput { + main_1(); + let _e2 = output0_; + let _e3 = output1_; + return FragmentOutput(_e2, _e3); +}