Skip to content

Commit

Permalink
Start adding queue validation tests for buffers and textures
Browse files Browse the repository at this point in the history
  • Loading branch information
greggman committed Mar 7, 2023
1 parent a1efadf commit ec5ad7d
Show file tree
Hide file tree
Showing 2 changed files with 305 additions and 0 deletions.
147 changes: 147 additions & 0 deletions src/webgpu/api/validation/queue/destroyed/buffer.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
export const description = `
Tests using a destroyed buffer on a queue.
TODO:
- test renderPass/renderBundle (setVertexBuffer, setIndexBuffer)
- test renderPass (resolveQuerySet)
- test renderPass/computePass (setBindGroup)
`;

import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { ValidationTest } from '../../validation_test.js';

export const g = makeTestGroup(ValidationTest);

g.test('writeBuffer')
.desc(
`
Tests that using a destroyed buffer in writeBuffer fails.
- x= {destroyed, not destroyed (control case)}
`
)
.paramsSubcasesOnly(u => u.combine('destroyed', [false, true] as const))
.fn(t => {
const { destroyed } = t.params;
const buffer = t.trackForCleanup(
t.device.createBuffer({
size: 4,
usage: GPUBufferUsage.COPY_DST,
})
);

if (destroyed) {
buffer.destroy();
}

t.expectValidationError(() => t.queue.writeBuffer(buffer, 0, new Uint8Array(4)), destroyed);
});

g.test('copyBufferToBuffer')
.desc(
`
Tests that using a destroyed buffer in copyBufferToBuffer fails.
- x= {not destroyed (control case), src destroyed, dst destroyed}
`
)
.paramsSubcasesOnly(u => u.combine('destroyed', ['none', 'src', 'dst', 'both'] as const))
.fn(t => {
const src = t.trackForCleanup(
t.device.createBuffer({ size: 4, usage: GPUBufferUsage.COPY_SRC })
);
const dst = t.trackForCleanup(
t.device.createBuffer({ size: 4, usage: GPUBufferUsage.COPY_DST })
);

const encoder = t.device.createCommandEncoder();
encoder.copyBufferToBuffer(src, 0, dst, 0, dst.size);
const commandBuffer = encoder.finish();

let shouldError = true;
switch (t.params.destroyed) {
case 'none':
shouldError = false;
break;
case 'src':
src.destroy();
break;
case 'dst':
dst.destroy();
break;
case 'both':
src.destroy();
dst.destroy();
break;
}

t.expectValidationError(() => {
t.queue.submit([commandBuffer]);
}, shouldError);
});

g.test('copyBufferToTexture')
.desc(
`
Tests that using a destroyed buffer in copyBufferToTexture fails.
- x= {not destroyed (control case), src destroyed}
`
)
.paramsSubcasesOnly(u => u.combine('destroyed', [false, true] as const))
.fn(t => {
const { destroyed } = t.params;
const buffer = t.trackForCleanup(
t.device.createBuffer({ size: 4, usage: GPUBufferUsage.COPY_SRC })
);
const texture = t.trackForCleanup(
t.device.createTexture({
size: [1, 1, 1],
format: 'rgba8unorm',
usage: GPUTextureUsage.COPY_DST,
})
);

const encoder = t.device.createCommandEncoder();
encoder.copyBufferToTexture({ buffer }, { texture }, [1, 1, 1]);
const commandBuffer = encoder.finish();

if (destroyed) {
buffer.destroy();
}

t.expectValidationError(() => {
t.queue.submit([commandBuffer]);
}, destroyed);
});

g.test('copyTextureToBuffer')
.desc(
`
Tests that using a destroyed buffer in copyTextureToBuffer fails.
- x= {not destroyed (control case), dst destroyed}
`
)
.paramsSubcasesOnly(u => u.combine('destroyed', [false, true] as const))
.fn(t => {
const { destroyed } = t.params;
const texture = t.trackForCleanup(
t.device.createTexture({
size: [1, 1, 1],
format: 'rgba8unorm',
usage: GPUTextureUsage.COPY_SRC,
})
);
const buffer = t.trackForCleanup(
t.device.createBuffer({ size: 4, usage: GPUBufferUsage.COPY_DST })
);

const encoder = t.device.createCommandEncoder();
encoder.copyTextureToBuffer({ texture }, { buffer }, [1, 1, 1]);
const commandBuffer = encoder.finish();

if (destroyed) {
buffer.destroy();
}

t.expectValidationError(() => {
t.queue.submit([commandBuffer]);
}, destroyed);
});
158 changes: 158 additions & 0 deletions src/webgpu/api/validation/queue/destroyed/texture.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
export const description = `
Tests using a destroyed texture on a queue.
TODO:
- test renderPass/computePass (setBindGroup)
- test beginRenderPass target
`;

