diff options
Diffstat (limited to 'dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/call/builtin/faceForward.spec.ts')
-rw-r--r-- | dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/call/builtin/faceForward.spec.ts | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/call/builtin/faceForward.spec.ts b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/call/builtin/faceForward.spec.ts new file mode 100644 index 0000000000..22897f449a --- /dev/null +++ b/dom/webgpu/tests/cts/checkout/src/webgpu/shader/execution/expression/call/builtin/faceForward.spec.ts @@ -0,0 +1,201 @@ +export const description = ` +Execution tests for the 'faceForward' builtin function + +T is vecN<AbstractFloat>, vecN<f32>, or vecN<f16> +@const fn faceForward(e1: T ,e2: T ,e3: T ) -> T +Returns e1 if dot(e2,e3) is negative, and -e1 otherwise. +`; + +import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; +import { GPUTest } from '../../../../../gpu_test.js'; +import { anyOf } from '../../../../../util/compare.js'; +import { f32, TypeF32, TypeVec, Vector } from '../../../../../util/conversion.js'; +import { F32Vector, faceForwardIntervals } from '../../../../../util/f32_interval.js'; +import { cartesianProduct, quantizeToF32, sparseVectorF32Range } from '../../../../../util/math.js'; +import { makeCaseCache } from '../../case_cache.js'; +import { allInputSources, Case, IntervalFilter, run } from '../../expression.js'; + +import { builtin } from './builtin.js'; + +export const g = makeTestGroup(GPUTest); + +// Using a bespoke implementation of make*Case and generate*Cases here +// since faceForwardIntervals is the only builtin with the API signature +// (vec, vec, vec) -> vec +// +// Additionally faceForward has significant complexities around it due to the +// fact that `dot` is calculated in it s operation, but the result of dot isn't +// used to calculate the builtin's result. + +/** + * @returns a Case for `faceForward` + * @param x the `x` param for the case + * @param y the `y` param for the case + * @param z the `z` param for the case + * @param check what interval checking to apply + * */ +function makeCaseF32( + x: number[], + y: number[], + z: number[], + check: IntervalFilter +): Case | undefined { + x = x.map(quantizeToF32); + y = y.map(quantizeToF32); + z = z.map(quantizeToF32); + + const x_f32 = x.map(f32); + const y_f32 = y.map(f32); + const z_f32 = z.map(f32); + + const results = faceForwardIntervals(x, y, z); + if (check === 'f32-only' && results.some(r => r === undefined)) { + return undefined; + } + + // Stripping the undefined results, since undefined is used to signal that an OOB + // could occur within the calculation that isn't reflected in the result + // intervals. + const define_results = results.filter((r): r is F32Vector => r !== undefined); + + return { + input: [new Vector(x_f32), new Vector(y_f32), new Vector(z_f32)], + expected: anyOf(...define_results), + }; +} + +/** + * @returns an array of Cases for `faceForward` + * @param xs array of inputs to try for the `x` param + * @param ys array of inputs to try for the `y` param + * @param zs array of inputs to try for the `z` param + * @param check what interval checking to apply + */ +function generateCasesF32( + xs: number[][], + ys: number[][], + zs: number[][], + check: IntervalFilter +): Case[] { + // Cannot use `cartesianProduct` here due to heterogeneous param types + return cartesianProduct(xs, ys, zs) + .map(e => makeCaseF32(e[0], e[1], e[2], check)) + .filter((c): c is Case => c !== undefined); +} + +export const d = makeCaseCache('faceForward', { + f32_vec2_const: () => { + return generateCasesF32( + sparseVectorF32Range(2), + sparseVectorF32Range(2), + sparseVectorF32Range(2), + 'f32-only' + ); + }, + f32_vec2_non_const: () => { + return generateCasesF32( + sparseVectorF32Range(2), + sparseVectorF32Range(2), + sparseVectorF32Range(2), + 'unfiltered' + ); + }, + f32_vec3_const: () => { + return generateCasesF32( + sparseVectorF32Range(3), + sparseVectorF32Range(3), + sparseVectorF32Range(3), + 'f32-only' + ); + }, + f32_vec3_non_const: () => { + return generateCasesF32( + sparseVectorF32Range(3), + sparseVectorF32Range(3), + sparseVectorF32Range(3), + 'unfiltered' + ); + }, + f32_vec4_const: () => { + return generateCasesF32( + sparseVectorF32Range(4), + sparseVectorF32Range(4), + sparseVectorF32Range(4), + 'f32-only' + ); + }, + f32_vec4_non_const: () => { + return generateCasesF32( + sparseVectorF32Range(4), + sparseVectorF32Range(4), + sparseVectorF32Range(4), + 'unfiltered' + ); + }, +}); + +g.test('abstract_float') + .specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions') + .desc(`abstract float tests`) + .params(u => u.combine('inputSource', allInputSources).combine('vectorize', [2, 3, 4] as const)) + .unimplemented(); + +g.test('f32_vec2') + .specURL('https://www.w3.org/TR/WGSL/#numeric-builtin-functions') + .desc(`f32 tests using vec2s`) + .params(u => u.combine('inputSource', allInputSources)) + .fn(async t => { + const cases = await d.get( + t.params.inputSource === 'const' ? 'f32_vec2_const' : 'f32_vec2_non_const' + ); + await run( + t, + builtin('faceForward'), + [TypeVec(2, TypeF32), TypeVec(2, TypeF32), TypeVec(2, TypeF32)], + TypeVec(2, TypeF32), + t.params, + cases + ); + }); + +g.test('f32_vec3') + .specURL('https://www.w3.org/TR/WGSL/#numeric-builtin-functions') + .desc(`f32 tests using vec3s`) + .params(u => u.combine('inputSource', allInputSources)) + .fn(async t => { + const cases = await d.get( + t.params.inputSource === 'const' ? 'f32_vec3_const' : 'f32_vec3_non_const' + ); + await run( + t, + builtin('faceForward'), + [TypeVec(3, TypeF32), TypeVec(3, TypeF32), TypeVec(3, TypeF32)], + TypeVec(3, TypeF32), + t.params, + cases + ); + }); + +g.test('f32_vec4') + .specURL('https://www.w3.org/TR/WGSL/#numeric-builtin-functions') + .desc(`f32 tests using vec4s`) + .params(u => u.combine('inputSource', allInputSources)) + .fn(async t => { + const cases = await d.get( + t.params.inputSource === 'const' ? 'f32_vec4_const' : 'f32_vec4_non_const' + ); + await run( + t, + builtin('faceForward'), + [TypeVec(4, TypeF32), TypeVec(4, TypeF32), TypeVec(4, TypeF32)], + TypeVec(4, TypeF32), + t.params, + cases + ); + }); + +g.test('f16') + .specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions') + .desc(`f16 tests`) + .params(u => u.combine('inputSource', allInputSources).combine('vectorize', [2, 3, 4] as const)) + .unimplemented(); |