Skip to content

Commit

Permalink
Moving createEncoder to ValidationTest (#293)
Browse files Browse the repository at this point in the history
* Moving createEncoder to ValidationTest

* Switching from intersection types to a common interfaces
  • Loading branch information
egalli authored Sep 25, 2020
1 parent fe0cbfa commit a0dda78
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 86 deletions.
98 changes: 12 additions & 86 deletions src/webgpu/api/validation/encoding/cmds/debug.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,87 +13,10 @@ Test Coverage:

import { poptions, params } from '../../../../../common/framework/params_builder.js';
import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { assert } from '../../../../../common/framework/util/util.js';

import { ValidationTest } from './../../validation_test.js';
import { ValidationTest, kEncoderTypes } from './../../validation_test.js';

type Encoder = GPUCommandEncoder | GPUProgrammablePassEncoder;
const kEncoderTypes = ['non-pass', 'compute pass', 'render pass', 'render bundle'] as const;
type EncoderType = typeof kEncoderTypes[number];

class F extends ValidationTest {
private commandEncoder: GPUCommandEncoder | undefined = undefined;

makeAttachmentTexture(): GPUTexture {
return this.device.createTexture({
format: 'rgba8unorm',
size: { width: 16, height: 16, depth: 1 },
usage: GPUTextureUsage.OUTPUT_ATTACHMENT,
});
}

createEncoder(encoderType: EncoderType): Encoder {
assert(this.commandEncoder === undefined);
switch (encoderType) {
case 'non-pass':
return this.device.createCommandEncoder({});
case 'render bundle':
return this.device.createRenderBundleEncoder({ colorFormats: ['rgba8unorm'] });
case 'compute pass':
this.commandEncoder = this.device.createCommandEncoder({});
return this.commandEncoder.beginComputePass({});
case 'render pass':
this.commandEncoder = this.device.createCommandEncoder({});
return this.commandEncoder.beginRenderPass({
colorAttachments: [
{
attachment: this.makeAttachmentTexture().createView(),
loadValue: { r: 1.0, g: 0.0, b: 0.0, a: 1.0 },
},
],
});
}
}

finishEncoder(encoder: Encoder, encoderType: EncoderType) {
let commandBuffer: GPUCommandBuffer | undefined = undefined;
switch (encoderType) {
case 'non-pass': {
commandBuffer = (encoder as GPUCommandEncoder).finish({});
break;
}
case 'render bundle': {
const bundle = (encoder as GPURenderBundleEncoder).finish({});
const commandEncoder = this.device.createCommandEncoder({});
const pass = commandEncoder.beginRenderPass({
colorAttachments: [
{
attachment: this.makeAttachmentTexture().createView(),
loadValue: { r: 1.0, g: 0.0, b: 0.0, a: 1.0 },
},
],
});
pass.executeBundles([bundle]);
pass.endPass();
commandBuffer = commandEncoder.finish({});
break;
}
case 'compute pass':
case 'render pass': {
assert(this.commandEncoder !== undefined);
(encoder as GPUComputePassEncoder | GPURenderPassEncoder).endPass();
commandBuffer = this.commandEncoder?.finish();
this.commandEncoder = undefined;
break;
}
}
if (commandBuffer !== undefined) {
this.queue.submit([commandBuffer]);
}
}
}

export const g = makeTestGroup(F);
export const g = makeTestGroup(ValidationTest);

g.test('debug_group_balanced')
.params(
Expand All @@ -103,7 +26,7 @@ g.test('debug_group_balanced')
.combine(poptions('popCount', [0, 1, 2]))
)
.fn(t => {
const encoder = t.createEncoder(t.params.encoderType);
const { encoder, finish } = t.createEncoder(t.params.encoderType);
for (let i = 0; i < t.params.pushCount; ++i) {
encoder.pushDebugGroup(`${i}`);
}
Expand All @@ -112,7 +35,8 @@ g.test('debug_group_balanced')
}
const shouldError = t.params.popCount !== t.params.pushCount;
t.expectValidationError(() => {
t.finishEncoder(encoder, t.params.encoderType);
const commandBuffer = finish();
t.queue.submit([commandBuffer]);
}, shouldError);
});

