Verify `@blend_src` can only be used as fragment output
This patch adds a check that `@blend_src` can only be used as
fragment output.
Bug: chromium:341973423
Test: tint_unittests
Change-Id: I441a9e492e572bf0f7fb8c35d4695252c6b6ef42
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/191808
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
diff --git a/src/tint/lang/wgsl/resolver/dual_source_blending_extension_test.cc b/src/tint/lang/wgsl/resolver/dual_source_blending_extension_test.cc
index e4f5ad4..cad1fd0 100644
--- a/src/tint/lang/wgsl/resolver/dual_source_blending_extension_test.cc
+++ b/src/tint/lang/wgsl/resolver/dual_source_blending_extension_test.cc
@@ -188,30 +188,6 @@
EXPECT_EQ(r()->error(), "12:34 error: '@blend_src' can only be used with '@location(0)'");
}
-TEST_F(DualSourceBlendingExtensionTests, NoNonZeroCollisionsBetweenInAndOut) {
- // struct NonZeroLocation {
- // @location(1) a : vec4<f32>,
- // };
- // struct NonZeroBlendSrc {
- // @location(0) @blend_src(1) a : vec4<f32>,
- // };
- // fn X(in : NonZeroLocation) -> NonZeroBlendSrc { return NonZeroBlendSrc(); }
- // fn Y(in : NonZeroBlendSrc) -> NonZeroLocation { return NonZeroLocation(); }
- Structure("NonZeroLocation", Vector{
- Member("a", ty.vec4<f32>(), Vector{Location(1_a)}),
- });
- Structure("NonZeroBlendSrc",
- Vector{
- Member("a", ty.vec4<f32>(), Vector{Location(0_a), BlendSrc(1_a)}),
- });
- Func("X", Vector{Param("in", ty("NonZeroLocation"))}, ty("NonZeroBlendSrc"),
- Vector{Return(Call("NonZeroBlendSrc"))}, Vector{Stage(ast::PipelineStage::kFragment)});
- Func("Y", Vector{Param("in", ty("NonZeroBlendSrc"))}, ty("NonZeroLocation"),
- Vector{Return(Call("NonZeroLocation"))}, Vector{Stage(ast::PipelineStage::kFragment)});
-
- EXPECT_TRUE(r()->Resolve()) << r()->error();
-}
-
TEST_F(DualSourceBlendingExtensionTests, MixedBlendSrcAndNonBlendSrcOnLocationZero_Struct) {
// struct S {
// @location(0) a : vec4<f32>,
@@ -293,6 +269,24 @@
note: while analyzing entry point 'F')");
}
+TEST_F(DualSourceBlendingExtensionTests, BlendSrcAsFragmentInput) {
+ // struct S {
+ // @location(0) @blend_src(0) a : vec4<f32>,
+ // @location(0) @blend_src(1) b : vec4<f32>,
+ // };
+ // @fragment fn F(s_in : S) -> S { return S(); }
+ Structure("S", Vector{
+ Member("a", ty.vec4<f32>(), Vector{Location(0_a), BlendSrc(0_a)}),
+ Member("b", ty.vec4<f32>(), Vector{Location(0_a), BlendSrc(1_a)}),
+ });
+ Func("F", Vector{Param("s_in", ty("S"))}, ty("S"), Vector{Return(Call("S"))},
+ Vector{Stage(ast::PipelineStage::kFragment)});
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), R"(error: '@blend_src' can only be used for fragment shader output
+note: while analyzing entry point 'F')");
+}
+
class DualSourceBlendingExtensionTestWithParams : public ResolverTestWithParam<int> {
public:
DualSourceBlendingExtensionTestWithParams() { Enable(wgsl::Extension::kDualSourceBlending); }
diff --git a/src/tint/lang/wgsl/resolver/validator.cc b/src/tint/lang/wgsl/resolver/validator.cc
index aaa1259..75abdac 100644
--- a/src/tint/lang/wgsl/resolver/validator.cc
+++ b/src/tint/lang/wgsl/resolver/validator.cc
@@ -1287,7 +1287,8 @@
TINT_ICE() << "@blend_src has no value";
}
- return BlendSrcAttribute(blend_src_attr, stage);
+ bool is_input = param_or_ret == ParamOrRetType::kParameter;
+ return BlendSrcAttribute(blend_src_attr, stage, is_input);
},
[&](const ast::ColorAttribute* col_attr) {
color_attribute = col_attr;
@@ -2499,8 +2500,8 @@
bool is_stage_non_fragment =
stage != ast::PipelineStage::kNone && stage != ast::PipelineStage::kFragment;
- bool is_output = is_input.value_or(false);
- if (is_stage_non_fragment || is_output) {
+ bool is_input_param = is_input.value_or(false);
+ if (is_stage_non_fragment || is_input_param) {
AddError(attr->source) << style::Attribute("@", attr->Name())
<< " can only be used for fragment shader output";
return false;