From e80efbc6497cf80065d53216618f22ba6e769b78 Mon Sep 17 00:00:00 2001 From: Jiawei Shao Date: Fri, 5 Jul 2024 10:31:03 +0800 Subject: [PATCH] Add shader validation tests on the usage of @blend_src (#3839) * Add shader validation tests on the usage of `@blend_src` This patch adds shader validation tests on the usage of `@blend_src`. According to the latest WGSL SPEC, - `@blend_src` can only be used on a struct member with `@location` attribute - If `@blend_src` is declared on a member of a struct, the struct must exactly have two members with `@location` attribute: one has `@location(0) @blend_src(0)` and another has `@location(0) @blend_src(1)`. * Add more tests on different variable declarations * Address reviewer's comments --- .../extension/dual_source_blending.spec.ts | 243 ++++++++++++++++++ 1 file changed, 243 insertions(+) diff --git a/src/webgpu/shader/validation/extension/dual_source_blending.spec.ts b/src/webgpu/shader/validation/extension/dual_source_blending.spec.ts index 7c0b6b8ce856..a8122067462f 100644 --- a/src/webgpu/shader/validation/extension/dual_source_blending.spec.ts +++ b/src/webgpu/shader/validation/extension/dual_source_blending.spec.ts @@ -317,3 +317,246 @@ ${kStageIOValidationTests[t.params.attr].shader} `; t.expectCompileResult(kStageIOValidationTests[t.params.attr].pass, code); }); + +const kUsageValidationTests = { + const: { + code: `@blend_src(0) const color = 1.2;`, + pass: false, + use_default_main_function: true, + }, + override: { + code: `@blend_src(0) @id(0) override color : f32;`, + pass: false, + use_default_main_function: true, + }, + let: { + code: ` + @fragment fn main() -> vec4f { + let @blend_src(0) color = vec4f(); + return color; + } + `, + pass: false, + use_default_main_function: false, + }, + var_private: { + code: `@blend_src(0) var color : vec4f;`, + pass: false, + use_default_main_function: true, + }, + var_function: { + code: ` + @fragment fn main() -> vec4f { + var @blend_src(0) color : vec4f; + color = vec4f(); + return color; + } + `, + pass: false, + use_default_main_function: false, + }, + function_declaration: { + code: ` + @blend_src(0) fn fun() {} + `, + pass: false, + use_default_main_function: true, + }, + non_entrypoint_function_input_non_struct: { + code: ` + fn fun(@blend_src(0) color : vec4f) -> vec4f { + return color; + } + `, + pass: false, + use_default_main_function: true, + }, + non_entrypoint_function_output_non_struct: { + code: ` + fn fun() -> @blend_src(0) vec4f { + return vec4f(); + } + `, + pass: false, + use_default_main_function: true, + }, + entrypoint_input_non_struct: { + code: ` + @fragment fn main(@location(0) @blend_src(0) color : vec4f) -> @location(0) vec4f { + return color; + } + `, + pass: false, + use_default_main_function: false, + }, + entrypoint_output_non_struct: { + code: ` + @fragment fn main() -> @location(0) @blend_src(0) vec4f { + return vec4f(); + } + `, + pass: false, + use_default_main_function: false, + }, + struct_member_only_blend_src_0: { + code: ` + struct BlendSrcStruct { + @location(0) @blend_src(0) color : vec4f, + } + `, + pass: false, + use_default_main_function: true, + }, + struct_member_only_blend_src_1: { + code: ` + struct BlendSrcStruct { + @location(0) @blend_src(1) blend : vec4f, + } + `, + pass: false, + use_default_main_function: true, + }, + struct_member_no_location_blend_src_0: { + code: ` + struct BlendSrcStruct { + @blend_src(0) color : vec4f, + @location(0) @blend_src(1) blend : vec4f, + } + `, + pass: false, + use_default_main_function: true, + }, + struct_member_no_location_blend_src_1: { + code: ` + struct BlendSrcStruct { + @location(0) @blend_src(0) color : vec4f, + @blend_src(1) blend : vec4f, + } + `, + pass: false, + use_default_main_function: true, + }, + struct_member_duplicate_blend_src_0: { + code: ` + struct BlendSrcStruct { + @location(0) @blend_src(0) color : vec4f, + @location(0) @blend_src(0) blend : vec4f, + } + `, + pass: false, + use_default_main_function: true, + }, + struct_member_duplicate_blend_src_1: { + code: ` + struct BlendSrcStruct { + @location(0) @blend_src(1) color : vec4f, + @location(0) @blend_src(1) blend : vec4f, + } + `, + pass: false, + use_default_main_function: true, + }, + struct_member_has_non_zero_location_blend_src_0: { + code: ` + struct BlendSrcStruct { + @location(0) @blend_src(0) color1 : vec4f, + @location(1) @blend_src(0) color2 : vec4f, + @location(0) @blend_src(1) blend : vec4f, + } + `, + pass: false, + use_default_main_function: true, + }, + struct_member_has_non_zero_location_blend_src_1: { + code: ` + struct BlendSrcStruct { + @location(0) @blend_src(0) color : vec4f, + @location(0) @blend_src(1) blend1 : vec4f, + @location(1) @blend_src(1) blend2 : vec4f, + } + `, + pass: false, + use_default_main_function: true, + }, + struct_member_non_zero_location_blend_src_0_blend_src_1: { + code: ` + struct BlendSrcStruct { + @location(1) @blend_src(0) color : vec4f, + @location(1) @blend_src(1) blend : vec4f, + } + `, + pass: false, + use_default_main_function: true, + }, + struct_member_has_non_zero_location_no_blend_src: { + code: ` + struct BlendSrcStruct { + @location(0) @blend_src(0) color : vec4f, + @location(0) @blend_src(1) blend : vec4f, + @location(1) color2 : vec4f, + } + `, + pass: false, + use_default_main_function: true, + }, + struct_member_no_location_no_blend_src: { + code: ` + struct BlendSrcStruct { + @location(0) @blend_src(0) color : vec4f, + @location(0) @blend_src(1) blend : vec4f, + depth : f32, + } + `, + pass: true, + use_default_main_function: true, + }, + struct_member_blend_src_and_builtin: { + code: ` + struct BlendSrcStruct { + @location(0) @blend_src(0) color : vec4f, + @location(0) @blend_src(1) blend : vec4f, + @builtin(frag_depth) depth : f32, + } + `, + pass: true, + use_default_main_function: true, + }, + struct_member_location_0_blend_src_0_blend_src_1: { + code: ` + struct BlendSrcStruct { + @location(0) @blend_src(0) color : vec4f, + @location(0) @blend_src(1) blend : vec4f, + } + `, + pass: true, + use_default_main_function: true, + }, +}; + +g.test('blend_src_usage') + .desc( + `Test that blend_src can only be used on a member of a structure, and must be used together with + the location attribute. In addition, if blend_src is used on a member of a structure, there must + be exactly 2 members that have location attribute in the structure: one is @location(0) + @blend_src(0) and another is @location(0) @blend_src(1).` + ) + .params(u => u.combine('attr', keysOf(kUsageValidationTests))) + .beforeAllSubcases(t => + t.selectDeviceOrSkipTestCase({ requiredFeatures: ['dual-source-blending'] }) + ) + .fn(t => { + const code = ` +enable dual_source_blending; + +${kUsageValidationTests[t.params.attr].code} + +${ + kUsageValidationTests[t.params.attr].use_default_main_function + ? `@fragment fn main() -> @location(0) vec4f { + return vec4f(); +}` + : '' +} +`; + t.expectCompileResult(kUsageValidationTests[t.params.attr].pass, code); + });