blob: 1614ff571bd0eb30662b3d082bdd5008c6b0a671 [file] [log] [blame]
export const description = `Test that variables in the shader are value initialized`;
import { makeTestGroup } from '../../../common/framework/test_group.js';
import { AllFeaturesMaxLimitsGPUTest, GPUTest } from '../../gpu_test.js';
import { Type } from '../../util/conversion.js';
export const g = makeTestGroup(AllFeaturesMaxLimitsGPUTest);
function generateShader(
isF16: boolean,
addressSpace: string,
typeDecl: string,
testValue: string,
comparison: string
): string {
let moduleScope = `
${isF16 ? 'enable f16;' : ''}
struct Output {
failed : atomic<u32>
}
@group(0) @binding(0) var<storage, read_write> output : Output;
`;
let functionScope = '';
switch (addressSpace) {
case 'private':
moduleScope += `\nvar<private> testVar: ${typeDecl} = ${testValue};`;
break;
case 'function':
functionScope += `\nvar testVar: ${typeDecl} = ${testValue};`;
break;
}
return `
${moduleScope}
@compute @workgroup_size(1, 1, 1)
fn main() {
${functionScope}
${comparison}
}
`;
}
async function run(t: GPUTest, wgsl: string) {
const pipeline = await t.device.createComputePipelineAsync({
layout: 'auto',
compute: {
module: t.device.createShaderModule({
code: wgsl,
}),
entryPoint: 'main',
},
});
const resultBuffer = t.createBufferTracked({
size: 4,
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,
});
const bindGroup = t.device.createBindGroup({
layout: pipeline.getBindGroupLayout(0),
entries: [
{
binding: 0,
resource: {
buffer: resultBuffer,
},
},
],
});
const encoder = t.device.createCommandEncoder();
const pass = encoder.beginComputePass();
pass.setPipeline(pipeline);
pass.setBindGroup(0, bindGroup);
pass.dispatchWorkgroups(1);
pass.end();
t.queue.submit([encoder.finish()]);
t.expectGPUBufferValuesEqual(resultBuffer, new Uint32Array([0]));
}
g.test('scalars')
.desc(`Test that scalars in private, and function storage classes can be initialized to a value.`)
.params(u =>
u
.combine('addressSpace', ['private', 'function'] as const)
.combine('type', ['bool', 'f32', 'f16', 'i32', 'u32'] as const)
)
.fn(async t => {
const typeDecl = t.params.type;
if (typeDecl === 'f16') {
t.skipIfDeviceDoesNotHaveFeature('shader-f16');
}
const testValue = Type[typeDecl].create(5).wgsl();
const comparison = `if (testVar != ${testValue}) {
atomicStore(&output.failed, 1u);
}`;
const wgsl = generateShader(
t.params.type === 'f16',
t.params.addressSpace,
typeDecl,
testValue,
comparison
);
await run(t, wgsl);
});
g.test('vec')
.desc(`Test that vectors in private, and function storage classes can be initialized to a value.`)
.params(u =>
u
.combine('addressSpace', ['private', 'function'] as const)
.combine('type', ['bool', 'f32', 'f16', 'i32', 'u32'] as const)
.combine('count', [2, 3, 4] as const)
)
.fn(async t => {
if (t.params.type === 'f16') {
t.skipIfDeviceDoesNotHaveFeature('shader-f16');
}
const typeDecl = `vec${t.params.count}<${t.params.type}>`;
const testValue = `${typeDecl}(${Type[t.params.type].create(5).wgsl()})`;
const comparison = `if (!all(testVar == ${testValue})) {
atomicStore(&output.failed, 1u);
}`;
const wgsl = generateShader(
t.params.type === 'f16',
t.params.addressSpace,
typeDecl,
testValue,
comparison
);
await run(t, wgsl);
});
g.test('mat')
.desc(
`Test that matrices in private, and function storage classes can be initialized to a value.`
)
.params(u =>
u
.combine('addressSpace', ['private', 'function'] as const)
.combine('type', ['f32', 'f16'] as const)
.beginSubcases()
.combine('c', [2, 3, 4] as const)
.combine('r', [2, 3, 4] as const)
)
.fn(async t => {
if (t.params.type === 'f16') {
t.skipIfDeviceDoesNotHaveFeature('shader-f16');
}
const typeDecl = `mat${t.params.c}x${t.params.r}<${t.params.type}>`;
const testScalarValue = Type[t.params.type].create(5).wgsl();
let testValue = `${typeDecl}(`;
for (let c = 0; c < t.params.c; c++) {
for (let r = 0; r < t.params.r; r++) {
testValue += `${testScalarValue},`;
}
}
testValue += ')';
const comparison = `for ( var i = 0; i < ${t.params.c}; i++) {
for (var k = 0; k < ${t.params.r}; k++) {
if (testVar[i][k] != ${testScalarValue}) {
atomicStore(&output.failed, 1u);
}
}
}`;
const wgsl = generateShader(
t.params.type === 'f16',
t.params.addressSpace,
typeDecl,
testValue,
comparison
);
await run(t, wgsl);
});
g.test('array')
.desc(`Test that arrays in private, and function storage classes can be initialized to a value.`)
.params(u =>
u
.combine('addressSpace', ['private', 'function'] as const)
.combine('type', ['bool', 'i32', 'u32', 'f32', 'f16'] as const)
)
.fn(async t => {
if (t.params.type === 'f16') {
t.skipIfDeviceDoesNotHaveFeature('shader-f16');
}
const arraySize = 4;
const typeDecl = `array<${t.params.type}, ${arraySize}>`;
const testScalarValue = Type[t.params.type].create(5).wgsl();
let testValue = `${typeDecl}(`;
for (let i = 0; i < arraySize; i++) {
testValue += `${testScalarValue},`;
}
testValue += ')';
const comparison = `for ( var i = 0; i < ${arraySize}; i++) {
if (testVar[i] != ${testScalarValue}) {
atomicStore(&output.failed, 1u);
}
}`;
const wgsl = generateShader(
t.params.type === 'f16',
t.params.addressSpace,
typeDecl,
testValue,
comparison
);
await run(t, wgsl);
});
g.test('array,nested')
.desc(`Test that arrays in private, and function storage classes can be initialized to a value.`)
.params(u =>
u
.combine('addressSpace', ['private', 'function'] as const)
.combine('type', ['bool', 'i32', 'u32', 'f32', 'f16'] as const)
)
.fn(async t => {
if (t.params.type === 'f16') {
t.skipIfDeviceDoesNotHaveFeature('shader-f16');
}
const arraySize = 4;
const innerDecl = `array<${t.params.type}, ${arraySize}>`;
const typeDecl = `array<${innerDecl}, ${arraySize}>`;
const testScalarValue = Type[t.params.type].create(5).wgsl();
let testValue = `${typeDecl}(`;
for (let i = 0; i < arraySize; i++) {
testValue += `${innerDecl}(`;
for (let j = 0; j < arraySize; j++) {
testValue += `${testScalarValue},`;
}
testValue += `),`;
}
testValue += ')';
const comparison = `
for ( var i = 0; i < ${arraySize}; i++) {
for ( var k = 0; k < ${arraySize}; k++) {
if (testVar[i][k] != ${testScalarValue}) {
atomicStore(&output.failed, 1u);
}
}
}
`;
const wgsl = generateShader(
t.params.type === 'f16',
t.params.addressSpace,
typeDecl,
testValue,
comparison
);
await run(t, wgsl);
});
g.test('struct')
.desc(`Test that structs in private, and function storage classes can be initialized to a value.`)
.params(u => u.combine('addressSpace', ['private', 'function'] as const))
.fn(async t => {
let moduleScope = `
struct Output {
failed : atomic<u32>
}
@group(0) @binding(0) var<storage, read_write> output : Output;
struct A {
a: i32,
b: f32,
}
struct S {
c: f32,
d: A,
e: array<i32, 2>,
}
`;
const typeDecl = 'S';
const testValue = 'S(5.f, A(5i, 5.f), array<i32, 2>(5i, 5i))';
let functionScope = '';
switch (t.params.addressSpace) {
case 'private':
moduleScope += `\nvar<private> testVar: ${typeDecl} = ${testValue};`;
break;
case 'function':
functionScope += `\nvar testVar: ${typeDecl} = ${testValue};`;
break;
}
const comparison = `
if (testVar.c != 5f || testVar.d.a != 5i || testVar.d.b != 5.f || testVar.e[0] != 5i || testVar.e[1] != 5i) {
atomicStore(&output.failed, 1u);
}
`;
const wgsl = `
${moduleScope}
@compute @workgroup_size(1, 1, 1)
fn main() {
${functionScope}
${comparison}
}
`;
await run(t, wgsl);
});