blob: 02f89b5628fdaa00c37cb2aec4dd2d75d3c0da7d [file] [log] [blame]
/**
* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
**/ export const description = `
createRenderPipeline validation tests.
TODO: review existing tests, write descriptions, and make sure tests are complete.
Make sure the following is covered. Consider splitting the file if too large/disjointed.
> - various attachment problems
>
> - interface matching between vertex and fragment shader
> - superset, subset, etc.
>
> - vertexStage {valid, invalid}
> - fragmentStage {valid, invalid}
> - primitiveTopology all possible values
> - rasterizationState various values
> - sampleCount {0, 1, 3, 4, 8, 16, 1024}
> - sampleMask {0, 0xFFFFFFFF}
> - alphaToCoverage:
> - alphaToCoverageEnabled is { true, false } and sampleCount { = 1, = 4 }.
> The only failing case is (true, 1).
> - output SV_Coverage semantics is statically used by fragmentStage and
> alphaToCoverageEnabled is { true (fails), false (passes) }.
> - sampleMask is being used and alphaToCoverageEnabled is { true (fails), false (passes) }.
`;
import { poptions } from '../../../common/framework/params_builder.js';
import { makeTestGroup } from '../../../common/framework/test_group.js';
import { kAllTextureFormats, kAllTextureFormatInfo } from '../../capability_info.js';
import { ValidationTest } from './validation_test.js';
class F extends ValidationTest {
getDescriptor(options = {}) {
const defaultColorStates = [{ format: 'rgba8unorm' }];
const {
primitiveTopology = 'triangle-list',
colorStates = defaultColorStates,
sampleCount = 1,
depthStencilState,
} = options;
const format = colorStates.length ? colorStates[0].format : 'rgba8unorm';
let fragColorType;
let suffix;
if (format.endsWith('sint')) {
fragColorType = 'i32';
suffix = '';
} else if (format.endsWith('uint')) {
fragColorType = 'u32';
suffix = 'u';
} else {
fragColorType = 'f32';
suffix = '.0';
}
return {
vertexStage: {
module: this.device.createShaderModule({
code: `
[[builtin(position)]] var<out> Position : vec4<f32>;
[[stage(vertex)]] fn main() -> void {
Position = vec4<f32>(0.0, 0.0, 0.0, 1.0);
}`,
}),
entryPoint: 'main',
},
fragmentStage: {
module: this.device.createShaderModule({
code: `
[[location(0)]] var<out> fragColor : vec4<${fragColorType}>;
[[stage(fragment)]] fn main() -> void {
fragColor = vec4<${fragColorType}>(0${suffix}, 1${suffix}, 0${suffix}, 1${suffix});
}`,
}),
entryPoint: 'main',
},
layout: this.getPipelineLayout(),
primitiveTopology,
colorStates,
sampleCount,
depthStencilState,
};
}
getPipelineLayout() {
return this.device.createPipelineLayout({ bindGroupLayouts: [] });
}
createTexture(params) {
const { format, sampleCount } = params;
return this.device.createTexture({
size: { width: 4, height: 4, depth: 1 },
usage: GPUTextureUsage.OUTPUT_ATTACHMENT,
format,
sampleCount,
});
}
}
export const g = makeTestGroup(F);
g.test('basic_use_of_createRenderPipeline').fn(t => {
const descriptor = t.getDescriptor();
t.device.createRenderPipeline(descriptor);
});
g.test('at_least_one_color_state_is_required').fn(async t => {
const goodDescriptor = t.getDescriptor({
colorStates: [{ format: 'rgba8unorm' }],
});
// Control case
t.device.createRenderPipeline(goodDescriptor);
// Fail because lack of color states
const badDescriptor = t.getDescriptor({
colorStates: [],
});
t.expectValidationError(() => {
t.device.createRenderPipeline(badDescriptor);
});
});
g.test('color_formats_must_be_renderable')
.params(poptions('format', kAllTextureFormats))
.fn(async t => {
const format = t.params.format;
const info = kAllTextureFormatInfo[format];
const descriptor = t.getDescriptor({ colorStates: [{ format }] });
if (info.renderable && info.color) {
// Succeeds when color format is renderable
t.device.createRenderPipeline(descriptor);
} else {
// Fails because when format is non-renderable
t.expectValidationError(() => {
t.device.createRenderPipeline(descriptor);
});
}
});
g.test('sample_count_must_be_valid')
.params([
{ sampleCount: 0, _success: false },
{ sampleCount: 1, _success: true },
{ sampleCount: 2, _success: false },
{ sampleCount: 3, _success: false },
{ sampleCount: 4, _success: true },
{ sampleCount: 8, _success: false },
{ sampleCount: 16, _success: false },
])
.fn(async t => {
const { sampleCount, _success } = t.params;
const descriptor = t.getDescriptor({ sampleCount });
if (_success) {
// Succeeds when sample count is valid
t.device.createRenderPipeline(descriptor);
} else {
// Fails when sample count is not 4 or 1
t.expectValidationError(() => {
t.device.createRenderPipeline(descriptor);
});
}
});
g.test('sample_count_must_be_equal_to_the_one_of_every_attachment_in_the_render_pass')
.params([
{ attachmentSamples: 4, pipelineSamples: 4, _success: true }, // It is allowed to use multisampled render pass and multisampled render pipeline.
{ attachmentSamples: 4, pipelineSamples: 1, _success: false }, // It is not allowed to use multisampled render pass and non-multisampled render pipeline.
{ attachmentSamples: 1, pipelineSamples: 4, _success: false }, // It is not allowed to use non-multisampled render pass and multisampled render pipeline.
])
.fn(async t => {
const { attachmentSamples, pipelineSamples, _success } = t.params;
const colorTexture = t.createTexture({
format: 'rgba8unorm',
sampleCount: attachmentSamples,
});
const depthStencilTexture = t.createTexture({
format: 'depth24plus-stencil8',
sampleCount: attachmentSamples,
});
const renderPassDescriptorWithoutDepthStencil = {
colorAttachments: [
{
attachment: colorTexture.createView(),
loadValue: { r: 1.0, g: 0.0, b: 0.0, a: 1.0 },
},
],
};
const renderPassDescriptorWithDepthStencilOnly = {
colorAttachments: [],
depthStencilAttachment: {
attachment: depthStencilTexture.createView(),
depthLoadValue: 1.0,
depthStoreOp: 'store',
stencilLoadValue: 0,
stencilStoreOp: 'store',
},
};
const pipelineWithoutDepthStencil = t.device.createRenderPipeline(
t.getDescriptor({
sampleCount: pipelineSamples,
})
);
const pipelineWithDepthStencilOnly = t.device.createRenderPipeline(
t.getDescriptor({
colorStates: [],
depthStencilState: { format: 'depth24plus-stencil8' },
sampleCount: pipelineSamples,
})
);
for (const { renderPassDescriptor, pipeline } of [
{
renderPassDescriptor: renderPassDescriptorWithoutDepthStencil,
pipeline: pipelineWithoutDepthStencil,
},
{
renderPassDescriptor: renderPassDescriptorWithDepthStencilOnly,
pipeline: pipelineWithDepthStencilOnly,
},
]) {
const commandEncoder = t.device.createCommandEncoder();
const renderPass = commandEncoder.beginRenderPass(renderPassDescriptor);
renderPass.setPipeline(pipeline);
renderPass.endPass();
t.expectValidationError(() => {
commandEncoder.finish();
}, !_success);
}
});