import { makeTestGroup } from '../../../../../common/framework/test_group.js';
import { ValidationTest } from '../../validation_test.js';

export const g = makeTestGroup(ValidationTest);

g.test('writeTexture')
.desc(
`
Tests that using a destroyed texture in writeTexture fails.
- x= {destroyed, not destroyed (control case)}
`
)
.paramsSubcasesOnly(u => u.combine('destroyed', [false, true] as const))
.fn(t => {
const { destroyed } = t.params;
const texture = t.trackForCleanup(
t.device.createTexture({
size: [1, 1, 1],
format: 'rgba8unorm',
usage: GPUTextureUsage.COPY_DST,
})
);

if (destroyed) {
texture.destroy();
}

t.expectValidationError(
() => t.queue.writeTexture({ texture }, new Uint8Array(4), { bytesPerRow: 4 }, [1, 1, 1]),
destroyed
);
});

g.test('copyTextureToTexture')
.desc(
`
Tests that using a destroyed texture in copyTextureToTexture fails.
- x= {not destroyed (control case), src destroyed, dst destroyed}
`
)
.paramsSubcasesOnly(u => u.combine('destroyed', ['none', 'src', 'dst', 'both'] as const))
.fn(t => {
const src = t.trackForCleanup(
t.device.createTexture({
size: [1, 1, 1],
format: 'rgba8unorm',
usage: GPUTextureUsage.COPY_SRC,
})
);
const dst = t.trackForCleanup(
t.device.createTexture({
size: [1, 1, 1],
format: 'rgba8unorm',
usage: GPUTextureUsage.COPY_DST,
})
);

const encoder = t.device.createCommandEncoder();
encoder.copyTextureToTexture({ texture: src }, { texture: dst }, [1, 1, 1]);
const commandBuffer = encoder.finish();

let shouldError = true;
switch (t.params.destroyed) {
case 'none':
shouldError = false;
break;
case 'src':
src.destroy();
break;
case 'dst':
dst.destroy();
break;
case 'both':
src.destroy();
dst.destroy();
break;
}

t.expectValidationError(() => {
t.queue.submit([commandBuffer]);
}, shouldError);
});

g.test('copyBufferToTexture')
.desc(
`
Tests that using a destroyed texture in copyBufferToTexture fails.
- x= {not destroyed (control case), dst destroyed}
`
)
.paramsSubcasesOnly(u => u.combine('destroyed', [false, true] as const))
.fn(t => {
const { destroyed } = t.params;
const buffer = t.trackForCleanup(
t.device.createBuffer({ size: 4, usage: GPUBufferUsage.COPY_SRC })
);
const texture = t.trackForCleanup(
t.device.createTexture({
size: [1, 1, 1],
format: 'rgba8unorm',
usage: GPUTextureUsage.COPY_DST,
})
);

const encoder = t.device.createCommandEncoder();
encoder.copyBufferToTexture({ buffer }, { texture }, [1, 1, 1]);
const commandBuffer = encoder.finish();

if (destroyed) {
texture.destroy();
}

t.expectValidationError(() => {
t.queue.submit([commandBuffer]);
}, destroyed);
});

g.test('copyTextureToBuffer')
.desc(
`
Tests that using a destroyed texture in copyTextureToBuffer fails.
- x= {not destroyed (control case), src destroyed}
`
)
.paramsSubcasesOnly(u => u.combine('destroyed', [false, true] as const))
.fn(t => {
const { destroyed } = t.params;
const texture = t.trackForCleanup(
t.device.createTexture({
size: [1, 1, 1],
format: 'rgba8unorm',
usage: GPUTextureUsage.COPY_SRC,
})
);
const buffer = t.trackForCleanup(
t.device.createBuffer({ size: 4, usage: GPUBufferUsage.COPY_DST })
);

const encoder = t.device.createCommandEncoder();
encoder.copyTextureToBuffer({ texture }, { buffer }, [1, 1, 1]);
const commandBuffer = encoder.finish();

if (destroyed) {
texture.destroy();
}

t.expectValidationError(() => {
t.queue.submit([commandBuffer]);
}, destroyed);
});

0 comments on commit ec5ad7d

Please sign in to comment.