Skip to content

Commit

Permalink
wgsl: Add validation test for min/max builtin functions (#3497)
Browse files Browse the repository at this point in the history
* Add validation test for min/max builtin functions

* Address feedback from @dneto
  • Loading branch information
toji authored Mar 15, 2024
1 parent 3c568c6 commit 06cae14
Show file tree
Hide file tree
Showing 3 changed files with 188 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/webgpu/listing_meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -1909,6 +1909,12 @@
"webgpu:shader,validation,expression,call,builtin,log:integer_argument:*": { "subcaseMS": 1.134 },
"webgpu:shader,validation,expression,call,builtin,log:must_use:*": { "subcaseMS": 1597.590 },
"webgpu:shader,validation,expression,call,builtin,log:values:*": { "subcaseMS": 0.291 },
"webgpu:shader,validation,expression,call,builtin,max:args:*": { "subcaseMS": 77.529 },
"webgpu:shader,validation,expression,call,builtin,max:must_use:*": { "subcaseMS": 8.286 },
"webgpu:shader,validation,expression,call,builtin,max:values:*": { "subcaseMS": 260241.074 },
"webgpu:shader,validation,expression,call,builtin,min:args:*": { "subcaseMS": 67.260 },
"webgpu:shader,validation,expression,call,builtin,min:must_use:*": { "subcaseMS": 3.899 },
"webgpu:shader,validation,expression,call,builtin,min:values:*": { "subcaseMS": 246733.594 },
"webgpu:shader,validation,expression,call,builtin,modf:integer_argument:*": { "subcaseMS": 1.089 },
"webgpu:shader,validation,expression,call,builtin,modf:values:*": { "subcaseMS": 1.866 },
"webgpu:shader,validation,expression,call,builtin,pack4xI8:args:*": { "subcaseMS": 36.226 },
Expand Down
91 changes: 91 additions & 0 deletions src/webgpu/shader/validation/expression/call/builtin/max.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
const builtin = 'max';
export const description = `
Validation tests for the ${builtin}() builtin.
`;

import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js';
import {
Type,
kAllNumericScalarsAndVectors,
scalarTypeOf,
} from '../../../../../util/conversion.js';
import { ShaderValidationTest } from '../../../shader_validation_test.js';

import {
fullRangeForType,
kConstantAndOverrideStages,
stageSupportsType,
validateConstOrOverrideBuiltinEval,
} from './const_override_validation.js';

export const g = makeTestGroup(ShaderValidationTest);

const kValuesTypes = objectsToRecord(kAllNumericScalarsAndVectors);

g.test('values')
.desc(
`
Validates that constant evaluation and override evaluation of ${builtin}() never errors
`
)
.params(u =>
u
.combine('stage', kConstantAndOverrideStages)
.combine('type', keysOf(kValuesTypes))
.filter(u => stageSupportsType(u.stage, kValuesTypes[u.type]))
.beginSubcases()
.expand('a', u => fullRangeForType(kValuesTypes[u.type], 5))
.expand('b', u => fullRangeForType(kValuesTypes[u.type], 5))
)
.beforeAllSubcases(t => {
if (scalarTypeOf(kValuesTypes[t.params.type]) === Type.f16) {
t.selectDeviceOrSkipTestCase('shader-f16');
}
})
.fn(t => {
const type = kValuesTypes[t.params.type];
const expectedResult = true; // should never error
validateConstOrOverrideBuiltinEval(
t,
builtin,
expectedResult,
[type.create(t.params.a), type.create(t.params.b)],
t.params.stage
);
});

const kArgCases = {
good: '(1.1, 2.2)',
bad_no_parens: '',
// Bad number of args
bad_0args: '()',
bad_1arg: '(1.0)',
bad_3arg: '(1.0, 2.0, 3.0)',
// Bad value for arg 0
bad_0bool: '(false, 1.0)',
bad_0array: '(array(1.1,2.2), 1.0)',
bad_0struct: '(modf(2.2), 1.0)',
// Bad value type for arg 1
bad_1bool: '(1.0, true)',
bad_1array: '(1.0, array(1.1,2.2))',
bad_1struct: '(1.0, modf(2.2))',
};

g.test('args')
.desc(`Test compilation failure of ${builtin} with variously shaped and typed arguments`)
.params(u => u.combine('arg', keysOf(kArgCases)))
.fn(t => {
t.expectCompileResult(
t.params.arg === 'good',
`const c = ${builtin}${kArgCases[t.params.arg]};`
);
});

g.test('must_use')
.desc(`Result of ${builtin} must be used`)
.params(u => u.combine('use', [true, false]))
.fn(t => {
const use_it = t.params.use ? '_ = ' : '';
t.expectCompileResult(t.params.use, `fn f() { ${use_it}${builtin}${kArgCases['good']}; }`);
});
91 changes: 91 additions & 0 deletions src/webgpu/shader/validation/expression/call/builtin/min.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
const builtin = 'min';
export const description = `
Validation tests for the ${builtin}() builtin.
`;

import { makeTestGroup } from '../../../../../../common/framework/test_group.js';
import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js';
import {
Type,
kAllNumericScalarsAndVectors,
scalarTypeOf,
} from '../../../../../util/conversion.js';
import { ShaderValidationTest } from '../../../shader_validation_test.js';

import {
fullRangeForType,
kConstantAndOverrideStages,
stageSupportsType,
validateConstOrOverrideBuiltinEval,
} from './const_override_validation.js';

export const g = makeTestGroup(ShaderValidationTest);

const kValuesTypes = objectsToRecord(kAllNumericScalarsAndVectors);

g.test('values')
.desc(
`
Validates that constant evaluation and override evaluation of ${builtin}() never errors
`
)
.params(u =>
u
.combine('stage', kConstantAndOverrideStages)
.combine('type', keysOf(kValuesTypes))
.filter(u => stageSupportsType(u.stage, kValuesTypes[u.type]))
.beginSubcases()
.expand('a', u => fullRangeForType(kValuesTypes[u.type], 5))
.expand('b', u => fullRangeForType(kValuesTypes[u.type], 5))
)
.beforeAllSubcases(t => {
if (scalarTypeOf(kValuesTypes[t.params.type]) === Type.f16) {
t.selectDeviceOrSkipTestCase('shader-f16');
}
})
.fn(t => {
const type = kValuesTypes[t.params.type];
const expectedResult = true; // should never error
validateConstOrOverrideBuiltinEval(
t,
builtin,
expectedResult,
[type.create(t.params.a), type.create(t.params.b)],
t.params.stage
);
});

const kArgCases = {
good: '(1.1, 2.2)',
bad_no_parens: '',
// Bad number of args
bad_0args: '()',
bad_1arg: '(1.0)',
bad_3arg: '(1.0, 2.0, 3.0)',
// Bad value for arg 0
bad_0bool: '(false, 1.0)',
bad_0array: '(array(1.1,2.2), 1.0)',
bad_0struct: '(modf(2.2), 1.0)',
// Bad value type for arg 1
bad_1bool: '(1.0, true)',
bad_1array: '(1.0, array(1.1,2.2))',
bad_1struct: '(1.0, modf(2.2))',
};

g.test('args')
.desc(`Test compilation failure of ${builtin} with variously shaped and typed arguments`)
.params(u => u.combine('arg', keysOf(kArgCases)))
.fn(t => {
t.expectCompileResult(
t.params.arg === 'good',
`const c = ${builtin}${kArgCases[t.params.arg]};`
);
});

g.test('must_use')
.desc(`Result of ${builtin} must be used`)
.params(u => u.combine('use', [true, false]))
.fn(t => {
const use_it = t.params.use ? '_ = ' : '';
t.expectCompileResult(t.params.use, `fn f() { ${use_it}${builtin}${kArgCases['good']}; }`);
});

0 comments on commit 06cae14

Please sign in to comment.