blob: 3b06a2259afc33e6f7b97b81156b65c92b657f34 [file] [log] [blame] [edit]
export const description = `
Compute dispatch validation tests.
`;
import { AllFeaturesMaxLimitsGPUTest } from '../.././gpu_test.js';
import { makeTestGroup } from '../../../common/framework/test_group.js';
export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);
g.test('dispatch,linear_indexing_range')
.desc('Tests validation of total invocations for linear_indexing built-in values')
.params(u =>
u
.combine('builtin', ['global_invocation_index', 'workgroup_index'] as const)
.beginSubcases()
.combine('size', ['max', 'valid'] as const)
)
.fn(t => {
// Other builtins are not tested due to onerous runtimes.
t.skipIf(!t.hasLanguageFeature('linear_indexing'), 'Missing linear_indexing language feature');
// Spec limits:
// - maxComputeWorkgroupsPerDimension = 65535
const { maxComputeWorkgroupsPerDimension } = t.device.limits;
const x = t.params.builtin === 'global_invocation_index' ? 2 : 1,
y = 1,
z = 1;
const wgSize = x * y * z;
const countX = maxComputeWorkgroupsPerDimension;
const countY = t.params.size === 'max' ? maxComputeWorkgroupsPerDimension : 1;
const countZ = t.params.builtin === 'workgroup_index' ? 2 : 1;
const totalInvocations = wgSize * countX * countY * countZ;
t.skipIf(t.params.size === 'max' && totalInvocations <= 0xffffffff, 'Uninteresting test');
const code = `
@compute @workgroup_size(${x}, ${y}, ${z})
fn main(@builtin(${t.params.builtin}) input : u32) {
_ = input;
}`;
const shaderModule = t.device.createShaderModule({ code });
const computePipeline = t.device.createComputePipeline({
layout: 'auto',
compute: {
module: shaderModule,
},
});
const commandEncoder = t.device.createCommandEncoder();
const computePassEncoder = commandEncoder.beginComputePass();
computePassEncoder.setPipeline(computePipeline);
computePassEncoder.dispatchWorkgroups(countX, countY, countZ);
computePassEncoder.end();
t.expectValidationError(() => {
commandEncoder.finish();
}, t.params.size === 'max');
});
g.test('dispatchIndirect,linear_indexing_range')
.desc('Tests dispatchIndirect skips when linear_indexing is out of range')
.params(u =>
u
.combine('builtin', ['global_invocation_index', 'workgroup_index'] as const)
.beginSubcases()
.combine('size', ['max', 'valid'] as const)
)
.fn(t => {
// Other builtins are not tested due to onerous runtimes.
t.skipIf(!t.hasLanguageFeature('linear_indexing'), 'Missing linear_indexing language feature');
// Spec limits:
// - maxComputeWorkgroupsPerDimension = 65535
const { maxComputeWorkgroupsPerDimension } = t.device.limits;
const x = t.params.builtin === 'global_invocation_index' ? 2 : 1,
y = 1,
z = 1;
const wgSize = x * y * z;
const countX = maxComputeWorkgroupsPerDimension;
const countY = t.params.size === 'max' ? maxComputeWorkgroupsPerDimension : 1;
const countZ = t.params.builtin === 'workgroup_index' ? 2 : 1;
const totalInvocations = wgSize * countX * countY * countZ;
t.skipIf(t.params.size === 'max' && totalInvocations <= 0xffffffff, 'Uninteresting test');
const kMagic = 0xdeadbeef;
const code = `
@group(0) @binding(0)
var<storage, read_write> out : u32;
@compute @workgroup_size(${x}, ${y}, ${z})
fn main(@builtin(${t.params.builtin}) input : u32,
@builtin(global_invocation_id) gid : vec3u) {
_ = input;
if (gid.x == 0 && gid.y == 0 && gid.z == 0) {
out = ${kMagic};
}
}`;
const dispatchIndirectCounts = new Uint32Array(3);
dispatchIndirectCounts[0] = countX;
dispatchIndirectCounts[1] = countY;
dispatchIndirectCounts[2] = countZ;
const indirectBuffer = t.makeBufferWithContents(
dispatchIndirectCounts,
GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST | GPUBufferUsage.INDIRECT
);
t.trackForCleanup(indirectBuffer);
const outputBuffer = t.makeBufferWithContents(
new Uint32Array([0]),
GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST | GPUBufferUsage.STORAGE
);
t.trackForCleanup(outputBuffer);
const shaderModule = t.device.createShaderModule({ code });
const computePipeline = t.device.createComputePipeline({
layout: 'auto',
compute: {
module: shaderModule,
},
});
const bg = t.device.createBindGroup({
layout: computePipeline.getBindGroupLayout(0),
entries: [
{
binding: 0,
resource: {
buffer: outputBuffer,
},
},
],
});
const commandEncoder = t.device.createCommandEncoder();
const computePassEncoder = commandEncoder.beginComputePass();
computePassEncoder.setPipeline(computePipeline);
computePassEncoder.setBindGroup(0, bg);
computePassEncoder.dispatchWorkgroupsIndirect(indirectBuffer, 0);
computePassEncoder.end();
t.queue.submit([commandEncoder.finish()]);
const expected = t.params.size === 'max' ? 0 : kMagic;
t.expectGPUBufferValuesEqual(outputBuffer, new Uint32Array([expected]));
});