diff --git a/src/webgpu/api/validation/encoding/programmable/pipeline_bind_group_compat.spec.ts b/src/webgpu/api/validation/encoding/programmable/pipeline_bind_group_compat.spec.ts index 46402e19031..c19cf90b96d 100644 --- a/src/webgpu/api/validation/encoding/programmable/pipeline_bind_group_compat.spec.ts +++ b/src/webgpu/api/validation/encoding/programmable/pipeline_bind_group_compat.spec.ts @@ -830,25 +830,37 @@ g.test('bgl_resource_type_mismatch') ); }); -g.test('empty_bind_group_layouts_requires_empty_bind_groups,compute_pass') +g.test('empty_bind_group_layouts_never_requires_empty_bind_groups,compute_pass') .desc( ` - Test that a compute pipeline with empty bind groups layouts requires empty bind groups to be set. + Test that a compute pipeline with empty bind group layouts doesn't require empty bind groups to be + set as empty bind group layout items should always be ignored. ` ) .params(u => u + .combine('emptyBindGroupLayoutType', ['Null', 'Undefined', 'Empty'] as const) .combine('bindGroupLayoutEntryCount', [3, 4]) .combine('computeCommand', ['dispatchIndirect', 'dispatch'] as const) ) .fn(t => { - const { bindGroupLayoutEntryCount, computeCommand } = t.params; + const { emptyBindGroupLayoutType, bindGroupLayoutEntryCount, computeCommand } = t.params; const emptyBGLCount = 4; const emptyBGL = t.device.createBindGroupLayout({ entries: [] }); const emptyBGLs = []; for (let i = 0; i < emptyBGLCount; i++) { - emptyBGLs.push(emptyBGL); + switch (emptyBindGroupLayoutType) { + case 'Null': + emptyBGLs.push(null); + break; + case 'Undefined': + emptyBGLs.push(undefined); + break; + case 'Empty': + emptyBGLs.push(emptyBGL); + break; + } } const pipelineLayout = t.device.createPipelineLayout({ @@ -880,21 +892,23 @@ g.test('empty_bind_group_layouts_requires_empty_bind_groups,compute_pass') t.doCompute(computePass, computeCommand, true); computePass.end(); - const success = bindGroupLayoutEntryCount === emptyBGLCount; + const success = true; t.expectValidationError(() => { encoder.finish(); }, !success); }); -g.test('empty_bind_group_layouts_requires_empty_bind_groups,render_pass') +g.test('empty_bind_group_layouts_never_requires_empty_bind_groups,render_pass') .desc( ` - Test that a render pipeline with empty bind groups layouts requires empty bind groups to be set. + Test that a render pipeline with empty bind groups layouts doesn't require empty bind groups to be + set as empty bind group layout items should always be ignored. ` ) .params(u => u + .combine('emptyBindGroupLayoutType', ['Null', 'Undefined', 'Empty'] as const) .combine('bindGroupLayoutEntryCount', [3, 4]) .combine('renderCommand', [ 'draw', @@ -904,13 +918,23 @@ g.test('empty_bind_group_layouts_requires_empty_bind_groups,render_pass') ] as const) ) .fn(t => { - const { bindGroupLayoutEntryCount, renderCommand } = t.params; + const { emptyBindGroupLayoutType, bindGroupLayoutEntryCount, renderCommand } = t.params; const emptyBGLCount = 4; const emptyBGL = t.device.createBindGroupLayout({ entries: [] }); const emptyBGLs = []; for (let i = 0; i < emptyBGLCount; i++) { - emptyBGLs.push(emptyBGL); + switch (emptyBindGroupLayoutType) { + case 'Null': + emptyBGLs.push(null); + break; + case 'Undefined': + emptyBGLs.push(undefined); + break; + case 'Empty': + emptyBGLs.push(emptyBGL); + break; + } } const pipelineLayout = t.device.createPipelineLayout({ @@ -966,7 +990,7 @@ g.test('empty_bind_group_layouts_requires_empty_bind_groups,render_pass') t.doRender(renderPass, renderCommand, true); renderPass.end(); - const success = bindGroupLayoutEntryCount === emptyBGLCount; + const success = true; t.expectValidationError(() => { encoder.finish(); @@ -997,11 +1021,17 @@ const kPipelineTypesAndBindingTypeParams = [ g.test('default_bind_group_layouts_never_match,compute_pass') .desc( ` - Test that bind groups created with default bind group layouts never match other layouts, including empty bind groups. - - * Test that a pipeline with an explicit layout can not be used with a bindGroup from an auto layout - * Test that a pipeline with an auto layout can not be used with a bindGroup from an explicit layout - * Test that an auto layout from one pipeline can not be used with an auto layout from a different pipeline. + Test that bind groups created with default bind group layouts never match other layouts, except + when the default bind group layouts are empty because the empty bind group layouts should all be + treated as null bind group layouts and be ignored when checking setBindGroup() against the current + pipeline. + + * Test that a pipeline with an explicit layout can not be used with a bindGroup from an auto + layout except the explicit layout is empty. + * Test that a pipeline with an auto layout can not be used with a bindGroup from an explicit + layout except the layout got from the pipeline is empty. + * Test that an auto layout from one pipeline can not be used with an auto layout from a different + pipeline except the layouts got from the pipeline are empty. * Test matching bindgroup layouts on the same default layout pipeline are compatible. In other words if you only define group(2) then group(0)'s empty layout and group(1)'s empty layout should be compatible. Similarly if group(2) and group(3) have the same types of resources they should be compatible. @@ -1014,7 +1044,16 @@ g.test('default_bind_group_layouts_never_match,compute_pass') .combine('computeCommand', ['dispatchIndirect', 'dispatch'] as const) ) .fn(t => { - const { pipelineType, bindingType, swap, _success: success, computeCommand, empty } = t.params; + const { + pipelineType, + bindingType, + swap, + _success: successWhenNonEmpty, + computeCommand, + empty, + } = t.params; + + const success = empty || successWhenNonEmpty; t.runDefaultLayoutBindingTest({ visibility: GPUShaderStage.COMPUTE, @@ -1056,11 +1095,17 @@ g.test('default_bind_group_layouts_never_match,compute_pass') g.test('default_bind_group_layouts_never_match,render_pass') .desc( ` - Test that bind groups created with default bind group layouts never match other layouts, including empty bind groups. - - * Test that a pipeline with an explicit layout can not be used with a bindGroup from an auto layout - * Test that a pipeline with an auto layout can not be used with a bindGroup from an explicit layout - * Test that an auto layout from one pipeline can not be used with an auto layout from a different pipeline. + Test that bind groups created with default bind group layouts never match other layouts, except + when the default bind group layouts are empty because the empty bind group layouts should all be + treated as null bind group layouts and be ignored when checking setBindGroup() against the current + pipeline. + + * Test that a pipeline with an explicit layout can not be used with a bindGroup from an auto + layout except the explicit layout is empty. + * Test that a pipeline with an auto layout can not be used with a bindGroup from an explicit + layout except the layout got from the pipeline is empty. + * Test that an auto layout from one pipeline can not be used with an auto layout from a different + pipeline except the layouts got from the pipeline are empty. * Test matching bindgroup layouts on the same default layout pipeline are compatible. In other words if you only define group(2) then group(0)'s empty layout and group(1)'s empty layout should be compatible. Similarly if group(2) and group(3) have the same types of resources they should be compatible. @@ -1078,7 +1123,16 @@ g.test('default_bind_group_layouts_never_match,render_pass') ] as const) ) .fn(t => { - const { pipelineType, bindingType, swap, _success: success, renderCommand, empty } = t.params; + const { + pipelineType, + bindingType, + swap, + _success: successWhenNonEmpty, + renderCommand, + empty, + } = t.params; + + const success = empty || successWhenNonEmpty; t.runDefaultLayoutBindingTest({ visibility: GPUShaderStage.VERTEX, diff --git a/src/webgpu/listing_meta.json b/src/webgpu/listing_meta.json index a44b8fc0790..e0390869579 100644 --- a/src/webgpu/listing_meta.json +++ b/src/webgpu/listing_meta.json @@ -548,8 +548,8 @@ "webgpu:api,validation,encoding,programmable,pipeline_bind_group_compat:buffer_binding,render_pipeline:*": { "subcaseMS": 1.734 }, "webgpu:api,validation,encoding,programmable,pipeline_bind_group_compat:default_bind_group_layouts_never_match,compute_pass:*": { "subcaseMS": 1.734 }, "webgpu:api,validation,encoding,programmable,pipeline_bind_group_compat:default_bind_group_layouts_never_match,render_pass:*": { "subcaseMS": 1.734 }, - "webgpu:api,validation,encoding,programmable,pipeline_bind_group_compat:empty_bind_group_layouts_requires_empty_bind_groups,compute_pass:*": { "subcaseMS": 2.325 }, - "webgpu:api,validation,encoding,programmable,pipeline_bind_group_compat:empty_bind_group_layouts_requires_empty_bind_groups,render_pass:*": { "subcaseMS": 10.838 }, + "webgpu:api,validation,encoding,programmable,pipeline_bind_group_compat:empty_bind_group_layouts_never_requires_empty_bind_groups,compute_pass:*": { "subcaseMS": 2.325 }, + "webgpu:api,validation,encoding,programmable,pipeline_bind_group_compat:empty_bind_group_layouts_never_requires_empty_bind_groups,render_pass:*": { "subcaseMS": 10.838 }, "webgpu:api,validation,encoding,programmable,pipeline_bind_group_compat:sampler_binding,render_pipeline:*": { "subcaseMS": 10.523 }, "webgpu:api,validation,encoding,queries,begin_end:nesting:*": { "subcaseMS": 1.101 }, "webgpu:api,validation,encoding,queries,begin_end:occlusion_query,begin_end_balance:*": { "subcaseMS": 0.820 },