Expand All @@ -123,10 +47,11 @@ g.test('debug_group')
.combine(poptions('label', ['', 'group']))
)
.fn(t => {
const encoder = t.createEncoder(t.params.encoderType);
const { encoder, finish } = t.createEncoder(t.params.encoderType);
encoder.pushDebugGroup(t.params.label);
encoder.popDebugGroup();
t.finishEncoder(encoder, t.params.encoderType);
const commandBuffer = finish();
t.queue.submit([commandBuffer]);
});

g.test('debug_marker')
Expand All @@ -136,7 +61,8 @@ g.test('debug_marker')
.combine(poptions('label', ['', 'marker']))
)
.fn(t => {
const encoder = t.createEncoder(t.params.encoderType);
encoder.insertDebugMarker(t.params.label);
t.finishEncoder(encoder, t.params.encoderType);
const maker = t.createEncoder(t.params.encoderType);
maker.encoder.insertDebugMarker(t.params.label);
const commandBuffer = maker.finish();
t.queue.submit([commandBuffer]);
});
87 changes: 87 additions & 0 deletions src/webgpu/api/validation/validation_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@ import { unreachable } from '../../../common/framework/util/util.js';
import { BindableResource } from '../../capability_info.js';
import { GPUTest } from '../../gpu_test.js';

type Encoder = GPUCommandEncoder | GPUProgrammablePassEncoder | GPURenderBundleEncoder;
export const kEncoderTypes = ['non-pass', 'compute pass', 'render pass', 'render bundle'] as const;
type EncoderType = typeof kEncoderTypes[number];

interface CommandBufferMaker<E extends Encoder> {
readonly encoder: E;
finish(): GPUCommandBuffer;
}

export class ValidationTest extends GPUTest {
createTextureWithState(
state: 'valid' | 'invalid' | 'destroyed',
Expand Down Expand Up @@ -181,6 +190,84 @@ export class ValidationTest extends GPUTest {
});
}

createEncoder(encoderType: 'non-pass'): CommandBufferMaker<GPUCommandEncoder>;
createEncoder(encoderType: 'render pass'): CommandBufferMaker<GPURenderPassEncoder>;
createEncoder(encoderType: 'compute pass'): CommandBufferMaker<GPUComputePassEncoder>;
createEncoder(encoderType: 'render bundle'): CommandBufferMaker<GPURenderBundleEncoder>;
createEncoder(
encoderType: 'render pass' | 'render bundle'
): CommandBufferMaker<GPURenderPassEncoder | GPURenderBundleEncoder>;
createEncoder(
encoderType: 'compute pass' | 'render pass' | 'render bundle'
): CommandBufferMaker<GPUProgrammablePassEncoder>;
createEncoder(encoderType: EncoderType): CommandBufferMaker<Encoder>;
createEncoder(encoderType: EncoderType): CommandBufferMaker<Encoder> {
const colorFormat = 'rgba8unorm';
switch (encoderType) {
case 'non-pass': {
const encoder = this.device.createCommandEncoder();
return {
encoder,

finish: () => {
return encoder.finish();
},
};
}
case 'render bundle': {
const device = this.device;
const encoder = device.createRenderBundleEncoder({
colorFormats: [colorFormat],
});
const pass = this.createEncoder('render pass');
return {
encoder,
finish: () => {
const bundle = encoder.finish();
pass.encoder.executeBundles([bundle]);
return pass.finish();
},
};
}
case 'compute pass': {
const commandEncoder = this.device.createCommandEncoder();
const encoder = commandEncoder.beginComputePass();
return {
encoder,
finish: () => {
encoder.endPass();
return commandEncoder.finish();
},
};
}
case 'render pass': {
const commandEncoder = this.device.createCommandEncoder();
const attachment = this.device
.createTexture({
format: colorFormat,
size: { width: 16, height: 16, depth: 1 },
usage: GPUTextureUsage.OUTPUT_ATTACHMENT,
})
.createView();
const encoder = commandEncoder.beginRenderPass({
colorAttachments: [
{
attachment,
loadValue: { r: 1.0, g: 0.0, b: 0.0, a: 1.0 },
},
],
});
return {
encoder,
finish: () => {
encoder.endPass();
return commandEncoder.finish();
},
};
}
}
}

expectValidationError(fn: Function, shouldError: boolean = true): void {
// If no error is expected, we let the scope surrounding the test catch it.
if (shouldError === false) {
Expand Down

0 comments on commit a0dda78

Please sign in to comment.