diff --git a/src/webgpu/shader/validation/expression/call/builtin/normalize.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/normalize.spec.ts index 28e1d9cdc61b..bed18020632d 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/normalize.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/normalize.spec.ts @@ -12,7 +12,13 @@ import { scalarTypeOf, ScalarType, } from '../../../../../util/conversion.js'; -import { QuantizeFunc, quantizeToF16, quantizeToF32 } from '../../../../../util/math.js'; +import { + QuantizeFunc, + quantizeToF16, + quantizeToF32, + isSubnormalNumberF16, + isSubnormalNumberF32, +} from '../../../../../util/math.js'; import { ShaderValidationTest } from '../../../shader_validation_test.js'; import { @@ -37,6 +43,17 @@ function quantizeFunctionForScalarType(type: ScalarType): QuantizeFunc { } } +function isSubnormalFunctionForScalarType(type: ScalarType): (v: number) => boolean { + switch (type) { + case Type.f32: + return isSubnormalNumberF32; + case Type.f16: + return isSubnormalNumberF16; + default: + return (v: number) => false; + } +} + g.test('values') .desc( ` @@ -73,6 +90,11 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec expectedResult = false; } + // We skip tests with values that would involve subnormal computations in + // order to avoid defining a specific behavior (flush to zero). + const isSubnormalFn = isSubnormalFunctionForScalarType(scalarType); + t.skipIf(isSubnormalFn(vv) || isSubnormalFn(dp) || isSubnormalFn(len)); + validateConstOrOverrideBuiltinEval( t, builtin, diff --git a/src/webgpu/shader/validation/expression/call/builtin/refract.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/refract.spec.ts index 51cf9553785c..387340f80e9f 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/refract.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/refract.spec.ts @@ -2,10 +2,21 @@ const builtin = 'refract'; 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 } from '../../../../../util/conversion.js'; +import { + Type, + kConvertableToFloatVectors, + scalarTypeOf, + ScalarType, +} from '../../../../../util/conversion.js'; +import { + QuantizeFunc, + quantizeToF16, + quantizeToF32, + isSubnormalNumberF16, + isSubnormalNumberF32, +} from '../../../../../util/math.js'; import { ShaderValidationTest } from '../../../shader_validation_test.js'; import { @@ -20,6 +31,28 @@ export const g = makeTestGroup(ShaderValidationTest); const kValidArgumentTypes = objectsToRecord(kConvertableToFloatVectors); +function quantizeFunctionForScalarType(type: ScalarType): QuantizeFunc { + switch (type) { + case Type.f32: + return quantizeToF32; + case Type.f16: + return quantizeToF16; + default: + return (v: number) => v; + } +} + +function isSubnormalFunctionForScalarType(type: ScalarType): (v: number) => boolean { + switch (type) { + case Type.f32: + return isSubnormalNumberF32; + case Type.f16: + return isSubnormalNumberF16; + default: + return (v: number) => false; + } +} + g.test('values') .desc( ` @@ -64,6 +97,17 @@ where a the calculations result in a non-representable value for the given type. const c2_one_minus_b_dot_a_2 = vCheck.checkedResult(c2 * one_minus_b_dot_a_2); const k = vCheck.checkedResult(1.0 - c2_one_minus_b_dot_a_2); + const quantizeFn = quantizeFunctionForScalarType(scalarType); + const isSubnormalFn = isSubnormalFunctionForScalarType(scalarType); + // We skip tests with values that would involve subnormal computations in + // order to avoid defining a specific behavior (flush to zero). + t.skipIf( + isSubnormalFn(quantizeFn(b_dot_a)) || + isSubnormalFn(quantizeFn(b_dot_a_2)) || + isSubnormalFn(quantizeFn(c2)) || + isSubnormalFn(quantizeFn(k)) + ); + if (k >= 0) { // If the k is near zero it may fail on some implementations which implement sqrt as // 1/inversesqrt, so skip the test.