diff options
Diffstat (limited to 'dom/webgpu/tests/cts/checkout/src/webgpu/util/command_buffer_maker.ts')
-rw-r--r-- | dom/webgpu/tests/cts/checkout/src/webgpu/util/command_buffer_maker.ts | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/util/command_buffer_maker.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/util/command_buffer_maker.ts new file mode 100644 index 0000000000..f52c8bb059 --- /dev/null +++ b/dom/webgpu/tests/cts/checkout/src/webgpu/util/command_buffer_maker.ts @@ -0,0 +1,85 @@ +import { ResourceState, GPUTest } from '../gpu_test.js'; + +export const kRenderEncodeTypes = ['render pass', 'render bundle'] as const; +export type RenderEncodeType = typeof kRenderEncodeTypes[number]; +export const kProgrammableEncoderTypes = ['compute pass', ...kRenderEncodeTypes] as const; +export type ProgrammableEncoderType = typeof kProgrammableEncoderTypes[number]; +export const kEncoderTypes = ['non-pass', ...kProgrammableEncoderTypes] as const; +export type EncoderType = typeof kEncoderTypes[number]; + +// Look up the type of the encoder based on `T`. If `T` is a union, this will be too! +type EncoderByEncoderType<T extends EncoderType> = { + 'non-pass': GPUCommandEncoder; + 'compute pass': GPUComputePassEncoder; + 'render pass': GPURenderPassEncoder; + 'render bundle': GPURenderBundleEncoder; +}[T]; + +/** See {@link webgpu/api/validation/validation_test.ValidationTest.createEncoder | + * GPUTest.createEncoder()}. */ +export class CommandBufferMaker<T extends EncoderType> { + /** `GPU___Encoder` for recording commands into. */ + // Look up the type of the encoder based on `T`. If `T` is a union, this will be too! + readonly encoder: EncoderByEncoderType<T>; + + /** + * Finish any passes, finish and record any bundles, and finish/return the command buffer. Any + * errors are ignored and the GPUCommandBuffer (which may be an error buffer) is returned. + */ + readonly finish: () => GPUCommandBuffer; + + /** + * Finish any passes, finish and record any bundles, and finish/return the command buffer. + * Checks for validation errors in (only) the appropriate finish call. + */ + readonly validateFinish: (shouldSucceed: boolean) => GPUCommandBuffer; + + /** + * Finish the command buffer and submit it. Checks for validation errors in either the submit or + * the appropriate finish call, depending on the state of a resource used in the encoding. + */ + readonly validateFinishAndSubmit: ( + shouldBeValid: boolean, + submitShouldSucceedIfValid: boolean + ) => void; + + /** + * `validateFinishAndSubmit()` based on the state of a resource in the command encoder. + * - `finish()` should fail if the resource is 'invalid'. + * - Only `submit()` should fail if the resource is 'destroyed'. + */ + readonly validateFinishAndSubmitGivenState: (resourceState: ResourceState) => void; + + constructor( + t: GPUTest, + encoder: EncoderByEncoderType<EncoderType>, + finish: () => GPUCommandBuffer + ) { + // TypeScript introduces an intersection type here where we don't want one. + this.encoder = encoder as EncoderByEncoderType<T>; + this.finish = finish; + + // Define extra methods like this, otherwise they get unbound when destructured, e.g.: + // const { encoder, validateFinishAndSubmit } = t.createEncoder(type); + // Alternatively, do not destructure, and call member functions, e.g.: + // const encoder = t.createEncoder(type); + // encoder.validateFinish(true); + this.validateFinish = (shouldSucceed: boolean) => { + return t.expectGPUError('validation', this.finish, !shouldSucceed); + }; + + this.validateFinishAndSubmit = ( + shouldBeValid: boolean, + submitShouldSucceedIfValid: boolean + ) => { + const commandBuffer = this.validateFinish(shouldBeValid); + if (shouldBeValid) { + t.expectValidationError(() => t.queue.submit([commandBuffer]), !submitShouldSucceedIfValid); + } + }; + + this.validateFinishAndSubmitGivenState = (resourceState: ResourceState) => { + this.validateFinishAndSubmit(resourceState !== 'invalid', resourceState !== 'destroyed'); + }; + } +} |