Skip to content

Commit 4c9c3f9

Browse files
committed
Additional encoder_state testcase
1 parent f5816ba commit 4c9c3f9

File tree

1 file changed

+80
-1
lines changed

1 file changed

+80
-1
lines changed

src/webgpu/api/validation/encoding/encoder_state.spec.ts

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ TODO:
1919
import { makeTestGroup } from '../../../../common/framework/test_group.js';
2020
import { objectEquals } from '../../../../common/util/util.js';
2121
import { AllFeaturesMaxLimitsGPUTest } from '../../../gpu_test.js';
22+
import * as vtu from '../validation_test_utils.js';
2223

2324
class F extends AllFeaturesMaxLimitsGPUTest {
2425
beginRenderPass(commandEncoder: GPUCommandEncoder, view: GPUTextureView): GPURenderPassEncoder {
@@ -154,7 +155,7 @@ g.test('call_after_successful_finish')
154155
g.test('pass_end_none')
155156
.desc(
156157
`
157-
Test that ending a {compute,render} pass without ending the passes generates a validation error.
158+
Test that finishing an encoder without ending a child {compute,render} pass generates a validation error.
158159
`
159160
)
160161
.paramsSubcasesOnly(u => u.combine('passType', ['compute', 'render']).combine('endCount', [0, 1]))
@@ -247,3 +248,81 @@ g.test('pass_end_twice,render_pass_invalid')
247248
encoder.finish();
248249
});
249250
});
251+
252+
g.test('pass_begin_invalid_encoder')
253+
.desc(
254+
`
255+
Test that {compute,render} passes can still be opened on an invalid encoder.
256+
`
257+
)
258+
.params(u =>
259+
u
260+
.combine('pass0Type', ['compute', 'render'])
261+
.combine('pass1Type', ['compute', 'render'])
262+
.beginSubcases()
263+
.combine('firstPassInvalid', [false, true])
264+
)
265+
.beforeAllSubcases(t => t.usesMismatchedDevice())
266+
.fn(t => {
267+
t.skipIfDeviceDoesNotSupportQueryType('timestamp');
268+
269+
const { pass0Type, pass1Type, firstPassInvalid } = t.params;
270+
271+
const view = t.createAttachmentTextureView();
272+
const mismatchedTexture = vtu.getDeviceMismatchedRenderTexture(t, 4)
273+
const mismatchedView = mismatchedTexture.createView();
274+
275+
const querySet = t.trackForCleanup(
276+
t.device.createQuerySet({
277+
type: 'timestamp',
278+
count: 1,
279+
})
280+
);
281+
282+
const timestampWrites = {
283+
querySet,
284+
beginningOfPassWriteIndex: 0,
285+
};
286+
287+
const descriptor = {
288+
timestampWrites,
289+
};
290+
291+
const mismatchedQuerySet = t.trackForCleanup(
292+
t.mismatchedDevice.createQuerySet({
293+
type: 'timestamp',
294+
count: 1,
295+
})
296+
);
297+
298+
const mismatchedTimestampWrites = {
299+
querySet: mismatchedQuerySet,
300+
beginningOfPassWriteIndex: 0,
301+
};
302+
303+
const mismatchedDescriptor = {
304+
timestampWrites: mismatchedTimestampWrites,
305+
};
306+
307+
const encoder = t.device.createCommandEncoder();
308+
309+
const firstPass =
310+
pass0Type === 'compute' ?
311+
(firstPassInvalid ? encoder.beginComputePass(mismatchedDescriptor)
312+
: encoder.beginComputePass(descriptor)) :
313+
(firstPassInvalid ? t.beginRenderPass(encoder, mismatchedView)
314+
: t.beginRenderPass(encoder, view));
315+
316+
// Ending an invalid pass invalidates the encoder
317+
firstPass.end();
318+
319+
// Passes can still be opened on an invalid encoder
320+
const secondPass =
321+
pass1Type === 'compute' ? encoder.beginComputePass() : t.beginRenderPass(encoder, view);
322+
323+
secondPass.end();
324+
325+
t.expectValidationError(() => {
326+
encoder.finish();
327+
}, firstPassInvalid);
328+
});

0 commit comments

Comments
 (0)