Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 146 additions & 1 deletion src/webgpu/api/validation/encoding/cmds/render/draw.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ and parameters as expect.
`;

import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { kVertexFormatInfo } from '../../../../../capability_info.js';
import {
kPrimitiveTopology,
kIndexFormat,
kVertexFormatInfo,
} from '../../../../../capability_info.js';
import { GPUTest, AllFeaturesMaxLimitsGPUTest } from '../../../../../gpu_test.js';
import * as vtu from '../../../validation_test_utils.js';

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

g.test(`index_buffer_format`)
.desc(
`
Check that pipelines with a strip topology require their stripIndexFormat to match the setIndexBuffer calls' indexFormat.
- Issues an indexed draw call after a setPipeline and setIndexBuffer call.
- For all valid (stripIndexFormat, topology) combinations.
- For all setIndexBuffer indexFormats.
- For all render encoders.
- For both orderings of setIndexBuffer and setPipeline.
`
)
.paramsSubcasesOnly(u =>
u
.combine('topology', kPrimitiveTopology)
.combine('stripIndexFormat', [undefined, ...kIndexFormat] as const)
.filter(
p =>
p.topology === 'line-strip' ||
p.topology === 'triangle-strip' ||
p.stripIndexFormat === undefined
)
.combine('indexFormat', kIndexFormat)
.combine('drawType', ['drawIndexed', 'drawIndexedIndirect'] as const)
)
.fn(t => {
const { indexFormat, topology, stripIndexFormat, drawType } = t.params;

const pipeline = t.device.createRenderPipeline({
layout: 'auto',
vertex: {
module: t.device.createShaderModule({ code: vtu.getNoOpShaderCode('VERTEX') }),
},
fragment: {
module: t.device.createShaderModule({ code: vtu.getNoOpShaderCode('FRAGMENT') }),
targets: [{ format: 'rgba8unorm', writeMask: 0 }],
},
primitive: {
topology,
stripIndexFormat,
},
});
const indexBuffer = vtu.createBufferWithState(t, 'valid', {
size: 16,
usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,
});

// Make the encoders that test the validation.
const isStrip = topology === 'line-strip' || topology === 'triangle-strip';
const success = !isStrip || stripIndexFormat === indexFormat;

for (const encoderType of ['render bundle', 'render pass'] as const) {
for (const setPipelineBeforeBuffer of [false, true]) {
const commandBufferMaker = t.createEncoder(encoderType);
const renderEncoder = commandBufferMaker.encoder;

if (setPipelineBeforeBuffer) {
renderEncoder.setPipeline(pipeline);
}
renderEncoder.setIndexBuffer(indexBuffer, indexFormat);
if (!setPipelineBeforeBuffer) {
renderEncoder.setPipeline(pipeline);
}

callDrawIndexed(t, renderEncoder, drawType, { indexCount: 3 });
commandBufferMaker.validateFinishAndSubmit(success, true);
}
}
});

g.test(`index_buffer_format_dirtying`)
.desc(
`
Check that the validation for indexFormat matching stripIndexFormat is dirtied if either the pipeline or the index buffer is changed.
`
)
.paramsSubcasesOnly(p =>
p
.combine('dirty', ['pipeline', 'indexBuffer', 'neither'])
.combine('drawType', ['drawIndexed', 'drawIndexedIndirect'] as const)
)
.fn(t => {
const { dirty, drawType } = t.params;

// Create render pipelines with both stripIndexFormats.
const makeStripIndexPipeline = (
topology: GPUPrimitiveTopology,
stripIndexFormat: GPUIndexFormat
) => {
return t.device.createRenderPipeline({
layout: 'auto',
vertex: {
module: t.device.createShaderModule({ code: vtu.getNoOpShaderCode('VERTEX') }),
},
fragment: {
module: t.device.createShaderModule({ code: vtu.getNoOpShaderCode('FRAGMENT') }),
targets: [{ format: 'rgba8unorm', writeMask: 0 }],
},
primitive: {
topology,
stripIndexFormat,
},
});
};

const pipelineUint32 = makeStripIndexPipeline('triangle-strip', 'uint32');
const pipelineUint16 = makeStripIndexPipeline('triangle-strip', 'uint16');

const indexBuffer = vtu.createBufferWithState(t, 'valid', {
size: 16,
usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,
});

// Make the encoders that test the validation.
const success = dirty === 'neither';

for (const encoderType of ['render bundle', 'render pass'] as const) {
const commandBufferMaker = t.createEncoder(encoderType);
const renderEncoder = commandBufferMaker.encoder;

// First draw that's valid (checked with 'dirty': 'neither').
renderEncoder.setPipeline(pipelineUint32);
renderEncoder.setIndexBuffer(indexBuffer, 'uint32');
callDrawIndexed(t, renderEncoder, drawType, { indexCount: 3 });

// Dirty the pipeline or the buffer such that the validation should fail.
switch (dirty) {
case 'pipeline':
renderEncoder.setPipeline(pipelineUint16);
break;
case 'indexBuffer':
renderEncoder.setIndexBuffer(indexBuffer, 'uint16');
break;
case 'neither':
break;
}

callDrawIndexed(t, renderEncoder, drawType, { indexCount: 3 });
commandBufferMaker.validateFinishAndSubmit(success, true);
}
});

g.test(`index_buffer_OOB`)
.desc(
`
Expand Down
7 changes: 7 additions & 0 deletions src/webgpu/listing_meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@
"webgpu:api,operation,vertex_state,index_format:primitive_restart:*": { "subcaseMS": 12.080 },
"webgpu:api,validation,buffer,create:createBuffer_invalid_and_oom:*": { "subcaseMS": 1.500 },
"webgpu:api,validation,buffer,create:limit:*": { "subcaseMS": 31.433 },
"webgpu:api,validation,buffer,create:new_usages:*": { "subcaseMS": 1.159 },
"webgpu:api,validation,buffer,create:size:*": { "subcaseMS": 5.570 },
"webgpu:api,validation,buffer,create:usage:*": { "subcaseMS": 3.971 },
"webgpu:api,validation,buffer,destroy:all_usages:*": { "subcaseMS": 3.250 },
Expand Down Expand Up @@ -485,6 +486,7 @@
"webgpu:api,validation,createTexture:mipLevelCount,bound_check,bigger_than_integer_bit_width:*": { "subcaseMS": 2.301 },
"webgpu:api,validation,createTexture:mipLevelCount,bound_check:*": { "subcaseMS": 0.801 },
"webgpu:api,validation,createTexture:mipLevelCount,format:*": { "subcaseMS": 1.258 },
"webgpu:api,validation,createTexture:new_usages:*": { "subcaseMS": 1.268 },
"webgpu:api,validation,createTexture:sampleCount,valid_sampleCount_with_other_parameter_varies:*": { "subcaseMS": 0.525 },
"webgpu:api,validation,createTexture:sampleCount,various_sampleCount_with_all_formats:*": { "subcaseMS": 2.336 },
"webgpu:api,validation,createTexture:sample_count,1d_2d_array_3d:*": { "subcaseMS": 2.480 },
Expand All @@ -496,6 +498,7 @@
"webgpu:api,validation,createTexture:texture_size,default_value_and_smallest_size,compressed_format:*": { "subcaseMS": 1.863 },
"webgpu:api,validation,createTexture:texture_size,default_value_and_smallest_size,uncompressed_format:*": { "subcaseMS": 1.694 },
"webgpu:api,validation,createTexture:texture_usage:*": { "subcaseMS": 0.870 },
"webgpu:api,validation,createTexture:usage:*": { "subcaseMS": 7.583 },
"webgpu:api,validation,createTexture:viewFormats:*": { "subcaseMS": 0.632 },
"webgpu:api,validation,createTexture:zero_size_and_usage:*": { "subcaseMS": 3.250 },
"webgpu:api,validation,createView:array_layers:*": { "subcaseMS": 0.491 },
Expand All @@ -506,6 +509,7 @@
"webgpu:api,validation,createView:mip_levels:*": { "subcaseMS": 0.436 },
"webgpu:api,validation,createView:texture_state:*": { "subcaseMS": 0.400 },
"webgpu:api,validation,createView:texture_view_usage:*": { "subcaseMS": 3106.634 },
"webgpu:api,validation,createView:texture_view_usage_of_multiple_usages:*": { "subcaseMS": 5.349 },
"webgpu:api,validation,createView:texture_view_usage_with_view_format:*": { "subcaseMS": 2406.440 },
"webgpu:api,validation,debugMarker:push_pop_call_count_unbalance,command_encoder:*": { "subcaseMS": 1.522 },
"webgpu:api,validation,debugMarker:push_pop_call_count_unbalance,render_compute_pass:*": { "subcaseMS": 0.601 },
Expand Down Expand Up @@ -560,6 +564,8 @@
"webgpu:api,validation,encoding,cmds,index_access:out_of_bounds_zero_sized_index_buffer:*": { "subcaseMS": 12.400 },
"webgpu:api,validation,encoding,cmds,render,draw:buffer_binding_overlap:*": { "subcaseMS": 0.446 },
"webgpu:api,validation,encoding,cmds,render,draw:index_buffer_OOB:*": { "subcaseMS": 5.825 },
"webgpu:api,validation,encoding,cmds,render,draw:index_buffer_format:*": { "subcaseMS": 8.864 },
"webgpu:api,validation,encoding,cmds,render,draw:index_buffer_format_dirtying:*": { "subcaseMS": 0.389 },
"webgpu:api,validation,encoding,cmds,render,draw:last_buffer_setting_take_account:*": { "subcaseMS": 30.801 },
"webgpu:api,validation,encoding,cmds,render,draw:max_draw_count:*": { "subcaseMS": 3.521 },
"webgpu:api,validation,encoding,cmds,render,draw:unused_buffer_bound:*": { "subcaseMS": 1.413 },
Expand Down Expand Up @@ -703,6 +709,7 @@
"webgpu:api,validation,image_copy,texture_related:valid:*": { "subcaseMS": 3.678 },
"webgpu:api,validation,layout_shader_compat:pipeline_layout_shader_exact_match:*": { "subcaseMS": 2.000 },
"webgpu:api,validation,non_filterable_texture:non_filterable_texture_with_filtering_sampler:*": { "subcaseMS": 170.470 },
"webgpu:api,validation,pipeline,immediates:pipeline_creation_immediate_size_mismatch:*": { "subcaseMS": 108.993 },
"webgpu:api,validation,query_set,create:count:*": { "subcaseMS": 0.967 },
"webgpu:api,validation,query_set,destroy:invalid_queryset:*": { "subcaseMS": 0.801 },
"webgpu:api,validation,query_set,destroy:twice:*": { "subcaseMS": 0.700 },
Expand Down
Loading