diff --git a/src/webgpu/listing_meta.json b/src/webgpu/listing_meta.json index 06bda67bda41..a672a5c8750b 100644 --- a/src/webgpu/listing_meta.json +++ b/src/webgpu/listing_meta.json @@ -2044,6 +2044,7 @@ "webgpu:shader,validation,shader_io,locations:stage_inout:*": { "subcaseMS": 1.850 }, "webgpu:shader,validation,shader_io,locations:type:*": { "subcaseMS": 1.332 }, "webgpu:shader,validation,shader_io,locations:validation:*": { "subcaseMS": 1.296 }, + "webgpu:shader,validation,shader_io,locations:out_of_order:*": { "subcaseMS": 1.296 }, "webgpu:shader,validation,shader_io,size:size:*": { "subcaseMS": 1.218 }, "webgpu:shader,validation,shader_io,size:size_fp16:*": { "subcaseMS": 1.500 }, "webgpu:shader,validation,shader_io,size:size_non_struct:*": { "subcaseMS": 0.929 }, diff --git a/src/webgpu/shader/validation/shader_io/locations.spec.ts b/src/webgpu/shader/validation/shader_io/locations.spec.ts index 8452679d7177..3c41f1a8b596 100644 --- a/src/webgpu/shader/validation/shader_io/locations.spec.ts +++ b/src/webgpu/shader/validation/shader_io/locations.spec.ts @@ -380,3 +380,152 @@ g.test('location_fp16') }`; t.expectCompileResult(t.params.ext === '', code); }); + +interface OutOfOrderCase { + params?: string; + returnType?: string; + decls?: string; + returnValue?: string; + valid: boolean; +} + +const kOutOfOrderCases: Record = { + reverse_params: { + params: `@location(2) p1 : f32, @location(1) p2 : f32, @location(0) p3 : f32`, + valid: true, + }, + no_zero_params: { + params: `@location(2) p1 : f32, @location(1) p2 : f32`, + valid: true, + }, + reverse_overlap: { + params: `@location(2) p1 : f32, @location(1) p2 : f32, @location(1) p3 : f32`, + valid: false, + }, + struct: { + params: `p1 : S`, + decls: `struct S { + @location(1) x : f32, + @location(0) y : f32, + }`, + valid: true, + }, + struct_override: { + params: `@location(0) p1 : S`, + decls: `struct S { + @location(1) x : f32, + @location(0) y : f32, + }`, + valid: false, + }, + struct_random: { + params: `p1 : S, p2 : T`, + decls: `struct S { + @location(16) x : f32, + @location(4) y : f32, + } + struct T { + @location(13) x : f32, + @location(7) y : f32, + }`, + valid: true, + }, + struct_random_overlap: { + params: `p1 : S, p2 : T`, + decls: `struct S { + @location(16) x : f32, + @location(4) y : f32, + } + struct T { + @location(13) x : f32, + @location(4) y : f32, + }`, + valid: false, + }, + mixed_locations1: { + params: `@location(12) p1 : f32, p2 : S`, + decls: `struct S { + @location(2) x : f32, + }`, + valid: true, + }, + mixed_locations2: { + params: `p1 : S, @location(2) p2 : f32`, + decls: `struct S { + @location(12) x : f32, + }`, + valid: true, + }, + mixed_overlap: { + params: `p1 : S, @location(12) p2 : f32`, + decls: `struct S { + @location(12) x : f32, + }`, + valid: false, + }, + with_param_builtin: { + params: `p : S`, + decls: `struct S { + @location(12) x : f32, + @builtin(position) pos : vec4f, + @location(0) y : f32, + }`, + valid: true, + }, + non_zero_return: { + returnType: `@location(1) vec4f`, + returnValue: `vec4f()`, + valid: true, + }, + reverse_return: { + returnType: `S`, + returnValue: `S()`, + decls: `struct S { + @location(2) x : f32, + @location(1) y : f32, + @location(0) z : f32, + }`, + valid: true, + }, + gap_return: { + returnType: `S`, + returnValue: `S()`, + decls: `struct S { + @location(13) x : f32, + @location(7) y : f32, + @location(2) z : f32, + }`, + valid: true, + }, + with_return_builtin: { + returnType: `S`, + returnValue: `S()`, + decls: `struct S { + @location(11) x : f32, + @builtin(frag_depth) d : f32, + @location(10) y : f32, + }`, + valid: true, + }, +}; + +g.test('out_of_order') + .desc(`Test validation of out of order locations`) + .params(u => u.combine('case', keysOf(kOutOfOrderCases))) + .fn(t => { + const testcase = kOutOfOrderCases[t.params.case]; + const decls = testcase.decls !== undefined ? testcase.decls : ``; + const params = testcase.params !== undefined ? testcase.params : ``; + const returnType = testcase.returnType !== undefined ? `-> ${testcase.returnType}` : ``; + const returnValue = testcase.returnValue !== undefined ? `return ${testcase.returnValue};` : ``; + const code = ` +${decls} + +@fragment +fn main(${params}) ${returnType} { + ${returnValue} +} +`; + + t.expectCompileResult(testcase.valid, code); + });