Skip to content

Commit 97b4991

Browse files
authored
Add tests for validation that stripIndexFormat and indexFormat must match (#4644)
1 parent 3b327eb commit 97b4991

2 files changed

Lines changed: 153 additions & 1 deletion

File tree

src/webgpu/api/validation/encoding/cmds/render/draw.spec.ts

Lines changed: 146 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ and parameters as expect.
55
`;
66

77
import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
8-
import { kVertexFormatInfo } from '../../../../../capability_info.js';
8+
import {
9+
kPrimitiveTopology,
10+
kIndexFormat,
11+
kVertexFormatInfo,
12+
} from '../../../../../capability_info.js';
913
import { GPUTest, AllFeaturesMaxLimitsGPUTest } from '../../../../../gpu_test.js';
1014
import * as vtu from '../../../validation_test_utils.js';
1115

@@ -287,6 +291,147 @@ In this test we test that a small buffer bound to unused buffer slot won't cause
287291
}
288292
});
289293

294+
g.test(`index_buffer_format`)
295+
.desc(
296+
`
297+
Check that pipelines with a strip topology require their stripIndexFormat to match the setIndexBuffer calls' indexFormat.
298+
- Issues an indexed draw call after a setPipeline and setIndexBuffer call.
299+
- For all valid (stripIndexFormat, topology) combinations.
300+
- For all setIndexBuffer indexFormats.
301+
- For all render encoders.
302+
- For both orderings of setIndexBuffer and setPipeline.
303+
`
304+
)
305+
.paramsSubcasesOnly(u =>
306+
u
307+
.combine('topology', kPrimitiveTopology)
308+
.combine('stripIndexFormat', [undefined, ...kIndexFormat] as const)
309+
.filter(
310+
p =>
311+
p.topology === 'line-strip' ||
312+
p.topology === 'triangle-strip' ||
313+
p.stripIndexFormat === undefined
314+
)
315+
.combine('indexFormat', kIndexFormat)
316+
.combine('drawType', ['drawIndexed', 'drawIndexedIndirect'] as const)
317+
)
318+
.fn(t => {
319+
const { indexFormat, topology, stripIndexFormat, drawType } = t.params;
320+
321+
const pipeline = t.device.createRenderPipeline({
322+
layout: 'auto',
323+
vertex: {
324+
module: t.device.createShaderModule({ code: vtu.getNoOpShaderCode('VERTEX') }),
325+
},
326+
fragment: {
327+
module: t.device.createShaderModule({ code: vtu.getNoOpShaderCode('FRAGMENT') }),
328+
targets: [{ format: 'rgba8unorm', writeMask: 0 }],
329+
},
330+
primitive: {
331+
topology,
332+
stripIndexFormat,
333+
},
334+
});
335+
const indexBuffer = vtu.createBufferWithState(t, 'valid', {
336+
size: 16,
337+
usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,
338+
});
339+
340+
// Make the encoders that test the validation.
341+
const isStrip = topology === 'line-strip' || topology === 'triangle-strip';
342+
const success = !isStrip || stripIndexFormat === indexFormat;
343+
344+
for (const encoderType of ['render bundle', 'render pass'] as const) {
345+
for (const setPipelineBeforeBuffer of [false, true]) {
346+
const commandBufferMaker = t.createEncoder(encoderType);
347+
const renderEncoder = commandBufferMaker.encoder;
348+
349+
if (setPipelineBeforeBuffer) {
350+
renderEncoder.setPipeline(pipeline);
351+
}
352+
renderEncoder.setIndexBuffer(indexBuffer, indexFormat);
353+
if (!setPipelineBeforeBuffer) {
354+
renderEncoder.setPipeline(pipeline);
355+
}
356+
357+
callDrawIndexed(t, renderEncoder, drawType, { indexCount: 3 });
358+
commandBufferMaker.validateFinishAndSubmit(success, true);
359+
}
360+
}
361+
});
362+
363+
g.test(`index_buffer_format_dirtying`)
364+
.desc(
365+
`
366+
Check that the validation for indexFormat matching stripIndexFormat is dirtied if either the pipeline or the index buffer is changed.
367+
`
368+
)
369+
.paramsSubcasesOnly(p =>
370+
p
371+
.combine('dirty', ['pipeline', 'indexBuffer', 'neither'])
372+
.combine('drawType', ['drawIndexed', 'drawIndexedIndirect'] as const)
373+
)
374+
.fn(t => {
375+
const { dirty, drawType } = t.params;
376+
377+
// Create render pipelines with both stripIndexFormats.
378+
const makeStripIndexPipeline = (
379+
topology: GPUPrimitiveTopology,
380+
stripIndexFormat: GPUIndexFormat
381+
) => {
382+
return t.device.createRenderPipeline({
383+
layout: 'auto',
384+
vertex: {
385+
module: t.device.createShaderModule({ code: vtu.getNoOpShaderCode('VERTEX') }),
386+
},
387+
fragment: {
388+
module: t.device.createShaderModule({ code: vtu.getNoOpShaderCode('FRAGMENT') }),
389+
targets: [{ format: 'rgba8unorm', writeMask: 0 }],
390+
},
391+
primitive: {
392+
topology,
393+
stripIndexFormat,
394+
},
395+
});
396+
};
397+
398+
const pipelineUint32 = makeStripIndexPipeline('triangle-strip', 'uint32');
399+
const pipelineUint16 = makeStripIndexPipeline('triangle-strip', 'uint16');
400+
401+
const indexBuffer = vtu.createBufferWithState(t, 'valid', {
402+
size: 16,
403+
usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,
404+
});
405+
406+
// Make the encoders that test the validation.
407+
const success = dirty === 'neither';
408+
409+
for (const encoderType of ['render bundle', 'render pass'] as const) {
410+
const commandBufferMaker = t.createEncoder(encoderType);
411+
const renderEncoder = commandBufferMaker.encoder;
412+
413+
// First draw that's valid (checked with 'dirty': 'neither').
414+
renderEncoder.setPipeline(pipelineUint32);
415+
renderEncoder.setIndexBuffer(indexBuffer, 'uint32');
416+
callDrawIndexed(t, renderEncoder, drawType, { indexCount: 3 });
417+
418+
// Dirty the pipeline or the buffer such that the validation should fail.
419+
switch (dirty) {
420+
case 'pipeline':
421+
renderEncoder.setPipeline(pipelineUint16);
422+
break;
423+
case 'indexBuffer':
424+
renderEncoder.setIndexBuffer(indexBuffer, 'uint16');
425+
break;
426+
case 'neither':
427+
break;
428+
}
429+
430+
callDrawIndexed(t, renderEncoder, drawType, { indexCount: 3 });
431+
commandBufferMaker.validateFinishAndSubmit(success, true);
432+
}
433+
});
434+
290435
g.test(`index_buffer_OOB`)
291436
.desc(
292437
`

src/webgpu/listing_meta.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@
250250
"webgpu:api,operation,vertex_state,index_format:primitive_restart:*": { "subcaseMS": 12.080 },
251251
"webgpu:api,validation,buffer,create:createBuffer_invalid_and_oom:*": { "subcaseMS": 1.500 },
252252
"webgpu:api,validation,buffer,create:limit:*": { "subcaseMS": 31.433 },
253+
"webgpu:api,validation,buffer,create:new_usages:*": { "subcaseMS": 1.159 },
253254
"webgpu:api,validation,buffer,create:size:*": { "subcaseMS": 5.570 },
254255
"webgpu:api,validation,buffer,create:usage:*": { "subcaseMS": 3.971 },
255256
"webgpu:api,validation,buffer,destroy:all_usages:*": { "subcaseMS": 3.250 },
@@ -485,6 +486,7 @@
485486
"webgpu:api,validation,createTexture:mipLevelCount,bound_check,bigger_than_integer_bit_width:*": { "subcaseMS": 2.301 },
486487
"webgpu:api,validation,createTexture:mipLevelCount,bound_check:*": { "subcaseMS": 0.801 },
487488
"webgpu:api,validation,createTexture:mipLevelCount,format:*": { "subcaseMS": 1.258 },
489+
"webgpu:api,validation,createTexture:new_usages:*": { "subcaseMS": 1.268 },
488490
"webgpu:api,validation,createTexture:sampleCount,valid_sampleCount_with_other_parameter_varies:*": { "subcaseMS": 0.525 },
489491
"webgpu:api,validation,createTexture:sampleCount,various_sampleCount_with_all_formats:*": { "subcaseMS": 2.336 },
490492
"webgpu:api,validation,createTexture:sample_count,1d_2d_array_3d:*": { "subcaseMS": 2.480 },
@@ -496,6 +498,7 @@
496498
"webgpu:api,validation,createTexture:texture_size,default_value_and_smallest_size,compressed_format:*": { "subcaseMS": 1.863 },
497499
"webgpu:api,validation,createTexture:texture_size,default_value_and_smallest_size,uncompressed_format:*": { "subcaseMS": 1.694 },
498500
"webgpu:api,validation,createTexture:texture_usage:*": { "subcaseMS": 0.870 },
501+
"webgpu:api,validation,createTexture:usage:*": { "subcaseMS": 7.583 },
499502
"webgpu:api,validation,createTexture:viewFormats:*": { "subcaseMS": 0.632 },
500503
"webgpu:api,validation,createTexture:zero_size_and_usage:*": { "subcaseMS": 3.250 },
501504
"webgpu:api,validation,createView:array_layers:*": { "subcaseMS": 0.491 },
@@ -506,6 +509,7 @@
506509
"webgpu:api,validation,createView:mip_levels:*": { "subcaseMS": 0.436 },
507510
"webgpu:api,validation,createView:texture_state:*": { "subcaseMS": 0.400 },
508511
"webgpu:api,validation,createView:texture_view_usage:*": { "subcaseMS": 3106.634 },
512+
"webgpu:api,validation,createView:texture_view_usage_of_multiple_usages:*": { "subcaseMS": 5.349 },
509513
"webgpu:api,validation,createView:texture_view_usage_with_view_format:*": { "subcaseMS": 2406.440 },
510514
"webgpu:api,validation,debugMarker:push_pop_call_count_unbalance,command_encoder:*": { "subcaseMS": 1.522 },
511515
"webgpu:api,validation,debugMarker:push_pop_call_count_unbalance,render_compute_pass:*": { "subcaseMS": 0.601 },
@@ -560,6 +564,8 @@
560564
"webgpu:api,validation,encoding,cmds,index_access:out_of_bounds_zero_sized_index_buffer:*": { "subcaseMS": 12.400 },
561565
"webgpu:api,validation,encoding,cmds,render,draw:buffer_binding_overlap:*": { "subcaseMS": 0.446 },
562566
"webgpu:api,validation,encoding,cmds,render,draw:index_buffer_OOB:*": { "subcaseMS": 5.825 },
567+
"webgpu:api,validation,encoding,cmds,render,draw:index_buffer_format:*": { "subcaseMS": 8.864 },
568+
"webgpu:api,validation,encoding,cmds,render,draw:index_buffer_format_dirtying:*": { "subcaseMS": 0.389 },
563569
"webgpu:api,validation,encoding,cmds,render,draw:last_buffer_setting_take_account:*": { "subcaseMS": 30.801 },
564570
"webgpu:api,validation,encoding,cmds,render,draw:max_draw_count:*": { "subcaseMS": 3.521 },
565571
"webgpu:api,validation,encoding,cmds,render,draw:unused_buffer_bound:*": { "subcaseMS": 1.413 },
@@ -703,6 +709,7 @@
703709
"webgpu:api,validation,image_copy,texture_related:valid:*": { "subcaseMS": 3.678 },
704710
"webgpu:api,validation,layout_shader_compat:pipeline_layout_shader_exact_match:*": { "subcaseMS": 2.000 },
705711
"webgpu:api,validation,non_filterable_texture:non_filterable_texture_with_filtering_sampler:*": { "subcaseMS": 170.470 },
712+
"webgpu:api,validation,pipeline,immediates:pipeline_creation_immediate_size_mismatch:*": { "subcaseMS": 108.993 },
706713
"webgpu:api,validation,query_set,create:count:*": { "subcaseMS": 0.967 },
707714
"webgpu:api,validation,query_set,destroy:invalid_queryset:*": { "subcaseMS": 0.801 },
708715
"webgpu:api,validation,query_set,destroy:twice:*": { "subcaseMS": 0.700 },

0 commit comments

Comments
 (0)