blob: bc041b5ffefa90e62e5e9eea3bee6251d1d5eccd [file] [log] [blame]
export const description = `
Tests submit validation.
Note: destroyed buffer/texture/querySet are tested in destroyed/. (unless it gets moved here)
Note: buffer map state is tested in ./buffer_mapped.spec.ts.
`;
import { makeTestGroup } from '../../../../common/framework/test_group.js';
import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
interface CommandBufferOptions {
device?: GPUDevice;
valid?: boolean;
}
class F extends AllFeaturesMaxLimitsGPUTest {
createCommandBuffer(options: CommandBufferOptions = {}): GPUCommandBuffer {
const device = options.device ?? this.device;
let cb!: GPUCommandBuffer;
this.expectValidationError(() => {
const encoder = device.createCommandEncoder();
if (options.valid === false) {
// Popping a debug group when none are pushed results in an invalid command buffer.
encoder.popDebugGroup();
}
cb = encoder.finish();
}, options.valid === false);
return cb;
}
}
export const g = makeTestGroup(F);
g.test('command_buffer,device_mismatch')
.desc(
`
Tests submit cannot be called with command buffers created from another device
Test with two command buffers to make sure all command buffers can be validated:
- cb0 and cb1 from same device
- cb0 and cb1 from different device
`
)
.paramsSubcasesOnly([
{ cb0Mismatched: false, cb1Mismatched: false }, // control case
{ cb0Mismatched: true, cb1Mismatched: false },
{ cb0Mismatched: false, cb1Mismatched: true },
])
.beforeAllSubcases(t => t.usesMismatchedDevice())
.fn(t => {
const { cb0Mismatched, cb1Mismatched } = t.params;
const mismatched = cb0Mismatched || cb1Mismatched;
const cb0 = t.createCommandBuffer({ device: cb0Mismatched ? t.mismatchedDevice : t.device });
const cb1 = t.createCommandBuffer({ device: cb1Mismatched ? t.mismatchedDevice : t.device });
t.expectValidationError(() => {
t.device.queue.submit([cb0, cb1]);
}, mismatched);
});
g.test('command_buffer,duplicate_buffers')
.desc(
`
Tests submit cannot be called with the same command buffer listed multiple times:
`
)
.fn(t => {
const cb = t.createCommandBuffer();
t.expectValidationError(() => {
t.device.queue.submit([cb, cb]);
}, true);
});
g.test('command_buffer,submit_invalidates')
.desc(
`
Tests that calling submit invalidates the command buffers passed to it:
`
)
.fn(t => {
const cb = t.createCommandBuffer();
// Initial submit of a valid command buffer should pass.
t.device.queue.submit([cb]);
// Subsequent submits of the same command buffer should fail.
t.expectValidationError(() => {
t.device.queue.submit([cb]);
});
});
g.test('command_buffer,invalid_submit_invalidates')
.desc(
`
Tests that calling submit invalidates all command buffers passed to it, even
if they're part of an invalid submit.
`
)
.fn(t => {
const cb1 = t.createCommandBuffer();
const cb1_invalid = t.createCommandBuffer({ valid: false });
// Submit should fail because on of the command buffers is invalid
t.expectValidationError(() => {
t.device.queue.submit([cb1, cb1_invalid]);
});
// Subsequent submits of the previously valid command buffer should fail.
t.expectValidationError(() => {
t.device.queue.submit([cb1]);
});
// The order of the invalid and valid command buffers in the submit array should not matter.
const cb2 = t.createCommandBuffer();
const cb2_invalid = t.createCommandBuffer({ valid: false });
t.expectValidationError(() => {
t.device.queue.submit([cb2_invalid, cb2]);
});
t.expectValidationError(() => {
t.device.queue.submit([cb2]);
});
});