summaryrefslogtreecommitdiffstats
path: root/dom/webgpu/tests/cts/checkout/src/webgpu/shader/validation/expression/call/builtin/reflect.spec.ts
diff options
context:
space:
mode:
Diffstat (limited to 'dom/webgpu/tests/cts/checkout/src/webgpu/shader/validation/expression/call/builtin/reflect.spec.ts')
-rw-r--r--dom/webgpu/tests/cts/checkout/src/webgpu/shader/validation/expression/call/builtin/reflect.spec.ts131
1 files changed, 131 insertions, 0 deletions
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/validation/expression/call/builtin/reflect.spec.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/validation/expression/call/builtin/reflect.spec.ts
new file mode 100644
index 0000000000..c71f37f895
--- /dev/null
+++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/validation/expression/call/builtin/reflect.spec.ts
@@ -0,0 +1,131 @@
+const builtin = 'reflect';
+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,
+ kConvertableToFloatVectors,
+ scalarTypeOf,
+ ScalarType,
+} from '../../../../../util/conversion.js';
+import { QuantizeFunc, quantizeToF16, quantizeToF32 } from '../../../../../util/math.js';
+import { ShaderValidationTest } from '../../../shader_validation_test.js';
+
+import {
+ fullRangeForType,
+ kConstantAndOverrideStages,
+ stageSupportsType,
+ validateConstOrOverrideBuiltinEval,
+} from './const_override_validation.js';
+
+export const g = makeTestGroup(ShaderValidationTest);
+
+const kValidArgumentTypes = objectsToRecord(kConvertableToFloatVectors);
+
+function quantizeFunctionForScalarType(type: ScalarType): QuantizeFunc<number> {
+ switch (type) {
+ case Type.f32:
+ return quantizeToF32;
+ case Type.f16:
+ return quantizeToF16;
+ default:
+ return (v: number) => v;
+ }
+}
+
+g.test('values')
+ .desc(
+ `
+Validates that constant evaluation and override evaluation of ${builtin}() never errors
+`
+ )
+ .params(u =>
+ u
+ .combine('stage', kConstantAndOverrideStages)
+ .combine('type', keysOf(kValidArgumentTypes))
+ .filter(u => stageSupportsType(u.stage, kValidArgumentTypes[u.type]))
+ .beginSubcases()
+ .expand('a', u => fullRangeForType(kValidArgumentTypes[u.type], 5))
+ .expand('b', u => fullRangeForType(kValidArgumentTypes[u.type], 5))
+ )
+ .beforeAllSubcases(t => {
+ if (scalarTypeOf(kValidArgumentTypes[t.params.type]) === Type.f16) {
+ t.selectDeviceOrSkipTestCase('shader-f16');
+ }
+ })
+ .fn(t => {
+ let expectedResult = true;
+
+ const scalarType = scalarTypeOf(kValidArgumentTypes[t.params.type]);
+ const quantizeFn = quantizeFunctionForScalarType(scalarType);
+
+ // Reflect equation: a - 2 * dot(b, a) * b
+ // Should be invalid if the reflect calculations result in intermediate
+ // values that exceed the maximum representable float value for the given type.
+ const a = Number(t.params.a);
+ const b = Number(t.params.b);
+ const ab = quantizeFn(a * b);
+ const dp = quantizeFn(ab * kValidArgumentTypes[t.params.type].width);
+ const dp2 = quantizeFn(dp * 2);
+ const dp2b = quantizeFn(dp2 * b);
+ const a_dp2b = quantizeFn(a - dp2b);
+
+ if (
+ !Number.isFinite(ab) ||
+ !Number.isFinite(dp) ||
+ !Number.isFinite(dp2) ||
+ !Number.isFinite(dp2b) ||
+ !Number.isFinite(a_dp2b)
+ ) {
+ expectedResult = false;
+ }
+
+ const type = kValidArgumentTypes[t.params.type];
+
+ // Validates reflect(vecN(a, a, a), vecN(b, b, b));
+ validateConstOrOverrideBuiltinEval(
+ t,
+ builtin,
+ expectedResult,
+ [type.create(t.params.a), type.create(t.params.b)],
+ t.params.stage
+ );
+ });
+
+const kArgCases = {
+ good: '(vec3(0), vec3(1))',
+ bad_no_parens: '',
+ // Bad number of args
+ bad_0args: '()',
+ bad_1arg: '(vec3(0))',
+ bad_3arg: '(vec3(0), vec3(1), vec3(2))',
+ // Bad value for arg 0
+ bad_0bool: '(false, vec3(1))',
+ bad_0array: '(array(1.1,2.2), vec3(1))',
+ bad_0struct: '(modf(2.2), vec3(1))',
+ // Bad value type for arg 1
+ bad_1bool: '(vec3(0), true)',
+ bad_1array: '(vec3(0), array(1.1,2.2))',
+ bad_1struct: '(vec3(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']}; }`);
+ });