From 72f23e93e83e79f3b3f73a80b5ad9be7c8e39bb6 Mon Sep 17 00:00:00 2001 From: Gregg Tavares Date: Mon, 30 Dec 2024 15:12:30 -0800 Subject: [PATCH] Compat: refactor setBindGroup for 0 storage buffers in frag stage. Most of these tests didn't seem to require storage buffers to test what they were testing so I switched them to uniform buffers. One of them used both storage and uniform buffers so I added more subcases so that it tests with both storage buffers and uniform buffers in compute stage only (this is for devices that don't support storage buffers in fragment stage). Then both compute+fragment stages like it was, but this case is skipped if there are no storage buffers in fragment shaders. I also added a case were it uses 2 uniform buffers. It's not clear what it's testing needs to buffers to be of different types. --- .../encoding/cmds/setBindGroup.spec.ts | 42 ++++++++++++------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/src/webgpu/api/validation/encoding/cmds/setBindGroup.spec.ts b/src/webgpu/api/validation/encoding/cmds/setBindGroup.spec.ts index 2bbcc2b8bb21..e392b718825e 100644 --- a/src/webgpu/api/validation/encoding/cmds/setBindGroup.spec.ts +++ b/src/webgpu/api/validation/encoding/cmds/setBindGroup.spec.ts @@ -16,7 +16,8 @@ import { kBufferBindingTypes, kMinDynamicBufferOffsetAlignment, } from '../../../../capability_info.js'; -import { kResourceStates, ResourceState } from '../../../../gpu_test.js'; +import { GPUConst } from '../../../../constants.js'; +import { kResourceStates, MaxLimitsTestMixin, ResourceState } from '../../../../gpu_test.js'; import { kProgrammableEncoderTypes, ProgrammableEncoderType, @@ -53,7 +54,7 @@ class F extends ValidationTest { return { buffer: this.createBufferWithState(state, { size: 4, - usage: GPUBufferUsage.STORAGE, + usage: GPUBufferUsage.UNIFORM, }), }; default: @@ -80,7 +81,7 @@ class F extends ValidationTest { entries: indices.map(binding => ({ binding, visibility: this.encoderTypeToStageFlag(encoderType), - ...(resourceType === 'buffer' ? { buffer: { type: 'storage' } } : { texture: {} }), + ...(resourceType === 'buffer' ? { buffer: { type: 'uniform' } } : { texture: {} }), })), }); const bindGroup = this.device.createBindGroup({ @@ -101,7 +102,7 @@ class F extends ValidationTest { } } -export const g = makeTestGroup(F); +export const g = makeTestGroup(MaxLimitsTestMixin(F)); g.test('state_and_binding_index') .desc('Tests that setBindGroup correctly handles {valid, invalid, destroyed} bindGroups.') @@ -153,7 +154,7 @@ g.test('bind_group,device_mismatch') const buffer = t.trackForCleanup( sourceDevice.createBuffer({ size: 4, - usage: GPUBufferUsage.STORAGE, + usage: GPUBufferUsage.UNIFORM, }) ); @@ -162,7 +163,7 @@ g.test('bind_group,device_mismatch') { binding: 0, visibility: t.encoderTypeToStageFlag(encoderType), - buffer: { type: 'storage', hasDynamicOffset: useU32Array }, + buffer: { type: 'uniform', hasDynamicOffset: useU32Array }, }, ], }); @@ -224,15 +225,28 @@ g.test('dynamic_offsets_match_expectations_in_pass_encoder') { dynamicOffsets: [0, 0xffffffff], _success: false }, ]) .combine('useU32array', [false, true]) + .beginSubcases() + .combine('visibility', [ + GPUConst.ShaderStage.COMPUTE, + GPUConst.ShaderStage.COMPUTE | GPUConst.ShaderStage.FRAGMENT, + ] as const) + .combine('useStorage', [false, true] as const) ) .fn(t => { + const { visibility, useStorage } = t.params; + t.skipIf( + t.isCompatibility && + (visibility & GPUShaderStage.FRAGMENT) !== 0 && + !(t.device.limits.maxStorageBuffersInFragmentStage! >= 1), + `maxStorageBuffersInFragmentStage${t.device.limits.maxStorageBuffersInFragmentStage} < 1` + ); const kBindingSize = 12; const bindGroupLayout = t.device.createBindGroupLayout({ entries: [ { binding: 0, - visibility: GPUShaderStage.COMPUTE | GPUShaderStage.FRAGMENT, + visibility, buffer: { type: 'uniform', hasDynamicOffset: true, @@ -240,9 +254,9 @@ g.test('dynamic_offsets_match_expectations_in_pass_encoder') }, { binding: 1, - visibility: GPUShaderStage.COMPUTE | GPUShaderStage.FRAGMENT, + visibility, buffer: { - type: 'storage', + type: useStorage ? 'storage' : 'uniform', hasDynamicOffset: true, }, }, @@ -254,9 +268,9 @@ g.test('dynamic_offsets_match_expectations_in_pass_encoder') usage: GPUBufferUsage.UNIFORM, }); - const storageBuffer = t.createBufferTracked({ + const storageOrUniformBuffer = t.createBufferTracked({ size: 2 * kMinDynamicBufferOffsetAlignment + 8, - usage: GPUBufferUsage.STORAGE, + usage: useStorage ? GPUBufferUsage.STORAGE : GPUBufferUsage.UNIFORM, }); const bindGroup = t.device.createBindGroup({ @@ -272,7 +286,7 @@ g.test('dynamic_offsets_match_expectations_in_pass_encoder') { binding: 1, resource: { - buffer: storageBuffer, + buffer: storageOrUniformBuffer, size: kBindingSize, }, }, @@ -335,7 +349,7 @@ g.test('u32array_start_and_length') binding: i, visibility: GPUShaderStage.FRAGMENT, buffer: { - type: 'storage', + type: 'uniform', hasDynamicOffset: true, }, })), @@ -348,7 +362,7 @@ g.test('u32array_start_and_length') resource: { buffer: t.createBufferWithState('valid', { size: kBindingSize, - usage: GPUBufferUsage.STORAGE, + usage: GPUBufferUsage.UNIFORM, }), size: kBindingSize, },