diff --git a/Gruntfile.js b/Gruntfile.js index c354249f8b69..eba38704f3ee 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -24,9 +24,9 @@ module.exports = function (grunt) { cmd: 'node', args: ['tools/gen_version'], }, - 'generate-listings': { + 'generate-listings-and-webworkers': { cmd: 'node', - args: ['tools/gen_listings', 'gen/', ...kAllSuites.map(s => 'src/' + s)], + args: ['tools/gen_listings_and_webworkers', 'gen/', ...kAllSuites.map(s => 'src/' + s)], }, validate: { cmd: 'node', @@ -159,14 +159,14 @@ module.exports = function (grunt) { // Must run after generate-common and run:build-out. files: [ { expand: true, dest: 'out/', cwd: 'gen', src: 'common/internal/version.js' }, - { expand: true, dest: 'out/', cwd: 'gen', src: '*/listing.js' }, + { expand: true, dest: 'out/', cwd: 'gen', src: '*/**/*.js' }, ], }, 'gen-to-out-wpt': { // Must run after generate-common and run:build-out-wpt. files: [ { expand: true, dest: 'out-wpt/', cwd: 'gen', src: 'common/internal/version.js' }, - { expand: true, dest: 'out-wpt/', cwd: 'gen', src: 'webgpu/listing.js' }, + { expand: true, dest: 'out-wpt/', cwd: 'gen', src: 'webgpu/**/*.js' }, ], }, 'htmlfiles-to-out': { @@ -243,7 +243,7 @@ module.exports = function (grunt) { grunt.registerTask('generate-common', 'Generate files into gen/ and src/', [ 'run:generate-version', - 'run:generate-listings', + 'run:generate-listings-and-webworkers', 'run:generate-cache', ]); grunt.registerTask('build-standalone', 'Build out/ (no checks; run after generate-common)', [ diff --git a/docs/intro/developing.md b/docs/intro/developing.md index d8869f985b31..c706e0c1c1b8 100644 --- a/docs/intro/developing.md +++ b/docs/intro/developing.md @@ -56,8 +56,9 @@ The following url parameters change how the harness runs: - `runnow=1` runs all matching tests on page load. - `debug=1` enables verbose debug logging from tests. -- `worker=dedicated` runs the tests on a dedicated worker instead of the main thread. +- `worker=dedicated` (or `worker` or `worker=1`) runs the tests on a dedicated worker instead of the main thread. - `worker=shared` runs the tests on a shared worker instead of the main thread. +- `worker=service` runs the tests on a service worker instead of the main thread. - `power_preference=low-power` runs most tests passing `powerPreference: low-power` to `requestAdapter` - `power_preference=high-performance` runs most tests passing `powerPreference: high-performance` to `requestAdapter` diff --git a/docs/terms.md b/docs/terms.md index 032639be577a..0dc6f0ca1701 100644 --- a/docs/terms.md +++ b/docs/terms.md @@ -111,7 +111,7 @@ Each Suite has one Listing File (`suite/listing.[tj]s`), containing a list of th in the suite. In `src/suite/listing.ts`, this is computed dynamically. -In `out/suite/listing.js`, the listing has been pre-baked (by `tools/gen_listings`). +In `out/suite/listing.js`, the listing has been pre-baked (by `tools/gen_listings_and_webworkers`). **Type:** Once `import`ed, `ListingFile` diff --git a/src/common/internal/query/compare.ts b/src/common/internal/query/compare.ts index a9419b87c196..f49833f5a2e0 100644 --- a/src/common/internal/query/compare.ts +++ b/src/common/internal/query/compare.ts @@ -58,7 +58,10 @@ function compareOneLevel(ordering: Ordering, aIsBig: boolean, bIsBig: boolean): return Ordering.Unordered; } -function comparePaths(a: readonly string[], b: readonly string[]): Ordering { +/** + * Compare two file paths, or file-local test paths, returning an Ordering between the two. + */ +export function comparePaths(a: readonly string[], b: readonly string[]): Ordering { const shorter = Math.min(a.length, b.length); for (let i = 0; i < shorter; ++i) { diff --git a/src/common/internal/query/query.ts b/src/common/internal/query/query.ts index ad7cf246e9d9..676ac46d3888 100644 --- a/src/common/internal/query/query.ts +++ b/src/common/internal/query/query.ts @@ -1,5 +1,5 @@ import { TestParams } from '../../framework/fixture.js'; -import { optionString } from '../../runtime/helper/options.js'; +import { optionWorkerMode } from '../../runtime/helper/options.js'; import { assert, unreachable } from '../../util/util.js'; import { Expectation } from '../logging/result.js'; @@ -193,7 +193,7 @@ Expectation should be of the form path/to/cts.https.html?debug=0&q=suite:test_pa ); const params = expectationURL.searchParams; - if (optionString('worker', params) !== optionString('worker', wptURL.searchParams)) { + if (optionWorkerMode('worker', params) !== optionWorkerMode('worker', wptURL.searchParams)) { continue; } diff --git a/src/common/internal/test_suite_listing.ts b/src/common/internal/test_suite_listing.ts index 2d2b555366e4..c5a0e1144839 100644 --- a/src/common/internal/test_suite_listing.ts +++ b/src/common/internal/test_suite_listing.ts @@ -1,6 +1,6 @@ // A listing of all specs within a single suite. This is the (awaited) type of // `groups` in '{cts,unittests}/listing.ts' and `listing` in the auto-generated -// 'out/{cts,unittests}/listing.js' files (see tools/gen_listings). +// 'out/{cts,unittests}/listing.js' files (see tools/gen_listings_and_webworkers). export type TestSuiteListing = TestSuiteListingEntry[]; export type TestSuiteListingEntry = TestSuiteListingEntrySpec | TestSuiteListingEntryReadme; diff --git a/src/common/runtime/helper/options.ts b/src/common/runtime/helper/options.ts index 60c2d1069181..38000341d945 100644 --- a/src/common/runtime/helper/options.ts +++ b/src/common/runtime/helper/options.ts @@ -1,3 +1,5 @@ +import { unreachable } from '../../util/util.js'; + let windowURL: URL | undefined = undefined; function getWindowURL() { if (windowURL === undefined) { @@ -6,6 +8,7 @@ function getWindowURL() { return windowURL; } +/** Parse a runner option that is always boolean-typed. False if missing or '0'. */ export function optionEnabled( opt: string, searchParams: URLSearchParams = getWindowURL().searchParams @@ -14,6 +17,7 @@ export function optionEnabled( return val !== null && val !== '0'; } +/** Parse a runner option that is always string-typed. If the option is missing, returns `''`. */ export function optionString( opt: string, searchParams: URLSearchParams = getWindowURL().searchParams @@ -21,20 +25,40 @@ export function optionString( return searchParams.get(opt) || ''; } +/** Runtime modes for whether to run tests in a worker. '0' means no worker. */ +type WorkerMode = '0' | 'dedicated' | 'service' | 'shared'; +/** Parse a runner option for different worker modes (as in `?worker=shared`). */ +export function optionWorkerMode( + opt: string, + searchParams: URLSearchParams = getWindowURL().searchParams +): WorkerMode { + const value = searchParams.get(opt); + if (value === null || value === '0') { + return '0'; + } else if (value === 'service') { + return 'service'; + } else if (value === 'shared') { + return 'shared'; + } else if (value === '' || value === '1' || value === 'dedicated') { + return 'dedicated'; + } + unreachable('invalid worker= option value'); +} + /** * The possible options for the tests. */ export interface CTSOptions { - worker?: 'dedicated' | 'shared' | ''; + worker: WorkerMode; debug: boolean; compatibility: boolean; forceFallbackAdapter: boolean; unrollConstEvalLoops: boolean; - powerPreference?: GPUPowerPreference | ''; + powerPreference: GPUPowerPreference | ''; } export const kDefaultCTSOptions: CTSOptions = { - worker: '', + worker: '0', debug: true, compatibility: false, forceFallbackAdapter: false, @@ -63,11 +87,12 @@ export type OptionsInfos = Record; export const kCTSOptionsInfo: OptionsInfos = { worker: { description: 'run in a worker', - parser: optionString, + parser: optionWorkerMode, selectValueDescriptions: [ - { value: '', description: 'no worker' }, + { value: '0', description: 'no worker' }, { value: 'dedicated', description: 'dedicated worker' }, { value: 'shared', description: 'shared worker' }, + { value: 'service', description: 'service worker' }, ], }, debug: { description: 'show more info' }, diff --git a/src/common/runtime/helper/test_worker-worker.ts b/src/common/runtime/helper/test_worker-worker.ts index caf6e7a1bc17..cb31f4d26388 100644 --- a/src/common/runtime/helper/test_worker-worker.ts +++ b/src/common/runtime/helper/test_worker-worker.ts @@ -1,13 +1,9 @@ import { setBaseResourcePath } from '../../framework/resources.js'; -import { globalTestConfig } from '../../framework/test_config.js'; import { DefaultTestFileLoader } from '../../internal/file_loader.js'; -import { Logger } from '../../internal/logging/logger.js'; import { parseQuery } from '../../internal/query/parseQuery.js'; -import { TestQueryWithExpectation } from '../../internal/query/query.js'; -import { setDefaultRequestAdapterOptions } from '../../util/navigator_gpu.js'; import { assert } from '../../util/util.js'; -import { CTSOptions } from './options.js'; +import { setupWorkerEnvironment, WorkerTestRunRequest } from './utils_worker.js'; // Should be WorkerGlobalScope, but importing lib "webworker" conflicts with lib "dom". /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ @@ -18,24 +14,9 @@ const loader = new DefaultTestFileLoader(); setBaseResourcePath('../../../resources'); async function reportTestResults(this: MessagePort | Worker, ev: MessageEvent) { - const query: string = ev.data.query; - const expectations: TestQueryWithExpectation[] = ev.data.expectations; - const ctsOptions: CTSOptions = ev.data.ctsOptions; + const { query, expectations, ctsOptions } = ev.data as WorkerTestRunRequest; - const { debug, unrollConstEvalLoops, powerPreference, compatibility } = ctsOptions; - globalTestConfig.unrollConstEvalLoops = unrollConstEvalLoops; - globalTestConfig.compatibility = compatibility; - - Logger.globalDebugMode = debug; - const log = new Logger(); - - if (powerPreference || compatibility) { - setDefaultRequestAdapterOptions({ - ...(powerPreference && { powerPreference }), - // MAINTENANCE_TODO: Change this to whatever the option ends up being - ...(compatibility && { compatibilityMode: true }), - }); - } + const log = setupWorkerEnvironment(ctsOptions); const testcases = Array.from(await loader.loadCases(parseQuery(query))); assert(testcases.length === 1, 'worker query resulted in != 1 cases'); @@ -48,7 +29,7 @@ async function reportTestResults(this: MessagePort | Worker, ev: MessageEvent) { } self.onmessage = (ev: MessageEvent) => { - void reportTestResults.call(self, ev); + void reportTestResults.call(ev.source || self, ev); }; self.onconnect = (event: MessageEvent) => { diff --git a/src/common/runtime/helper/test_worker.ts b/src/common/runtime/helper/test_worker.ts index 9e2ec17efa95..42848106b68e 100644 --- a/src/common/runtime/helper/test_worker.ts +++ b/src/common/runtime/helper/test_worker.ts @@ -2,80 +2,121 @@ import { LogMessageWithStack } from '../../internal/logging/log_message.js'; import { TransferredTestCaseResult, LiveTestCaseResult } from '../../internal/logging/result.js'; import { TestCaseRecorder } from '../../internal/logging/test_case_recorder.js'; import { TestQueryWithExpectation } from '../../internal/query/query.js'; +import { timeout } from '../../util/timeout.js'; +import { assert } from '../../util/util.js'; import { CTSOptions, kDefaultCTSOptions } from './options.js'; +import { WorkerTestRunRequest } from './utils_worker.js'; -export class TestDedicatedWorker { - private readonly ctsOptions: CTSOptions; - private readonly worker: Worker; - private readonly resolvers = new Map void>(); +/** Query all currently-registered service workers, and unregister them. */ +function unregisterAllServiceWorkers() { + void navigator.serviceWorker.getRegistrations().then(registrations => { + for (const registration of registrations) { + void registration.unregister(); + } + }); +} - constructor(ctsOptions?: CTSOptions) { - this.ctsOptions = { ...(ctsOptions || kDefaultCTSOptions), ...{ worker: 'dedicated' } }; - const selfPath = import.meta.url; - const selfPathDir = selfPath.substring(0, selfPath.lastIndexOf('/')); - const workerPath = selfPathDir + '/test_worker-worker.js'; - this.worker = new Worker(workerPath, { type: 'module' }); - this.worker.onmessage = ev => { - const query: string = ev.data.query; - const result: TransferredTestCaseResult = ev.data.result; - if (result.logs) { - for (const l of result.logs) { - Object.setPrototypeOf(l, LogMessageWithStack.prototype); - } +// NOTE: This code runs on startup for any runtime with worker support. Here, we use that chance to +// delete any leaked service workers, and register to clean up after ourselves at shutdown. +unregisterAllServiceWorkers(); +window.addEventListener('beforeunload', () => { + unregisterAllServiceWorkers(); +}); + +class TestBaseWorker { + protected readonly ctsOptions: CTSOptions; + protected readonly resolvers = new Map void>(); + + constructor(worker: CTSOptions['worker'], ctsOptions?: CTSOptions) { + this.ctsOptions = { ...(ctsOptions || kDefaultCTSOptions), ...{ worker } }; + } + + onmessage(ev: MessageEvent) { + const query: string = ev.data.query; + const result: TransferredTestCaseResult = ev.data.result; + if (result.logs) { + for (const l of result.logs) { + Object.setPrototypeOf(l, LogMessageWithStack.prototype); } - this.resolvers.get(query)!(result as LiveTestCaseResult); + } + this.resolvers.get(query)!(result as LiveTestCaseResult); + this.resolvers.delete(query); - // MAINTENANCE_TODO(kainino0x): update the Logger with this result (or don't have a logger and - // update the entire results JSON somehow at some point). - }; + // MAINTENANCE_TODO(kainino0x): update the Logger with this result (or don't have a logger and + // update the entire results JSON somehow at some point). } - async run( + async makeRequestAndRecordResult( + target: MessagePort | Worker | ServiceWorker, rec: TestCaseRecorder, query: string, - expectations: TestQueryWithExpectation[] = [] - ): Promise { - this.worker.postMessage({ + expectations: TestQueryWithExpectation[] + ) { + const request: WorkerTestRunRequest = { query, expectations, ctsOptions: this.ctsOptions, - }); + }; + target.postMessage(request); + const workerResult = await new Promise(resolve => { + assert(!this.resolvers.has(query), "can't request same query twice simultaneously"); this.resolvers.set(query, resolve); }); rec.injectResult(workerResult); } } +export class TestDedicatedWorker extends TestBaseWorker { + private readonly worker: Worker; + + constructor(ctsOptions?: CTSOptions) { + super('dedicated', ctsOptions); + const selfPath = import.meta.url; + const selfPathDir = selfPath.substring(0, selfPath.lastIndexOf('/')); + const workerPath = selfPathDir + '/test_worker-worker.js'; + this.worker = new Worker(workerPath, { type: 'module' }); + this.worker.onmessage = ev => this.onmessage(ev); + } + + async run( + rec: TestCaseRecorder, + query: string, + expectations: TestQueryWithExpectation[] = [] + ): Promise { + await this.makeRequestAndRecordResult(this.worker, rec, query, expectations); + } +} + export class TestWorker extends TestDedicatedWorker {} -export class TestSharedWorker { - private readonly ctsOptions: CTSOptions; +export class TestSharedWorker extends TestBaseWorker { private readonly port: MessagePort; - private readonly resolvers = new Map void>(); constructor(ctsOptions?: CTSOptions) { - this.ctsOptions = { ...(ctsOptions || kDefaultCTSOptions), ...{ worker: 'shared' } }; + super('shared', ctsOptions); const selfPath = import.meta.url; const selfPathDir = selfPath.substring(0, selfPath.lastIndexOf('/')); const workerPath = selfPathDir + '/test_worker-worker.js'; const worker = new SharedWorker(workerPath, { type: 'module' }); this.port = worker.port; this.port.start(); - this.port.onmessage = ev => { - const query: string = ev.data.query; - const result: TransferredTestCaseResult = ev.data.result; - if (result.logs) { - for (const l of result.logs) { - Object.setPrototypeOf(l, LogMessageWithStack.prototype); - } - } - this.resolvers.get(query)!(result as LiveTestCaseResult); + this.port.onmessage = ev => this.onmessage(ev); + } - // MAINTENANCE_TODO(kainino0x): update the Logger with this result (or don't have a logger and - // update the entire results JSON somehow at some point). - }; + async run( + rec: TestCaseRecorder, + query: string, + expectations: TestQueryWithExpectation[] = [] + ): Promise { + await this.makeRequestAndRecordResult(this.port, rec, query, expectations); + } +} + +export class TestServiceWorker extends TestBaseWorker { + constructor(ctsOptions?: CTSOptions) { + super('service', ctsOptions); } async run( @@ -83,14 +124,25 @@ export class TestSharedWorker { query: string, expectations: TestQueryWithExpectation[] = [] ): Promise { - this.port.postMessage({ - query, - expectations, - ctsOptions: this.ctsOptions, - }); - const workerResult = await new Promise(resolve => { - this.resolvers.set(query, resolve); + const [suite, name] = query.split(':', 2); + const fileName = name.split(',').join('/'); + const serviceWorkerURL = new URL( + `/out/${suite}/webworker/${fileName}.worker.js`, + window.location.href + ).toString(); + + // If a registration already exists for this path, it will be ignored. + const registration = await navigator.serviceWorker.register(serviceWorkerURL, { + type: 'module', }); - rec.injectResult(workerResult); + // Make sure the registration we just requested is active. (We don't worry about it being + // outdated from a previous page load, because we wipe all service workers on shutdown/startup.) + while (!registration.active || registration.active.scriptURL !== serviceWorkerURL) { + await new Promise(resolve => timeout(resolve, 0)); + } + const serviceWorker = registration.active; + + navigator.serviceWorker.onmessage = ev => this.onmessage(ev); + await this.makeRequestAndRecordResult(serviceWorker, rec, query, expectations); } } diff --git a/src/common/runtime/helper/utils_worker.ts b/src/common/runtime/helper/utils_worker.ts new file mode 100644 index 000000000000..c8ca6a2a3a0a --- /dev/null +++ b/src/common/runtime/helper/utils_worker.ts @@ -0,0 +1,34 @@ +import { globalTestConfig } from '../../framework/test_config.js'; +import { Logger } from '../../internal/logging/logger.js'; +import { TestQueryWithExpectation } from '../../internal/query/query.js'; +import { setDefaultRequestAdapterOptions } from '../../util/navigator_gpu.js'; + +import { CTSOptions } from './options.js'; + +export interface WorkerTestRunRequest { + query: string; + expectations: TestQueryWithExpectation[]; + ctsOptions: CTSOptions; +} + +/** + * Set config environment for workers with ctsOptions and return a Logger. + */ +export function setupWorkerEnvironment(ctsOptions: CTSOptions): Logger { + const { debug, unrollConstEvalLoops, powerPreference, compatibility } = ctsOptions; + globalTestConfig.unrollConstEvalLoops = unrollConstEvalLoops; + globalTestConfig.compatibility = compatibility; + + Logger.globalDebugMode = debug; + const log = new Logger(); + + if (powerPreference || compatibility) { + setDefaultRequestAdapterOptions({ + ...(powerPreference && { powerPreference }), + // MAINTENANCE_TODO: Change this to whatever the option ends up being + ...(compatibility && { compatibilityMode: true }), + }); + } + + return log; +} diff --git a/src/common/runtime/helper/wrap_for_worker.ts b/src/common/runtime/helper/wrap_for_worker.ts new file mode 100644 index 000000000000..8e206f8399ab --- /dev/null +++ b/src/common/runtime/helper/wrap_for_worker.ts @@ -0,0 +1,43 @@ +import { Fixture } from '../../framework/fixture'; +import { LogMessageWithStack } from '../../internal/logging/log_message.js'; +import { comparePaths, comparePublicParamsPaths, Ordering } from '../../internal/query/compare.js'; +import { parseQuery } from '../../internal/query/parseQuery.js'; +import { TestQuerySingleCase } from '../../internal/query/query.js'; +import { TestGroup } from '../../internal/test_group.js'; +import { assert } from '../../util/util.js'; + +import { setupWorkerEnvironment, WorkerTestRunRequest } from './utils_worker.js'; + +export function wrapTestGroupForWorker(g: TestGroup) { + self.onmessage = async (ev: MessageEvent) => { + const { query, expectations, ctsOptions } = ev.data as WorkerTestRunRequest; + try { + const log = setupWorkerEnvironment(ctsOptions); + + const testQuery = parseQuery(query); + assert(testQuery instanceof TestQuerySingleCase); + let testcase = null; + for (const t of g.iterate()) { + if (comparePaths(t.testPath, testQuery.testPathParts) !== Ordering.Equal) { + continue; + } + for (const c of t.iterate(testQuery.params)) { + if (comparePublicParamsPaths(c.id.params, testQuery.params) === Ordering.Equal) { + testcase = c; + } + } + } + assert(!!testcase, 'testcase not found'); + const [rec, result] = log.record(query); + await testcase.run(rec, testQuery, expectations); + + ev.source?.postMessage({ query, result }); + } catch (thrown) { + const ex = thrown instanceof Error ? thrown : new Error(`${thrown}`); + ev.source?.postMessage({ + query, + result: { status: 'fail', timems: 0, logs: [new LogMessageWithStack('INTERNAL', ex)] }, + }); + } + }; +} diff --git a/src/common/runtime/standalone.ts b/src/common/runtime/standalone.ts index fa938c55a276..385de9937e09 100644 --- a/src/common/runtime/standalone.ts +++ b/src/common/runtime/standalone.ts @@ -21,7 +21,7 @@ import { OptionsInfos, camelCaseToSnakeCase, } from './helper/options.js'; -import { TestDedicatedWorker, TestSharedWorker } from './helper/test_worker.js'; +import { TestDedicatedWorker, TestSharedWorker, TestServiceWorker } from './helper/test_worker.js'; const rootQuerySpec = 'webgpu:*'; let promptBeforeReload = false; @@ -66,6 +66,7 @@ setBaseResourcePath('../out/resources'); const dedicatedWorker = options.worker === 'dedicated' ? new TestDedicatedWorker(options) : undefined; const sharedWorker = options.worker === 'shared' ? new TestSharedWorker(options) : undefined; +const serviceWorker = options.worker === 'service' ? new TestServiceWorker(options) : undefined; const autoCloseOnPass = document.getElementById('autoCloseOnPass') as HTMLInputElement; const resultsVis = document.getElementById('resultsVis')!; @@ -182,6 +183,8 @@ function makeCaseHTML(t: TestTreeLeaf): VisualizedSubtree { await dedicatedWorker.run(rec, name); } else if (sharedWorker) { await sharedWorker.run(rec, name); + } else if (serviceWorker) { + await serviceWorker.run(rec, name); } else { await t.run(rec); } @@ -547,7 +550,7 @@ function keyValueToPairs([k, v]: [string, ParamValue]): [string, string][] { */ function prepareParams(params: Record): string { const pairsArrays = Object.entries(params) - .filter(([, v]) => !!v) + .filter(([, v]) => !!v && v !== '0') .map(keyValueToPairs); const pairs = pairsArrays.flat(); return new URLSearchParams(pairs).toString(); diff --git a/src/common/runtime/wpt.ts b/src/common/runtime/wpt.ts index aacd34b13e51..79ed1b5924dd 100644 --- a/src/common/runtime/wpt.ts +++ b/src/common/runtime/wpt.ts @@ -8,8 +8,8 @@ import { parseQuery } from '../internal/query/parseQuery.js'; import { parseExpectationsForTestQuery, relativeQueryString } from '../internal/query/query.js'; import { assert } from '../util/util.js'; -import { optionEnabled, optionString } from './helper/options.js'; -import { TestDedicatedWorker, TestSharedWorker } from './helper/test_worker.js'; +import { optionEnabled, optionWorkerMode } from './helper/options.js'; +import { TestDedicatedWorker, TestServiceWorker, TestSharedWorker } from './helper/test_worker.js'; // testharness.js API (https://web-platform-tests.org/writing-tests/testharness-api.html) declare interface WptTestObject { @@ -31,9 +31,10 @@ setup({ }); void (async () => { - const workerString = optionString('worker'); + const workerString = optionWorkerMode('worker'); const dedicatedWorker = workerString === 'dedicated' ? new TestDedicatedWorker() : undefined; const sharedWorker = workerString === 'shared' ? new TestSharedWorker() : undefined; + const serviceWorker = workerString === 'service' ? new TestServiceWorker() : undefined; globalTestConfig.unrollConstEvalLoops = optionEnabled('unroll_const_eval_loops'); @@ -68,6 +69,8 @@ void (async () => { await dedicatedWorker.run(rec, name, expectations); } else if (sharedWorker) { await sharedWorker.run(rec, name, expectations); + } else if (serviceWorker) { + await serviceWorker.run(rec, name, expectations); } else { await testcase.run(rec, expectations); } diff --git a/src/common/tools/dev_server.ts b/src/common/tools/dev_server.ts index 57cb6a7ea4f6..8e0e3bdbe656 100644 --- a/src/common/tools/dev_server.ts +++ b/src/common/tools/dev_server.ts @@ -144,6 +144,19 @@ app.get('/out/:suite([a-zA-Z0-9_-]+)/listing.js', async (req, res, next) => { } }); +// Serve .worker.js files by generating the necessary wrapper. +app.get('/out/:suite([a-zA-Z0-9_-]+)/webworker/:filepath(*).worker.js', (req, res, next) => { + const { suite, filepath } = req.params; + const result = `\ +import { g } from '/out/${suite}/${filepath}.spec.js'; +import { wrapTestGroupForWorker } from '/out/common/runtime/helper/wrap_for_worker.js'; + +wrapTestGroupForWorker(g); +`; + res.setHeader('Content-Type', 'application/javascript'); + res.send(result); +}); + // Serve all other .js files by fetching the source .ts file and compiling it. app.get('/out/**/*.js', async (req, res, next) => { const jsUrl = path.relative('/out', req.url); diff --git a/src/common/tools/gen_listings_and_webworkers.ts b/src/common/tools/gen_listings_and_webworkers.ts new file mode 100644 index 000000000000..e446936b66cf --- /dev/null +++ b/src/common/tools/gen_listings_and_webworkers.ts @@ -0,0 +1,90 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import * as process from 'process'; + +import { crawl } from './crawl.js'; + +function usage(rc: number): void { + console.error(`Usage: tools/gen_listings_and_webworkers [options] [OUT_DIR] [SUITE_DIRS...] + +For each suite in SUITE_DIRS, generate listings into OUT_DIR/{suite}/listing.js, +and generate Web Worker proxies in OUT_DIR/{suite}/webworker/**/*.worker.js for +every .spec.js file. (Note {suite}/webworker/ is reserved for this purpose.) + +Example: + tools/gen_listings_and_webworkers gen/ src/unittests/ src/webgpu/ + +Options: + --help Print this message and exit. +`); + process.exit(rc); +} + +const argv = process.argv; +if (argv.indexOf('--help') !== -1) { + usage(0); +} + +{ + // Ignore old argument that is now the default + const i = argv.indexOf('--no-validate'); + if (i !== -1) { + argv.splice(i, 1); + } +} + +if (argv.length < 4) { + usage(0); +} + +const myself = 'src/common/tools/gen_listings_and_webworkers.ts'; + +const outDir = argv[2]; + +for (const suiteDir of argv.slice(3)) { + // Run concurrently for each suite (might be a tiny bit more efficient) + void crawl(suiteDir, false).then(listing => { + const suite = path.basename(suiteDir); + + // Write listing.js + const outFile = path.normalize(path.join(outDir, `${suite}/listing.js`)); + fs.mkdirSync(path.join(outDir, suite), { recursive: true }); + fs.writeFileSync( + outFile, + `\ +// AUTO-GENERATED - DO NOT EDIT. See ${myself}. + +export const listing = ${JSON.stringify(listing, undefined, 2)}; +` + ); + + // Write suite/webworker/**/*.worker.js + for (const entry of listing) { + if ('readme' in entry) continue; + + const outFileDir = path.join( + outDir, + suite, + 'webworker', + ...entry.file.slice(0, entry.file.length - 1) + ); + const outFile = path.join(outDir, suite, 'webworker', ...entry.file) + '.worker.js'; + + const relPathToSuiteRoot = Array(entry.file.length).fill('..').join('/'); + + fs.mkdirSync(outFileDir, { recursive: true }); + fs.writeFileSync( + outFile, + `\ +// AUTO-GENERATED - DO NOT EDIT. See ${myself}. + +// g is a TestGroup object (defined in common/internal/test_group.ts). +import { g } from '${relPathToSuiteRoot}/${entry.file.join('/')}.spec.js'; +import { wrapTestGroupForWorker } from '${relPathToSuiteRoot}/../common/runtime/helper/wrap_for_worker.js'; + +wrapTestGroupForWorker(g); +` + ); + } + }); +} diff --git a/src/demo/webworker/.gitignore b/src/demo/webworker/.gitignore new file mode 100644 index 000000000000..8496277ad72e --- /dev/null +++ b/src/demo/webworker/.gitignore @@ -0,0 +1,2 @@ +# DIRECTORY RESERVED FOR GENERATED FILES. See gen_listings_and_webworkers. +* diff --git a/src/manual/webworker/.gitignore b/src/manual/webworker/.gitignore new file mode 100644 index 000000000000..8496277ad72e --- /dev/null +++ b/src/manual/webworker/.gitignore @@ -0,0 +1,2 @@ +# DIRECTORY RESERVED FOR GENERATED FILES. See gen_listings_and_webworkers. +* diff --git a/src/resources/cache/hashes.json b/src/resources/cache/hashes.json index 61bc0ff73192..6a616d571a9e 100644 --- a/src/resources/cache/hashes.json +++ b/src/resources/cache/hashes.json @@ -1,110 +1,110 @@ { - "webgpu/shader/execution/binary/af_addition.bin": "1843098d", - "webgpu/shader/execution/binary/af_logical.bin": "1382526e", - "webgpu/shader/execution/binary/af_division.bin": "e0262a88", - "webgpu/shader/execution/binary/af_matrix_addition.bin": "1e39ddea", - "webgpu/shader/execution/binary/af_matrix_matrix_multiplication.bin": "dd6bc727", - "webgpu/shader/execution/binary/af_matrix_scalar_multiplication.bin": "fb15115", - "webgpu/shader/execution/binary/af_matrix_subtraction.bin": "d7ba7836", - "webgpu/shader/execution/binary/af_matrix_vector_multiplication.bin": "5a23b6cc", - "webgpu/shader/execution/binary/af_multiplication.bin": "e6a5c5e4", - "webgpu/shader/execution/binary/af_remainder.bin": "e063382c", - "webgpu/shader/execution/binary/af_subtraction.bin": "d43eb5af", - "webgpu/shader/execution/binary/ai_arithmetic.bin": "2d6a0f7e", - "webgpu/shader/execution/binary/f16_addition.bin": "3346b4bd", - "webgpu/shader/execution/binary/f16_logical.bin": "b0bfe351", - "webgpu/shader/execution/binary/f16_division.bin": "db83c0cc", - "webgpu/shader/execution/binary/f16_matrix_addition.bin": "882f40bb", - "webgpu/shader/execution/binary/f16_matrix_matrix_multiplication.bin": "cfc4cb6", - "webgpu/shader/execution/binary/f16_matrix_scalar_multiplication.bin": "b2344dc1", - "webgpu/shader/execution/binary/f16_matrix_subtraction.bin": "1822ca", - "webgpu/shader/execution/binary/f16_matrix_vector_multiplication.bin": "f5529ab4", - "webgpu/shader/execution/binary/f16_multiplication.bin": "9ea35453", - "webgpu/shader/execution/binary/f16_remainder.bin": "39fe22c1", - "webgpu/shader/execution/binary/f16_subtraction.bin": "d65e2e11", - "webgpu/shader/execution/binary/f32_addition.bin": "e2576a3b", - "webgpu/shader/execution/binary/f32_logical.bin": "a4e17c69", - "webgpu/shader/execution/binary/f32_division.bin": "24a41b78", - "webgpu/shader/execution/binary/f32_matrix_addition.bin": "4af13f54", - "webgpu/shader/execution/binary/f32_matrix_matrix_multiplication.bin": "ffe9e80b", - "webgpu/shader/execution/binary/f32_matrix_scalar_multiplication.bin": "1eb1789c", - "webgpu/shader/execution/binary/f32_matrix_subtraction.bin": "e2694b78", - "webgpu/shader/execution/binary/f32_matrix_vector_multiplication.bin": "bbf90", - "webgpu/shader/execution/binary/f32_multiplication.bin": "63f63b02", - "webgpu/shader/execution/binary/f32_remainder.bin": "6a44daa2", - "webgpu/shader/execution/binary/f32_subtraction.bin": "a6240f28", - "webgpu/shader/execution/binary/i32_arithmetic.bin": "6fee3e4e", - "webgpu/shader/execution/binary/i32_comparison.bin": "788881cd", - "webgpu/shader/execution/binary/u32_arithmetic.bin": "23da1ed8", - "webgpu/shader/execution/binary/u32_comparison.bin": "8ab2e08c", - "webgpu/shader/execution/abs.bin": "19017bb1", - "webgpu/shader/execution/acos.bin": "9dd5c222", - "webgpu/shader/execution/acosh.bin": "c5b7a2b9", - "webgpu/shader/execution/asin.bin": "998df766", - "webgpu/shader/execution/asinh.bin": "ace06d5a", - "webgpu/shader/execution/atan.bin": "b94c5065", - "webgpu/shader/execution/atan2.bin": "a2c19388", - "webgpu/shader/execution/atanh.bin": "f726651b", - "webgpu/shader/execution/bitcast.bin": "81370da9", - "webgpu/shader/execution/ceil.bin": "f6fda5fa", - "webgpu/shader/execution/clamp.bin": "47a17327", - "webgpu/shader/execution/cos.bin": "6b63dc60", - "webgpu/shader/execution/cosh.bin": "8fe08827", - "webgpu/shader/execution/cross.bin": "2ef763e5", - "webgpu/shader/execution/degrees.bin": "c30f7423", - "webgpu/shader/execution/determinant.bin": "4dedfa96", - "webgpu/shader/execution/distance.bin": "9b71fb94", - "webgpu/shader/execution/dot.bin": "db15b119", - "webgpu/shader/execution/exp.bin": "65c5d3ab", - "webgpu/shader/execution/exp2.bin": "6e7766a1", - "webgpu/shader/execution/faceForward.bin": "282fbba6", - "webgpu/shader/execution/floor.bin": "dce512dd", - "webgpu/shader/execution/fma.bin": "21d0a25e", - "webgpu/shader/execution/fract.bin": "82f96adc", - "webgpu/shader/execution/frexp.bin": "a41c87a4", - "webgpu/shader/execution/inverseSqrt.bin": "ec953eb3", - "webgpu/shader/execution/ldexp.bin": "fcfd6224", - "webgpu/shader/execution/length.bin": "4da1998f", - "webgpu/shader/execution/log.bin": "d99e6690", - "webgpu/shader/execution/log2.bin": "4f7644b3", - "webgpu/shader/execution/max.bin": "f8bc9388", - "webgpu/shader/execution/min.bin": "7b1b016c", - "webgpu/shader/execution/mix.bin": "7b257d9c", - "webgpu/shader/execution/modf.bin": "fa632cd1", - "webgpu/shader/execution/normalize.bin": "ace99215", - "webgpu/shader/execution/pack2x16float.bin": "6ef332cb", - "webgpu/shader/execution/pow.bin": "7c042e04", - "webgpu/shader/execution/quantizeToF16.bin": "7fd41be3", - "webgpu/shader/execution/radians.bin": "3e3aae03", - "webgpu/shader/execution/reflect.bin": "c75fc3e0", - "webgpu/shader/execution/refract.bin": "8455f497", - "webgpu/shader/execution/round.bin": "95773d03", - "webgpu/shader/execution/saturate.bin": "e2d02ac5", - "webgpu/shader/execution/sign.bin": "9c56fda6", - "webgpu/shader/execution/sin.bin": "7256a0d6", - "webgpu/shader/execution/sinh.bin": "593345a9", - "webgpu/shader/execution/smoothstep.bin": "5064d00b", - "webgpu/shader/execution/sqrt.bin": "601a4fbc", - "webgpu/shader/execution/step.bin": "5596f86a", - "webgpu/shader/execution/tan.bin": "ba7975c1", - "webgpu/shader/execution/tanh.bin": "cac48441", - "webgpu/shader/execution/transpose.bin": "e5d5b2a9", - "webgpu/shader/execution/trunc.bin": "95811ca", - "webgpu/shader/execution/unpack2x16float.bin": "9995d9a7", - "webgpu/shader/execution/unpack2x16snorm.bin": "a4c1d0b4", - "webgpu/shader/execution/unpack2x16unorm.bin": "7b130e1f", - "webgpu/shader/execution/unpack4x8snorm.bin": "9879686e", - "webgpu/shader/execution/unpack4x8unorm.bin": "727028f2", - "webgpu/shader/execution/unary/af_arithmetic.bin": "4894a2dc", - "webgpu/shader/execution/unary/af_assignment.bin": "b4c538d5", - "webgpu/shader/execution/unary/ai_arithmetic.bin": "3272cb52", - "webgpu/shader/execution/unary/ai_assignment.bin": "c2877676", - "webgpu/shader/execution/unary/bool_conversion.bin": "97ef95b3", - "webgpu/shader/execution/unary/f16_arithmetic.bin": "86b56801", - "webgpu/shader/execution/unary/f16_conversion.bin": "5cf66fac", - "webgpu/shader/execution/unary/f32_arithmetic.bin": "c7b8416", - "webgpu/shader/execution/unary/f32_conversion.bin": "b0af00cd", - "webgpu/shader/execution/unary/i32_arithmetic.bin": "b2d016ce", - "webgpu/shader/execution/unary/i32_conversion.bin": "ca9cd82d", - "webgpu/shader/execution/unary/u32_conversion.bin": "40797b79" + "webgpu/shader/execution/binary/af_addition.bin": "24160909", + "webgpu/shader/execution/binary/af_logical.bin": "ffb5a83f", + "webgpu/shader/execution/binary/af_division.bin": "c230ac78", + "webgpu/shader/execution/binary/af_matrix_addition.bin": "9079a042", + "webgpu/shader/execution/binary/af_matrix_subtraction.bin": "6b55102f", + "webgpu/shader/execution/binary/af_multiplication.bin": "4fc3b0d6", + "webgpu/shader/execution/binary/af_remainder.bin": "366caec6", + "webgpu/shader/execution/binary/af_subtraction.bin": "49a16db4", + "webgpu/shader/execution/binary/f16_addition.bin": "3fb1ee09", + "webgpu/shader/execution/binary/f16_logical.bin": "65cdc6f", + "webgpu/shader/execution/binary/f16_division.bin": "1b5bd44a", + "webgpu/shader/execution/binary/f16_matrix_addition.bin": "fdea291a", + "webgpu/shader/execution/binary/f16_matrix_matrix_multiplication.bin": "e727482e", + "webgpu/shader/execution/binary/f16_matrix_scalar_multiplication.bin": "24d70bdd", + "webgpu/shader/execution/binary/f16_matrix_subtraction.bin": "7acd3c3b", + "webgpu/shader/execution/binary/f16_matrix_vector_multiplication.bin": "9e01e0cf", + "webgpu/shader/execution/binary/f16_multiplication.bin": "c24b705c", + "webgpu/shader/execution/binary/f16_remainder.bin": "2764c7e1", + "webgpu/shader/execution/binary/f16_subtraction.bin": "d4014a38", + "webgpu/shader/execution/binary/f32_addition.bin": "b6707259", + "webgpu/shader/execution/binary/f32_logical.bin": "d40c1c0", + "webgpu/shader/execution/binary/f32_division.bin": "e19e30a6", + "webgpu/shader/execution/binary/f32_matrix_addition.bin": "6a13d6d6", + "webgpu/shader/execution/binary/f32_matrix_matrix_multiplication.bin": "4c5cb0a2", + "webgpu/shader/execution/binary/f32_matrix_scalar_multiplication.bin": "6b00d17f", + "webgpu/shader/execution/binary/f32_matrix_subtraction.bin": "319d3ae1", + "webgpu/shader/execution/binary/f32_matrix_vector_multiplication.bin": "1c4893ca", + "webgpu/shader/execution/binary/f32_multiplication.bin": "f7dbbc8", + "webgpu/shader/execution/binary/f32_remainder.bin": "fb5dd3fe", + "webgpu/shader/execution/binary/f32_subtraction.bin": "aeaca568", + "webgpu/shader/execution/binary/i32_arithmetic.bin": "90a3514a", + "webgpu/shader/execution/binary/i32_comparison.bin": "840b09e6", + "webgpu/shader/execution/binary/u32_arithmetic.bin": "e3f04e97", + "webgpu/shader/execution/binary/u32_comparison.bin": "dc1398d3", + "webgpu/shader/execution/abs.bin": "2b663377", + "webgpu/shader/execution/acos.bin": "a888c67f", + "webgpu/shader/execution/acosh.bin": "5383658b", + "webgpu/shader/execution/asin.bin": "a580a322", + "webgpu/shader/execution/asinh.bin": "31388535", + "webgpu/shader/execution/atan.bin": "c6f4c771", + "webgpu/shader/execution/atan2.bin": "3b9a37a1", + "webgpu/shader/execution/atanh.bin": "7295a313", + "webgpu/shader/execution/bitcast.bin": "73e0bea6", + "webgpu/shader/execution/ceil.bin": "24bd6be9", + "webgpu/shader/execution/clamp.bin": "8ed55492", + "webgpu/shader/execution/cos.bin": "4d36fa0", + "webgpu/shader/execution/cosh.bin": "a7da3a3", + "webgpu/shader/execution/cross.bin": "6ce2660b", + "webgpu/shader/execution/degrees.bin": "53a0849", + "webgpu/shader/execution/determinant.bin": "873e78af", + "webgpu/shader/execution/distance.bin": "bfce09a0", + "webgpu/shader/execution/dot.bin": "566b6e55", + "webgpu/shader/execution/exp.bin": "d8142d49", + "webgpu/shader/execution/exp2.bin": "52a403d1", + "webgpu/shader/execution/faceForward.bin": "f90dacbe", + "webgpu/shader/execution/floor.bin": "c7465b11", + "webgpu/shader/execution/fma.bin": "db3497d4", + "webgpu/shader/execution/fract.bin": "e65c5bd1", + "webgpu/shader/execution/frexp.bin": "5ce112f4", + "webgpu/shader/execution/inverseSqrt.bin": "84ea0a57", + "webgpu/shader/execution/ldexp.bin": "9d11f120", + "webgpu/shader/execution/length.bin": "dd759736", + "webgpu/shader/execution/log.bin": "5f77a59d", + "webgpu/shader/execution/log2.bin": "57fff45e", + "webgpu/shader/execution/max.bin": "c7cdd54f", + "webgpu/shader/execution/min.bin": "422be325", + "webgpu/shader/execution/mix.bin": "957e7d92", + "webgpu/shader/execution/modf.bin": "946d1f4f", + "webgpu/shader/execution/normalize.bin": "2ac02e80", + "webgpu/shader/execution/pack2x16float.bin": "d7ef3cf5", + "webgpu/shader/execution/pow.bin": "cd492166", + "webgpu/shader/execution/quantizeToF16.bin": "58bac06c", + "webgpu/shader/execution/radians.bin": "6ac08f50", + "webgpu/shader/execution/reflect.bin": "3c260554", + "webgpu/shader/execution/refract.bin": "7e952d7c", + "webgpu/shader/execution/round.bin": "f6b9bda1", + "webgpu/shader/execution/saturate.bin": "1c22f301", + "webgpu/shader/execution/sign.bin": "3ce55105", + "webgpu/shader/execution/sin.bin": "d48e7f2a", + "webgpu/shader/execution/sinh.bin": "f227c1d1", + "webgpu/shader/execution/smoothstep.bin": "6bdb4309", + "webgpu/shader/execution/sqrt.bin": "cd576d27", + "webgpu/shader/execution/step.bin": "dd584686", + "webgpu/shader/execution/tan.bin": "5ae50f61", + "webgpu/shader/execution/tanh.bin": "fe7a619d", + "webgpu/shader/execution/transpose.bin": "469edd7e", + "webgpu/shader/execution/trunc.bin": "8d3a05de", + "webgpu/shader/execution/unpack2x16float.bin": "e897c5ac", + "webgpu/shader/execution/unpack2x16snorm.bin": "450d5402", + "webgpu/shader/execution/unpack2x16unorm.bin": "306b3bf9", + "webgpu/shader/execution/unpack4x8snorm.bin": "fc1bd4c3", + "webgpu/shader/execution/unpack4x8unorm.bin": "763288cc", + "webgpu/shader/execution/unary/af_arithmetic.bin": "a39d4121", + "webgpu/shader/execution/unary/af_assignment.bin": "6ed540e8", + "webgpu/shader/execution/unary/bool_conversion.bin": "f37ea003", + "webgpu/shader/execution/unary/f16_arithmetic.bin": "9cadc739", + "webgpu/shader/execution/unary/f16_conversion.bin": "49c7b38e", + "webgpu/shader/execution/unary/f32_arithmetic.bin": "28da577a", + "webgpu/shader/execution/unary/f32_conversion.bin": "fcdfdd08", + "webgpu/shader/execution/unary/i32_arithmetic.bin": "25cf27d1", + "webgpu/shader/execution/unary/i32_conversion.bin": "276dcf69", + "webgpu/shader/execution/unary/u32_conversion.bin": "acac2172", + "webgpu/shader/execution/unary/ai_assignment.bin": "c876d431", + "webgpu/shader/execution/binary/ai_arithmetic.bin": "36a1d65b", + "webgpu/shader/execution/unary/ai_arithmetic.bin": "89e34dcf", + "webgpu/shader/execution/binary/af_matrix_matrix_multiplication.bin": "3fd8797b", + "webgpu/shader/execution/binary/af_matrix_scalar_multiplication.bin": "bf99158a", + "webgpu/shader/execution/binary/af_matrix_vector_multiplication.bin": "8bcc7c30" } \ No newline at end of file diff --git a/src/resources/cache/webgpu/shader/execution/binary/af_matrix_addition.bin b/src/resources/cache/webgpu/shader/execution/binary/af_matrix_addition.bin index d387abcd7f20..ba9d123cbf41 100644 Binary files a/src/resources/cache/webgpu/shader/execution/binary/af_matrix_addition.bin and b/src/resources/cache/webgpu/shader/execution/binary/af_matrix_addition.bin differ diff --git a/src/resources/cache/webgpu/shader/execution/binary/af_matrix_matrix_multiplication.bin b/src/resources/cache/webgpu/shader/execution/binary/af_matrix_matrix_multiplication.bin index 5f8636b77c7d..b710ae908402 100644 Binary files a/src/resources/cache/webgpu/shader/execution/binary/af_matrix_matrix_multiplication.bin and b/src/resources/cache/webgpu/shader/execution/binary/af_matrix_matrix_multiplication.bin differ diff --git a/src/resources/cache/webgpu/shader/execution/binary/af_matrix_scalar_multiplication.bin b/src/resources/cache/webgpu/shader/execution/binary/af_matrix_scalar_multiplication.bin index a8d35f964d4e..c8a3b7205aaa 100644 Binary files a/src/resources/cache/webgpu/shader/execution/binary/af_matrix_scalar_multiplication.bin and b/src/resources/cache/webgpu/shader/execution/binary/af_matrix_scalar_multiplication.bin differ diff --git a/src/resources/cache/webgpu/shader/execution/binary/af_matrix_subtraction.bin b/src/resources/cache/webgpu/shader/execution/binary/af_matrix_subtraction.bin index 4a1449182109..8f88d196cebe 100644 Binary files a/src/resources/cache/webgpu/shader/execution/binary/af_matrix_subtraction.bin and b/src/resources/cache/webgpu/shader/execution/binary/af_matrix_subtraction.bin differ diff --git a/src/resources/cache/webgpu/shader/execution/binary/af_matrix_vector_multiplication.bin b/src/resources/cache/webgpu/shader/execution/binary/af_matrix_vector_multiplication.bin index 0a61c01c1a46..e57f91ffd980 100644 Binary files a/src/resources/cache/webgpu/shader/execution/binary/af_matrix_vector_multiplication.bin and b/src/resources/cache/webgpu/shader/execution/binary/af_matrix_vector_multiplication.bin differ diff --git a/src/resources/cache/webgpu/shader/execution/bitcast.bin b/src/resources/cache/webgpu/shader/execution/bitcast.bin index 3c24c88e1ffb..d3954903ac89 100644 Binary files a/src/resources/cache/webgpu/shader/execution/bitcast.bin and b/src/resources/cache/webgpu/shader/execution/bitcast.bin differ diff --git a/src/resources/cache/webgpu/shader/execution/ceil.bin b/src/resources/cache/webgpu/shader/execution/ceil.bin index 5ec60b6e150d..7ff8dea27eee 100644 Binary files a/src/resources/cache/webgpu/shader/execution/ceil.bin and b/src/resources/cache/webgpu/shader/execution/ceil.bin differ diff --git a/src/resources/cache/webgpu/shader/execution/determinant.bin b/src/resources/cache/webgpu/shader/execution/determinant.bin index cef09cd67bd1..d09c7df7e8aa 100644 Binary files a/src/resources/cache/webgpu/shader/execution/determinant.bin and b/src/resources/cache/webgpu/shader/execution/determinant.bin differ diff --git a/src/stress/webworker/.gitignore b/src/stress/webworker/.gitignore new file mode 100644 index 000000000000..8496277ad72e --- /dev/null +++ b/src/stress/webworker/.gitignore @@ -0,0 +1,2 @@ +# DIRECTORY RESERVED FOR GENERATED FILES. See gen_listings_and_webworkers. +* diff --git a/src/unittests/conversion.spec.ts b/src/unittests/conversion.spec.ts index 8606aa871794..e144f39288a2 100644 --- a/src/unittests/conversion.spec.ts +++ b/src/unittests/conversion.spec.ts @@ -18,7 +18,7 @@ import { i32, kFloat16Format, kFloat32Format, - Matrix, + MatrixValue, numbersApproximatelyEqual, pack2x16float, pack2x16snorm, @@ -26,14 +26,14 @@ import { pack4x8snorm, pack4x8unorm, packRGB9E5UFloat, - Scalar, + ScalarValue, toMatrix, u32, unpackRGB9E5UFloat, vec2, vec3, vec4, - Vector, + VectorValue, } from '../webgpu/util/conversion.js'; import { UnitTest } from './unit_test.js'; @@ -191,7 +191,7 @@ g.test('floatBitsToULPFromZero,32').fn(t => { }); g.test('scalarWGSL').fn(t => { - const cases: Array<[Scalar, string]> = [ + const cases: Array<[ScalarValue, string]> = [ [f32(0.0), '0.0f'], // The number -0.0 can be remapped to 0.0 when stored in a Scalar // object. It is not possible to guarantee that '-0.0f' will @@ -227,7 +227,7 @@ expect: ${expect}` }); g.test('vectorWGSL').fn(t => { - const cases: Array<[Vector, string]> = [ + const cases: Array<[VectorValue, string]> = [ [vec2(f32(42.0), f32(24.0)), 'vec2(42.0f, 24.0f)'], [vec2(f16Bits(0x5140), f16Bits(0x4e00)), 'vec2(42.0h, 24.0h)'], [vec2(u32(42), u32(24)), 'vec2(42u, 24u)'], @@ -261,7 +261,7 @@ expect: ${expect}` }); g.test('matrixWGSL').fn(t => { - const cases: Array<[Matrix, string]> = [ + const cases: Array<[MatrixValue, string]> = [ [ toMatrix( [ @@ -391,7 +391,7 @@ g.test('constructorMatrix') return [...Array(rows).keys()].map(r => scalar_builder(c * cols + r)); }); - const got = new Matrix(elements); + const got = new MatrixValue(elements); const got_type = got.type; t.expect( got_type.cols === cols, diff --git a/src/unittests/floating_point.spec.ts b/src/unittests/floating_point.spec.ts index ad27c1d711d8..0c5c32ecd2e3 100644 --- a/src/unittests/floating_point.spec.ts +++ b/src/unittests/floating_point.spec.ts @@ -1861,6 +1861,7 @@ g.test('absoluteErrorInterval') const smallErr = kSmallAbsoluteErrorValue[p.trait]; const largeErr = kLargeAbsoluteErrorValue[p.trait]; const subnormalErr = kSubnormalAbsoluteErrorValue[p.trait]; + // prettier-ignore return [ // Edge Cases @@ -1903,6 +1904,19 @@ g.test('absoluteErrorInterval') { value: constants.negative.subnormal.max, error: smallErr, expected: [constants.negative.subnormal.max - smallErr, smallErr] }, { value: constants.negative.subnormal.max, error: 1, expected: [constants.negative.subnormal.max - 1, 1] }, + // Zero + { value: 0, error: 0, expected: 0 }, + { value: 0, error: smallErr, expected: [-smallErr, smallErr] }, + { value: 0, error: 1, expected: [-1, 1] }, + + // Two + { value: 2, error: 0, expected: 2 }, + { value: 2, error: smallErr, expected: [2 - smallErr, 2 + smallErr] }, + { value: 2, error: 1, expected: [1, 3] }, + { value: -2, error: 0, expected: -2 }, + { value: -2, error: smallErr, expected: [-2 - smallErr, -2 + smallErr] }, + { value: -2, error: 1, expected: [-3, -1] }, + // 64-bit subnormals, expected to be treated as 0.0 or smallest subnormal of kind. { value: reinterpretU64AsF64(0x0000_0000_0000_0001n), error: 0, expected: [0, constants.positive.subnormal.min] }, { value: reinterpretU64AsF64(0x0000_0000_0000_0001n), error: subnormalErr, expected: [-subnormalErr, constants.positive.subnormal.min + subnormalErr] }, @@ -1917,19 +1931,6 @@ g.test('absoluteErrorInterval') { value: reinterpretU64AsF64(0x800f_ffff_ffff_fffen), error: 0, expected: [constants.negative.subnormal.max, 0] }, { value: reinterpretU64AsF64(0x800f_ffff_ffff_fffen), error: subnormalErr, expected: [constants.negative.subnormal.max - subnormalErr, subnormalErr] }, { value: reinterpretU64AsF64(0x800f_ffff_ffff_fffen), error: 1, expected: [constants.negative.subnormal.max - 1, 1] }, - - // Zero - { value: 0, error: 0, expected: 0 }, - { value: 0, error: smallErr, expected: [-smallErr, smallErr] }, - { value: 0, error: 1, expected: [-1, 1] }, - - // Two - { value: 2, error: 0, expected: 2 }, - { value: 2, error: smallErr, expected: [2 - smallErr, 2 + smallErr] }, - { value: 2, error: 1, expected: [1, 3] }, - { value: -2, error: 0, expected: -2 }, - { value: -2, error: smallErr, expected: [-2 - smallErr, -2 + smallErr] }, - { value: -2, error: 1, expected: [-3, -1] }, ]; }) ) @@ -2091,7 +2092,7 @@ const kULPErrorValue = { g.test('ulpInterval') .params(u => u - .combine('trait', ['abstract', 'f32', 'f16'] as const) + .combine('trait', ['f32', 'f16'] as const) .beginSubcases() .expandWithParams(p => { const trait = kFPTraitForULP[p.trait]; @@ -2657,12 +2658,17 @@ const kCeilIntervalCases = { { input: -(2 ** 14), expected: -(2 ** 14) }, { input: 0x8000, expected: 0x8000 }, // https://github.com/gpuweb/cts/issues/2766 ], + abstract: [ + { input: 2 ** 52, expected: 2 ** 52 }, + { input: -(2 ** 52), expected: -(2 ** 52) }, + { input: 0x8000000000000000, expected: 0x8000000000000000 }, // https://github.com/gpuweb/cts/issues/2766 + ], } as const; g.test('ceilInterval') .params(u => u - .combine('trait', ['f32', 'f16'] as const) + .combine('trait', ['f32', 'f16', 'abstract'] as const) .beginSubcases() .expandWithParams(p => { const constants = FP[p.trait].constants(); @@ -2689,7 +2695,7 @@ g.test('ceilInterval') { input: constants.negative.max, expected: 0 }, ...kCeilIntervalCases[p.trait], - // 32-bit subnormals + // Subnormals { input: constants.positive.subnormal.max, expected: [0, 1] }, { input: constants.positive.subnormal.min, expected: [0, 1] }, { input: constants.negative.subnormal.min, expected: 0 }, @@ -6488,7 +6494,7 @@ interface MatrixToScalarCase { g.test('determinantInterval') .params(u => u - .combine('trait', ['f32', 'f16'] as const) + .combine('trait', ['f32', 'f16', 'abstract'] as const) .beginSubcases() .combineWithParams([ // Extreme values, i.e. subnormals, very large magnitudes, and those lead to diff --git a/src/unittests/webworker/.gitignore b/src/unittests/webworker/.gitignore new file mode 100644 index 000000000000..8496277ad72e --- /dev/null +++ b/src/unittests/webworker/.gitignore @@ -0,0 +1,2 @@ +# DIRECTORY RESERVED FOR GENERATED FILES. See gen_listings_and_webworkers. +* diff --git a/src/webgpu/api/operation/command_buffer/image_copy.spec.ts b/src/webgpu/api/operation/command_buffer/image_copy.spec.ts index 9927bfb89872..cff2bd50d575 100644 --- a/src/webgpu/api/operation/command_buffer/image_copy.spec.ts +++ b/src/webgpu/api/operation/command_buffer/image_copy.spec.ts @@ -1595,7 +1595,7 @@ works for every format with 2d and 2d-array textures. }; let textureHeight = 4 * info.blockHeight; let rowsPerImage = rowsPerImageEqualsCopyHeight ? copyHeight : copyHeight + 1; - const bytesPerRow = align(copyWidth * info.bytesPerBlock, 256); + const bytesPerRow = align(copyWidth * info.color.bytes, 256); if (dimension === '1d') { copySize.height = 1; diff --git a/src/webgpu/api/operation/render_pipeline/sample_mask.spec.ts b/src/webgpu/api/operation/render_pipeline/sample_mask.spec.ts index ca4a2479658e..b28e1b381cad 100644 --- a/src/webgpu/api/operation/render_pipeline/sample_mask.spec.ts +++ b/src/webgpu/api/operation/render_pipeline/sample_mask.spec.ts @@ -21,7 +21,7 @@ import { makeTestGroup } from '../../../../common/framework/test_group.js'; import { assert, range } from '../../../../common/util/util.js'; import { GPUTest, TextureTestMixin } from '../../../gpu_test.js'; import { checkElementsPassPredicate, checkElementsEqual } from '../../../util/check_contents.js'; -import { TypeF32, TypeU32 } from '../../../util/conversion.js'; +import { Type } from '../../../util/conversion.js'; import { TexelView } from '../../../util/texture/texel_view.js'; const kColors = [ @@ -438,7 +438,7 @@ class F extends TextureTestMixin(GPUTest) { fragmentShaderOutputMask: number ) { const buffer = this.copy2DTextureToBufferUsingComputePass( - TypeF32, // correspond to 'rgba8unorm' format + Type.f32, // correspond to 'rgba8unorm' format 4, texture.createView(), sampleCount @@ -464,7 +464,7 @@ class F extends TextureTestMixin(GPUTest) { const buffer = this.copy2DTextureToBufferUsingComputePass( // Use f32 as the scalar type for depth (depth24plus, depth32float) // Use u32 as the scalar type for stencil (stencil8) - aspect === 'depth-only' ? TypeF32 : TypeU32, + aspect === 'depth-only' ? Type.f32 : Type.u32, 1, depthStencilTexture.createView({ aspect }), sampleCount @@ -705,7 +705,7 @@ color' <= color. ); const colorBuffer = t.copy2DTextureToBufferUsingComputePass( - TypeF32, // correspond to 'rgba8unorm' format + Type.f32, // correspond to 'rgba8unorm' format 4, color.createView(), sampleCount @@ -717,7 +717,7 @@ color' <= color. colorResultPromises.push(colorResult); const depthBuffer = t.copy2DTextureToBufferUsingComputePass( - TypeF32, // correspond to 'depth24plus-stencil8' format + Type.f32, // correspond to 'depth24plus-stencil8' format 1, depthStencil.createView({ aspect: 'depth-only' }), sampleCount @@ -729,7 +729,7 @@ color' <= color. depthResultPromises.push(depthResult); const stencilBuffer = t.copy2DTextureToBufferUsingComputePass( - TypeU32, // correspond to 'depth24plus-stencil8' format + Type.u32, // correspond to 'depth24plus-stencil8' format 1, depthStencil.createView({ aspect: 'stencil-only' }), sampleCount diff --git a/src/webgpu/api/operation/rendering/depth_clip_clamp.spec.ts b/src/webgpu/api/operation/rendering/depth_clip_clamp.spec.ts index 65e2e8af1f21..5e8357114107 100644 --- a/src/webgpu/api/operation/rendering/depth_clip_clamp.spec.ts +++ b/src/webgpu/api/operation/rendering/depth_clip_clamp.spec.ts @@ -4,6 +4,7 @@ depth ranges as well. `; import { makeTestGroup } from '../../../../common/framework/test_group.js'; +import { assert } from '../../../../common/util/util.js'; import { kDepthStencilFormats, kTextureFormatInfo } from '../../../format_info.js'; import { GPUTest } from '../../../gpu_test.js'; import { @@ -52,6 +53,7 @@ have unexpected values then get drawn to the color buffer, which is later checke .fn(async t => { const { format, unclippedDepth, writeDepth, multisampled } = t.params; const info = kTextureFormatInfo[format]; + assert(!!info.depth); /** Number of depth values to test for both vertex output and frag_depth output. */ const kNumDepthValues = 8; @@ -222,16 +224,16 @@ have unexpected values then get drawn to the color buffer, which is later checke : undefined; const dsActual = - !multisampled && info.bytesPerBlock + !multisampled && info.depth.bytes ? t.device.createBuffer({ - size: kNumTestPoints * info.bytesPerBlock, + size: kNumTestPoints * info.depth.bytes, usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ, }) : undefined; const dsExpected = - !multisampled && info.bytesPerBlock + !multisampled && info.depth.bytes ? t.device.createBuffer({ - size: kNumTestPoints * info.bytesPerBlock, + size: kNumTestPoints * info.depth.bytes, usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ, }) : undefined; diff --git a/src/webgpu/api/operation/rendering/draw.spec.ts b/src/webgpu/api/operation/rendering/draw.spec.ts index 6ed4be08fd24..fc8fdf2224d1 100644 --- a/src/webgpu/api/operation/rendering/draw.spec.ts +++ b/src/webgpu/api/operation/rendering/draw.spec.ts @@ -11,10 +11,10 @@ import { TypedArrayBufferView, TypedArrayBufferViewConstructor, } from '../../../../common/util/util.js'; -import { GPUTest, TextureTestMixin } from '../../../gpu_test.js'; +import { AdapterLimitsGPUTest, TextureTestMixin } from '../../../gpu_test.js'; import { PerPixelComparison } from '../../../util/texture/texture_ok.js'; -class DrawTest extends TextureTestMixin(GPUTest) { +class DrawTest extends TextureTestMixin(AdapterLimitsGPUTest) { checkTriangleDraw(opts: { firstIndex: number | undefined; count: number; diff --git a/src/webgpu/api/operation/resource_init/check_texture/texture_zero_init_test.ts b/src/webgpu/api/operation/resource_init/check_texture/texture_zero_init_test.ts index 22ffe0a3e518..6ff3ab4c9b41 100644 --- a/src/webgpu/api/operation/resource_init/check_texture/texture_zero_init_test.ts +++ b/src/webgpu/api/operation/resource_init/check_texture/texture_zero_init_test.ts @@ -115,6 +115,14 @@ const initializedStateAsStencil = { [InitializedState.Canary]: 42, }; +function allAspectsCopyDst(info: (typeof kTextureFormatInfo)[UncompressedTextureFormat]) { + return ( + (!info.color || info.color.copyDst) && + (!info.depth || info.depth.copyDst) && + (!info.stencil || info.stencil.copyDst) + ); +} + export function getRequiredTextureUsage( format: UncompressedTextureFormat, sampleCount: number, @@ -159,10 +167,11 @@ export function getRequiredTextureUsage( usage |= GPUConst.TextureUsage.RENDER_ATTACHMENT; } - if (!kTextureFormatInfo[format].copyDst) { + const info = kTextureFormatInfo[format]; + if (!allAspectsCopyDst(info)) { // Copies are not possible. We need OutputAttachment to initialize // canary data. - assert(kTextureFormatInfo[format].renderable); + if (info.color) assert(!!info.colorRender, 'not implemented for non-renderable color'); usage |= GPUConst.TextureUsage.RENDER_ATTACHMENT; } @@ -388,10 +397,11 @@ export class TextureZeroInitTest extends GPUTest { state: InitializedState, subresourceRange: SubresourceRange ): void { - if (this.p.sampleCount > 1 || !kTextureFormatInfo[this.p.format].copyDst) { + const info = kTextureFormatInfo[this.p.format]; + if (this.p.sampleCount > 1 || !allAspectsCopyDst(info)) { // Copies to multisampled textures not yet specified. // Use a storeOp for now. - assert(kTextureFormatInfo[this.p.format].renderable); + if (info.color) assert(!!info.colorRender, 'not implemented for non-renderable color'); this.initializeWithStoreOp(state, texture, subresourceRange); } else { this.initializeWithCopy(texture, state, subresourceRange); @@ -517,20 +527,15 @@ export const kTestParams = kUnitCaseParamsBuilder const info = kTextureFormatInfo[format]; return ( - ((usage & GPUConst.TextureUsage.RENDER_ATTACHMENT) !== 0 && !info.renderable) || + ((usage & GPUConst.TextureUsage.RENDER_ATTACHMENT) !== 0 && + info.color && + !info.colorRender) || ((usage & GPUConst.TextureUsage.STORAGE_BINDING) !== 0 && !info.color?.storage) || (sampleCount > 1 && !info.multisample) ); }) .combine('nonPowerOfTwo', [false, true]) - .combine('canaryOnCreation', [false, true]) - .filter(({ canaryOnCreation, format }) => { - // We can only initialize the texture if it's encodable or renderable. - const canInitialize = format in kTextureFormatInfo || kTextureFormatInfo[format].renderable; - - // Filter out cases where we want canary values but can't initialize. - return !canaryOnCreation || canInitialize; - }); + .combine('canaryOnCreation', [false, true]); type TextureZeroParams = ParamTypeOf; diff --git a/src/webgpu/api/operation/storage_texture/read_only.spec.ts b/src/webgpu/api/operation/storage_texture/read_only.spec.ts index 9a479eee9d15..978924aabd67 100644 --- a/src/webgpu/api/operation/storage_texture/read_only.spec.ts +++ b/src/webgpu/api/operation/storage_texture/read_only.spec.ts @@ -51,7 +51,7 @@ class F extends GPUTest { storageTexture: GPUTexture, format: ColorTextureFormat ): ArrayBuffer { - const bytesPerBlock = kTextureFormatInfo[format].bytesPerBlock; + const bytesPerBlock = kTextureFormatInfo[format].color.bytes; assert(bytesPerBlock !== undefined); const width = storageTexture.width; diff --git a/src/webgpu/api/validation/createTexture.spec.ts b/src/webgpu/api/validation/createTexture.spec.ts index 04c029d78f1d..fc1c8b86b26b 100644 --- a/src/webgpu/api/validation/createTexture.spec.ts +++ b/src/webgpu/api/validation/createTexture.spec.ts @@ -299,7 +299,7 @@ g.test('sampleCount,various_sampleCount_with_all_formats') usage, }; - const success = sampleCount === 1 || (sampleCount === 4 && info.multisample && info.renderable); + const success = sampleCount === 1 || (sampleCount === 4 && info.multisample); t.expectValidationError(() => { t.device.createTexture(descriptor); @@ -1066,16 +1066,13 @@ g.test('texture_usage') // Note that we unconditionally test copy usages for all formats. We don't check copySrc/copyDst in kTextureFormatInfo in capability_info.js // if (!info.copySrc && (usage & GPUTextureUsage.COPY_SRC) !== 0) success = false; // if (!info.copyDst && (usage & GPUTextureUsage.COPY_DST) !== 0) success = false; - if ( - (usage & GPUTextureUsage.STORAGE_BINDING) !== 0 && - !isTextureFormatUsableAsStorageFormat(format, t.isCompatibility) - ) - success = false; - if ( - (!info.renderable || (appliedDimension !== '2d' && appliedDimension !== '3d')) && - (usage & GPUTextureUsage.RENDER_ATTACHMENT) !== 0 - ) - success = false; + if (usage & GPUTextureUsage.STORAGE_BINDING) { + if (!isTextureFormatUsableAsStorageFormat(format, t.isCompatibility)) success = false; + } + if (usage & GPUTextureUsage.RENDER_ATTACHMENT) { + if (appliedDimension === '1d') success = false; + if (info.color && !info.colorRender) success = false; + } t.expectValidationError(() => { t.device.createTexture(descriptor); diff --git a/src/webgpu/api/validation/image_copy/texture_related.spec.ts b/src/webgpu/api/validation/image_copy/texture_related.spec.ts index a0fe38e8e313..cbc36b1431ba 100644 --- a/src/webgpu/api/validation/image_copy/texture_related.spec.ts +++ b/src/webgpu/api/validation/image_copy/texture_related.spec.ts @@ -440,7 +440,7 @@ Test that the copy size must be aligned to the texture's format's block size. const texture = t.createAlignedTexture(format, size, origin, dimension); const bytesPerRow = align( - Math.max(1, Math.ceil(size.width / info.blockWidth)) * info.bytesPerBlock, + Math.max(1, Math.ceil(size.width / info.blockWidth)) * info.color.bytes, 256 ); const rowsPerImage = Math.ceil(size.height / info.blockHeight); diff --git a/src/webgpu/compat/api/validation/encoding/cmds/copyTextureToBuffer.spec.ts b/src/webgpu/compat/api/validation/encoding/cmds/copyTextureToBuffer.spec.ts index a9af7795b3c4..e7d5164c4539 100644 --- a/src/webgpu/compat/api/validation/encoding/cmds/copyTextureToBuffer.spec.ts +++ b/src/webgpu/compat/api/validation/encoding/cmds/copyTextureToBuffer.spec.ts @@ -19,16 +19,17 @@ g.test('compressed') .fn(t => { const { format } = t.params; - const { blockWidth, blockHeight, bytesPerBlock } = kTextureFormatInfo[format]; + const info = kTextureFormatInfo[format]; + const textureSize = [info.blockWidth, info.blockHeight, 1]; const texture = t.device.createTexture({ - size: [blockWidth, blockHeight, 1], + size: textureSize, format, usage: GPUTextureUsage.COPY_SRC, }); t.trackForCleanup(texture); - const bytesPerRow = align(bytesPerBlock, 256); + const bytesPerRow = align(info.color.bytes, 256); const buffer = t.device.createBuffer({ size: bytesPerRow, @@ -37,7 +38,7 @@ g.test('compressed') t.trackForCleanup(buffer); const encoder = t.device.createCommandEncoder(); - encoder.copyTextureToBuffer({ texture }, { buffer, bytesPerRow }, [blockWidth, blockHeight, 1]); + encoder.copyTextureToBuffer({ texture }, { buffer, bytesPerRow }, textureSize); t.expectGPUError('validation', () => { encoder.finish(); }); diff --git a/src/webgpu/format_info.ts b/src/webgpu/format_info.ts index 8ed39cdf3d22..be1320d3cdad 100644 --- a/src/webgpu/format_info.ts +++ b/src/webgpu/format_info.ts @@ -31,16 +31,8 @@ const kFormatUniversalDefaults = { /** The base format for srgb formats. Specified on both srgb and equivalent non-srgb formats. */ baseFormat: undefined, - /** @deprecated */ - copyDst: undefined, /** @deprecated Use `.color.bytes`, `.depth.bytes`, or `.stencil.bytes`. */ bytesPerBlock: undefined, - /** @deprecated */ - renderable: false, - /** @deprecated */ - renderTargetPixelByteCost: undefined, - /** @deprecated */ - renderTargetComponentAlignment: undefined, // IMPORTANT: // Add new top-level keys both here and in TextureFormatInfo_TypeCheck. @@ -76,7 +68,7 @@ function formatTableWithDefaults kColorTextureFormatInfo[v].colorRender ); -assert( - kRenderableColorTextureFormats.every( - f => - kAllTextureFormatInfo[f].renderTargetComponentAlignment !== undefined && - kAllTextureFormatInfo[f].renderTargetPixelByteCost !== undefined - ) -); /** Per-GPUTextureFormat-per-aspect info. */ interface TextureFormatAspectInfo { @@ -1608,11 +1483,7 @@ type TextureFormatInfo_TypeCheck = { baseFormat: GPUTextureFormat | undefined; feature: GPUFeatureName | undefined; - copyDst: boolean; bytesPerBlock: number | undefined; - renderable: boolean; - renderTargetPixelByteCost: number | undefined; - renderTargetComponentAlignment: number | undefined; // IMPORTANT: // Add new top-level keys both here and in kUniversalDefaults. diff --git a/src/webgpu/gpu_test.ts b/src/webgpu/gpu_test.ts index 1f021218d290..a2ae8f1b901f 100644 --- a/src/webgpu/gpu_test.ts +++ b/src/webgpu/gpu_test.ts @@ -93,11 +93,47 @@ export function initUncanonicalizedDeviceDescriptor( } } +/** + * Gets the adapter limits as a standard JavaScript object. + */ +function getAdapterLimitsAsDeviceRequiredLimits(adapter: GPUAdapter) { + const requiredLimits: Record = {}; + const adapterLimits = adapter.limits as unknown as Record; + for (const key in adapter.limits) { + requiredLimits[key] = adapterLimits[key]; + } + return requiredLimits; +} + +/** + * Conditionally applies adapter limits to device descriptor + * but does not overwrite existing requested limits. + */ +function conditionallyApplyAdapterLimitsToDeviceDescriptor( + adapter: GPUAdapter, + useAdapterLimits: boolean, + descriptor: UncanonicalizedDeviceDescriptor | undefined +): UncanonicalizedDeviceDescriptor { + return { + ...(descriptor || {}), + requiredLimits: { + ...(useAdapterLimits && getAdapterLimitsAsDeviceRequiredLimits(adapter)), + ...(descriptor?.requiredLimits || {}), + }, + }; +} + export class GPUTestSubcaseBatchState extends SubcaseBatchState { /** Provider for default device. */ private provider: Promise | undefined; /** Provider for mismatched device. */ private mismatchedProvider: Promise | undefined; + /** True if device should be created with adapter limits */ + private useAdapterLimits = false; + + constructor(recorder: TestCaseRecorder, params: TestParams) { + super(recorder, params); + } override async postInit(): Promise { // Skip all subcases if there's no device. @@ -123,6 +159,14 @@ export class GPUTestSubcaseBatchState extends SubcaseBatchState { return this.provider; } + useAdapterLimitsForDevice() { + assert( + this.provider === undefined, + 'useAdapterLimits must be called before getting the device' + ); + this.useAdapterLimits = true; + } + get isCompatibility() { return globalTestConfig.compatibility; } @@ -140,10 +184,18 @@ export class GPUTestSubcaseBatchState extends SubcaseBatchState { */ selectDeviceOrSkipTestCase(descriptor: DeviceSelectionDescriptor): void { assert(this.provider === undefined, "Can't selectDeviceOrSkipTestCase() multiple times"); - this.provider = devicePool.acquire( - this.recorder, - initUncanonicalizedDeviceDescriptor(descriptor) - ); + this.provider = devicePool + .requestAdapter(this.recorder) + .then(adapter => + devicePool.acquire( + adapter, + conditionallyApplyAdapterLimitsToDeviceDescriptor( + adapter, + this.useAdapterLimits, + initUncanonicalizedDeviceDescriptor(descriptor) + ) + ) + ); // Suppress uncaught promise rejection (we'll catch it later). this.provider.catch(() => {}); } @@ -201,10 +253,18 @@ export class GPUTestSubcaseBatchState extends SubcaseBatchState { "Can't selectMismatchedDeviceOrSkipTestCase() multiple times" ); - this.mismatchedProvider = mismatchedDevicePool.acquire( - this.recorder, - initUncanonicalizedDeviceDescriptor(descriptor) - ); + this.mismatchedProvider = mismatchedDevicePool + .requestAdapter(this.recorder) + .then(adapter => + mismatchedDevicePool.acquire( + adapter, + conditionallyApplyAdapterLimitsToDeviceDescriptor( + adapter, + this.useAdapterLimits, + initUncanonicalizedDeviceDescriptor(descriptor) + ) + ) + ); // Suppress uncaught promise rejection (we'll catch it later). this.mismatchedProvider.catch(() => {}); } @@ -1203,6 +1263,20 @@ export class GPUTest extends GPUTestBase { } } +/** + * A version of GPUTest that requires the adapter limits. + */ +export class AdapterLimitsGPUTest extends GPUTest { + public static override MakeSharedState( + recorder: TestCaseRecorder, + params: TestParams + ): GPUTestSubcaseBatchState { + const state = new GPUTestSubcaseBatchState(recorder, params); + state.useAdapterLimitsForDevice(); + return state; + } +} + /** * Texture expectation mixin can be applied on top of GPUTest to add texture * related expectation helpers. diff --git a/src/webgpu/listing_meta.json b/src/webgpu/listing_meta.json index 7c8a0d6c387a..3ac0ab414253 100644 --- a/src/webgpu/listing_meta.json +++ b/src/webgpu/listing_meta.json @@ -899,6 +899,13 @@ "webgpu:idl,constructable:gpu_errors:*": { "subcaseMS": 0.101 }, "webgpu:idl,constructable:pipeline_errors:*": { "subcaseMS": 0.101 }, "webgpu:idl,constructable:uncaptured_error_event:*": { "subcaseMS": 0.101 }, + "webgpu:shader,execution,expression,access,array,index:abstract_scalar:*": { "subcaseMS": 235.962 }, + "webgpu:shader,execution,expression,access,array,index:concrete_scalar:*": { "subcaseMS": 1439.796 }, + "webgpu:shader,execution,expression,access,array,index:vector:*": { "subcaseMS": 2137.684 }, + "webgpu:shader,execution,expression,access,vector,components:abstract_scalar:*": { "subcaseMS": 533.768 }, + "webgpu:shader,execution,expression,access,vector,components:concrete_scalar:*": { "subcaseMS": 11636.652 }, + "webgpu:shader,execution,expression,access,vector,index:abstract_scalar:*": { "subcaseMS": 215.404 }, + "webgpu:shader,execution,expression,access,vector,index:concrete_scalar:*": { "subcaseMS": 1707.582 }, "webgpu:shader,execution,expression,binary,af_addition:scalar:*": { "subcaseMS": 815.300 }, "webgpu:shader,execution,expression,binary,af_addition:scalar_vector:*": { "subcaseMS": 1803.434 }, "webgpu:shader,execution,expression,binary,af_addition:vector:*": { "subcaseMS": 719.600 }, @@ -1809,10 +1816,14 @@ "webgpu:shader,validation,decl,var_access_mode:read_access:*": { "subcaseMS": 1.177 }, "webgpu:shader,validation,decl,var_access_mode:write_access:*": { "subcaseMS": 1.154 }, "webgpu:shader,validation,expression,access,vector:vector:*": { "subcaseMS": 1.407 }, + "webgpu:shader,validation,expression,binary,and_or_xor:invalid_types:*": { "subcaseMS": 24.069 }, + "webgpu:shader,validation,expression,binary,and_or_xor:scalar_vector:*": { "subcaseMS": 666.807 }, "webgpu:shader,validation,expression,binary,bitwise_shift:shift_left_concrete:*": { "subcaseMS": 1.216 }, "webgpu:shader,validation,expression,binary,bitwise_shift:shift_left_vec_size_mismatch:*": { "subcaseMS": 1.367 }, "webgpu:shader,validation,expression,binary,bitwise_shift:shift_right_concrete:*": { "subcaseMS": 1.237 }, "webgpu:shader,validation,expression,binary,bitwise_shift:shift_right_vec_size_mismatch:*": { "subcaseMS": 1.334 }, + "webgpu:shader,validation,expression,binary,comparison:invalid_types:*": { "subcaseMS": 39.526 }, + "webgpu:shader,validation,expression,binary,comparison:scalar_vector:*": { "subcaseMS": 1598.064 }, "webgpu:shader,validation,expression,call,builtin,abs:parameters:*": { "subcaseMS": 10.133 }, "webgpu:shader,validation,expression,call,builtin,abs:values:*": { "subcaseMS": 0.391 }, "webgpu:shader,validation,expression,call,builtin,acos:integer_argument:*": { "subcaseMS": 1.512 }, @@ -1833,6 +1844,9 @@ "webgpu:shader,validation,expression,call,builtin,atan:values:*": { "subcaseMS": 0.335 }, "webgpu:shader,validation,expression,call,builtin,atanh:integer_argument:*": { "subcaseMS": 0.912 }, "webgpu:shader,validation,expression,call,builtin,atanh:values:*": { "subcaseMS": 0.231 }, + "webgpu:shader,validation,expression,call,builtin,atomics:atomic_parameterization:*": { "subcaseMS": 1.346 }, + "webgpu:shader,validation,expression,call,builtin,atomics:data_parameters:*": { "subcaseMS": 38.382 }, + "webgpu:shader,validation,expression,call,builtin,atomics:return_types:*": { "subcaseMS": 28.021 }, "webgpu:shader,validation,expression,call,builtin,atomics:stage:*": { "subcaseMS": 1.346 }, "webgpu:shader,validation,expression,call,builtin,barriers:no_return_value:*": { "subcaseMS": 1.500 }, "webgpu:shader,validation,expression,call,builtin,barriers:only_in_compute:*": { "subcaseMS": 1.500 }, @@ -1914,6 +1928,10 @@ "webgpu:shader,validation,expression,call,builtin,sqrt:values:*": { "subcaseMS": 0.302 }, "webgpu:shader,validation,expression,call,builtin,tan:integer_argument:*": { "subcaseMS": 1.734 }, "webgpu:shader,validation,expression,call,builtin,tan:values:*": { "subcaseMS": 0.350 }, + "webgpu:shader,validation,expression,call,builtin,textureSample:array_index_argument:*": { "subcaseMS": 1.888 }, + "webgpu:shader,validation,expression,call,builtin,textureSample:coords_argument:*": { "subcaseMS": 1.342 }, + "webgpu:shader,validation,expression,call,builtin,textureSample:offset_argument,non_const:*": { "subcaseMS": 1.604 }, + "webgpu:shader,validation,expression,call,builtin,textureSample:offset_argument:*": { "subcaseMS": 1.401 }, "webgpu:shader,validation,expression,call,builtin,unpack4xI8:bad_args:*": { "subcaseMS": 121.263 }, "webgpu:shader,validation,expression,call,builtin,unpack4xI8:must_use:*": { "subcaseMS": 35.200 }, "webgpu:shader,validation,expression,call,builtin,unpack4xI8:supported:*": { "subcaseMS": 24.150 }, @@ -1927,6 +1945,10 @@ "webgpu:shader,validation,expression,unary,address_of_and_indirection:basic:*": { "subcaseMS": 0.000 }, "webgpu:shader,validation,expression,unary,address_of_and_indirection:composite:*": { "subcaseMS": 0.000 }, "webgpu:shader,validation,expression,unary,address_of_and_indirection:invalid:*": { "subcaseMS": 0.000 }, + "webgpu:shader,validation,expression,unary,bitwise_complement:invalid_types:*": { "subcaseMS": 7.564 }, + "webgpu:shader,validation,expression,unary,bitwise_complement:scalar_vector:*": { "subcaseMS": 73.852 }, + "webgpu:shader,validation,expression,unary,logical_negation:invalid_types:*": { "subcaseMS": 7.100 }, + "webgpu:shader,validation,expression,unary,logical_negation:scalar_vector:*": { "subcaseMS": 84.680 }, "webgpu:shader,validation,extension,pointer_composite_access:deref:*": { "subcaseMS": 0.000 }, "webgpu:shader,validation,extension,pointer_composite_access:pointer:*": { "subcaseMS": 0.000 }, "webgpu:shader,validation,extension,readonly_and_readwrite_storage_textures:textureBarrier:*": { "subcaseMS": 1.141 }, @@ -2138,6 +2160,9 @@ "webgpu:shader,validation,types,alias:no_indirect_recursion_via_struct_attribute:*": { "subcaseMS": 1.584 }, "webgpu:shader,validation,types,alias:no_indirect_recursion_via_struct_member:*": { "subcaseMS": 1.000 }, "webgpu:shader,validation,types,alias:no_indirect_recursion_via_vector_element:*": { "subcaseMS": 1.050 }, + "webgpu:shader,validation,types,atomics:address_space:*": { "subcaseMS": 1.050 }, + "webgpu:shader,validation,types,atomics:invalid_operations:*": { "subcaseMS": 1.050 }, + "webgpu:shader,validation,types,atomics:type:*": { "subcaseMS": 1.050 }, "webgpu:shader,validation,types,struct:no_direct_recursion:*": { "subcaseMS": 0.951 }, "webgpu:shader,validation,types,struct:no_indirect_recursion:*": { "subcaseMS": 0.901 }, "webgpu:shader,validation,types,struct:no_indirect_recursion_via_array_element:*": { "subcaseMS": 0.901 }, @@ -2209,6 +2234,7 @@ "webgpu:web_platform,external_texture,video:importExternalTexture,sampleWithVideoFrameWithVisibleRectParam:*": { "subcaseMS": 29.160 }, "webgpu:web_platform,external_texture,video:importExternalTexture,sample_non_YUV_video_frame:*": { "subcaseMS": 36.270 }, "webgpu:web_platform,worker,worker:dedicated_worker:*": { "subcaseMS": 245.901 }, + "webgpu:web_platform,worker,worker:service_worker:*": { "subcaseMS": 102.800 }, "webgpu:web_platform,worker,worker:shared_worker:*": { "subcaseMS": 26.801 }, "_end": "" } diff --git a/src/webgpu/shader/execution/expression/access/array/index.spec.ts b/src/webgpu/shader/execution/expression/access/array/index.spec.ts new file mode 100644 index 000000000000..6cf84c979da9 --- /dev/null +++ b/src/webgpu/shader/execution/expression/access/array/index.spec.ts @@ -0,0 +1,199 @@ +export const description = ` +Execution Tests for array indexing expressions +`; + +import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; +import { GPUTest } from '../../../../../gpu_test.js'; +import { Type, array, f32 } from '../../../../../util/conversion.js'; +import { Case } from '../../case.js'; +import { allInputSources, basicExpressionBuilder, run } from '../../expression.js'; + +export const g = makeTestGroup(GPUTest); + +g.test('concrete_scalar') + .specURL('https://www.w3.org/TR/WGSL/#array-access-expr') + .desc(`Test indexing of an array of concrete scalars`) + .params(u => + u + .combine( + 'inputSource', + // 'uniform' address space requires array stride to be multiple of 16 bytes + allInputSources.filter(s => s !== 'uniform') + ) + .combine('elementType', ['i32', 'u32', 'f32', 'f16'] as const) + .combine('indexType', ['i32', 'u32'] as const) + ) + .beforeAllSubcases(t => { + if (t.params.elementType === 'f16') { + t.selectDeviceOrSkipTestCase('shader-f16'); + } + }) + .fn(async t => { + const elementType = Type[t.params.elementType]; + const indexType = Type[t.params.indexType]; + const cases: Case[] = [ + { + input: [ + array( + /* 0 */ elementType.create(10), + /* 1 */ elementType.create(11), + /* 2 */ elementType.create(12) + ), + indexType.create(0), + ], + expected: elementType.create(10), + }, + { + input: [ + array( + /* 0 */ elementType.create(20), + /* 1 */ elementType.create(21), + /* 2 */ elementType.create(22) + ), + indexType.create(1), + ], + expected: elementType.create(21), + }, + { + input: [ + array( + /* 0 */ elementType.create(30), + /* 1 */ elementType.create(31), + /* 2 */ elementType.create(32) + ), + indexType.create(2), + ], + expected: elementType.create(32), + }, + ]; + await run( + t, + basicExpressionBuilder(ops => `${ops[0]}[${ops[1]}]`), + [Type.array(3, elementType), indexType], + elementType, + t.params, + cases + ); + }); + +g.test('abstract_scalar') + .specURL('https://www.w3.org/TR/WGSL/#array-access-expr') + .desc(`Test indexing of an array of scalars`) + .params(u => + u + .combine('elementType', ['abstract-int', 'abstract-float'] as const) + .combine('indexType', ['i32', 'u32'] as const) + ) + .fn(async t => { + const elementType = Type[t.params.elementType]; + const indexType = Type[t.params.indexType]; + const cases: Case[] = [ + { + input: [ + array( + /* 0 */ elementType.create(0x10_00000000), + /* 1 */ elementType.create(0x11_00000000), + /* 2 */ elementType.create(0x12_00000000) + ), + indexType.create(0), + ], + expected: f32(0x10), + }, + { + input: [ + array( + /* 0 */ elementType.create(0x20_00000000), + /* 1 */ elementType.create(0x21_00000000), + /* 2 */ elementType.create(0x22_00000000) + ), + indexType.create(1), + ], + expected: f32(0x21), + }, + { + input: [ + array( + /* 0 */ elementType.create(0x30_00000000), + /* 1 */ elementType.create(0x31_00000000), + /* 2 */ elementType.create(0x32_00000000) + ), + indexType.create(2), + ], + expected: f32(0x32), + }, + ]; + await run( + t, + basicExpressionBuilder(ops => `${ops[0]}[${ops[1]}] / 0x100000000`), + [Type.array(3, elementType), indexType], + Type.f32, + { inputSource: 'const' }, + cases + ); + }); + +g.test('vector') + .specURL('https://www.w3.org/TR/WGSL/#array-access-expr') + .desc(`Test indexing of an array of vectors`) + .params(u => + u + .combine('inputSource', allInputSources) + .expand('elementType', t => + t.inputSource === 'uniform' + ? (['vec4i', 'vec4u', 'vec4f'] as const) + : (['vec4i', 'vec4u', 'vec4f', 'vec4h'] as const) + ) + .combine('indexType', ['i32', 'u32'] as const) + ) + .beforeAllSubcases(t => { + if (t.params.elementType === 'vec4h') { + t.selectDeviceOrSkipTestCase('shader-f16'); + } + }) + .fn(async t => { + const elementType = Type[t.params.elementType]; + const indexType = Type[t.params.indexType]; + const cases: Case[] = [ + { + input: [ + array( + /* 0 */ elementType.create([0x10, 0x11, 0x12, 0x13]), + /* 1 */ elementType.create([0x14, 0x15, 0x16, 0x17]), + /* 2 */ elementType.create([0x18, 0x19, 0x1a, 0x1b]) + ), + indexType.create(0), + ], + expected: elementType.create([0x10, 0x11, 0x12, 0x13]), + }, + { + input: [ + array( + /* 0 */ elementType.create([0x20, 0x21, 0x22, 0x23]), + /* 1 */ elementType.create([0x24, 0x25, 0x26, 0x27]), + /* 2 */ elementType.create([0x28, 0x29, 0x2a, 0x2b]) + ), + indexType.create(1), + ], + expected: elementType.create([0x24, 0x25, 0x26, 0x27]), + }, + { + input: [ + array( + /* 0 */ elementType.create([0x30, 0x31, 0x32, 0x33]), + /* 1 */ elementType.create([0x34, 0x35, 0x36, 0x37]), + /* 2 */ elementType.create([0x38, 0x39, 0x3a, 0x3b]) + ), + indexType.create(2), + ], + expected: elementType.create([0x38, 0x39, 0x3a, 0x3b]), + }, + ]; + await run( + t, + basicExpressionBuilder(ops => `${ops[0]}[${ops[1]}]`), + [Type.array(3, elementType), indexType], + elementType, + t.params, + cases + ); + }); diff --git a/src/webgpu/shader/execution/expression/access/vector/components.spec.ts b/src/webgpu/shader/execution/expression/access/vector/components.spec.ts new file mode 100644 index 000000000000..e04e4884811b --- /dev/null +++ b/src/webgpu/shader/execution/expression/access/vector/components.spec.ts @@ -0,0 +1,117 @@ +export const description = ` +Execution Tests for vector component selection expressions +`; + +import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; +import { GPUTest } from '../../../../../gpu_test.js'; +import { ScalarValue, Type, VectorValue, f32 } from '../../../../../util/conversion.js'; +import { allInputSources, basicExpressionBuilder, run } from '../../expression.js'; + +export const g = makeTestGroup(GPUTest); + +/** @returns the full permutation of component indices used to component select a vector of width 'n' */ +function indices(n: number) { + const out: number[][] = []; + for (let width = 1; width < n; width++) { + let generate = (swizzle: number[]) => { + out.push(swizzle); + }; + for (let i = 0; i < width; i++) { + const next = generate; + generate = (swizzle: number[]) => { + for (let j = 0; j < width; j++) { + next([...swizzle, j]); + } + }; + } + generate([]); + } + return out; +} + +g.test('concrete_scalar') + .specURL('https://www.w3.org/TR/WGSL/#vector-access-expr') + .desc(`Test vector component selection of concrete vectors`) + .params(u => + u + .combine('inputSource', allInputSources) + .combine('elementType', ['i32', 'u32', 'f32', 'f16'] as const) + .combine('width', [2, 3, 4] as const) + .combine('components', ['rgba', 'xyzw'] as const) + .beginSubcases() + .expand('indices', u => indices(u.width)) + ) + .beforeAllSubcases(t => { + if (t.params.elementType === 'f16') { + t.selectDeviceOrSkipTestCase('shader-f16'); + } + }) + .fn(async t => { + const elementType = Type[t.params.elementType]; + const vectorType = Type.vec(t.params.width, elementType); + const elementValues = (i: number) => (i + 1) * 10; + const elements: ScalarValue[] = []; + for (let i = 0; i < t.params.width; i++) { + elements.push(elementType.create(elementValues(i))); + } + const result = (() => { + if (t.params.indices.length === 1) { + return { type: elementType, value: elementType.create(elementValues(0)) }; + } else { + const vec = Type.vec(t.params.indices.length, elementType); + return { type: vec, value: vec.create(t.params.indices.map(i => elementValues(i))) }; + } + })(); + + const components = t.params.indices.map(i => t.params.components[i]).join(''); + await run( + t, + basicExpressionBuilder(ops => `${ops[0]}.${components}`), + [vectorType], + result.type, + t.params, + [{ input: [new VectorValue(elements)], expected: result.value }] + ); + }); + +g.test('abstract_scalar') + .specURL('https://www.w3.org/TR/WGSL/#vector-access-expr') + .desc(`Test vector component selection of abstract numeric vectors`) + .params(u => + u + .combine('elementType', ['abstract-int', 'abstract-float'] as const) + .combine('width', [2, 3, 4] as const) + .combine('components', ['rgba', 'xyzw'] as const) + .beginSubcases() + .expand('indices', u => indices(u.width)) + ) + .fn(async t => { + const elementType = Type[t.params.elementType]; + const vectorType = Type.vec(t.params.width, elementType); + const elementValues = (i: number) => (i + 1) * 0x100000000; + const elements: ScalarValue[] = []; + for (let i = 0; i < t.params.width; i++) { + elements.push(elementType.create(elementValues(i))); + } + const result = (() => { + if (t.params.indices.length === 1) { + return { type: Type.f32, value: f32(elementValues(0) / 0x100000000) }; + } else { + const vec = Type.vec(t.params.indices.length, Type.f32); + return { + type: vec, + value: vec.create(t.params.indices.map(i => elementValues(i) / 0x100000000)), + }; + } + })(); + + const components = t.params.indices.map(i => t.params.components[i]).join(''); + await run( + t, + basicExpressionBuilder(ops => `${ops[0]}.${components} / 0x100000000`), + [vectorType], + result.type, + { inputSource: 'const' }, + [{ input: [new VectorValue(elements)], expected: result.value }] + ); + }); diff --git a/src/webgpu/shader/execution/expression/access/vector/index.spec.ts b/src/webgpu/shader/execution/expression/access/vector/index.spec.ts new file mode 100644 index 000000000000..acfab82e68ca --- /dev/null +++ b/src/webgpu/shader/execution/expression/access/vector/index.spec.ts @@ -0,0 +1,83 @@ +export const description = ` +Execution Tests for vector indexing expressions +`; + +import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; +import { GPUTest } from '../../../../../gpu_test.js'; +import { ScalarValue, Type, VectorValue, f32 } from '../../../../../util/conversion.js'; +import { Case } from '../../case.js'; +import { allInputSources, basicExpressionBuilder, run } from '../../expression.js'; + +export const g = makeTestGroup(GPUTest); + +g.test('concrete_scalar') + .specURL('https://www.w3.org/TR/WGSL/#vector-access-expr') + .desc(`Test indexing of concrete vectors`) + .params(u => + u + .combine('inputSource', allInputSources) + .combine('elementType', ['i32', 'u32', 'f32', 'f16'] as const) + .combine('indexType', ['i32', 'u32'] as const) + .combine('width', [2, 3, 4] as const) + ) + .beforeAllSubcases(t => { + if (t.params.elementType === 'f16') { + t.selectDeviceOrSkipTestCase('shader-f16'); + } + }) + .fn(async t => { + const elementType = Type[t.params.elementType]; + const indexType = Type[t.params.indexType]; + const vectorType = Type.vec(t.params.width, elementType); + const elements: ScalarValue[] = []; + for (let i = 0; i < t.params.width; i++) { + elements.push(elementType.create((i + 1) * 10)); + } + const vector = new VectorValue(elements); + const cases: Case[] = []; + for (let i = 0; i < t.params.width; i++) { + cases.push({ input: [vector, indexType.create(i)], expected: elements[i] }); + } + + await run( + t, + basicExpressionBuilder(ops => `${ops[0]}[${ops[1]}]`), + [vectorType, indexType], + elementType, + t.params, + cases + ); + }); + +g.test('abstract_scalar') + .specURL('https://www.w3.org/TR/WGSL/#vector-access-expr') + .desc(`Test indexing of abstract numeric vectors`) + .params(u => + u + .combine('elementType', ['abstract-int', 'abstract-float'] as const) + .combine('indexType', ['i32', 'u32'] as const) + .combine('width', [2, 3, 4] as const) + ) + .fn(async t => { + const elementType = Type[t.params.elementType]; + const indexType = Type[t.params.indexType]; + const vectorType = Type.vec(t.params.width, elementType); + const elements: ScalarValue[] = []; + for (let i = 0; i < t.params.width; i++) { + elements.push(elementType.create((i + 1) * 0x100000000)); + } + const vector = new VectorValue(elements); + const cases: Case[] = []; + for (let i = 0; i < t.params.width; i++) { + cases.push({ input: [vector, indexType.create(i)], expected: f32(i + 1) }); + } + + await run( + t, + basicExpressionBuilder(ops => `${ops[0]}[${ops[1]}] / 0x100000000`), + [vectorType, indexType], + Type.f32, + { inputSource: 'const' }, + cases + ); + }); diff --git a/src/webgpu/shader/execution/expression/binary/af_addition.spec.ts b/src/webgpu/shader/execution/expression/binary/af_addition.spec.ts index 3b14897c2227..52a07ff328f8 100644 --- a/src/webgpu/shader/execution/expression/binary/af_addition.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/af_addition.spec.ts @@ -1,10 +1,10 @@ export const description = ` -Execution Tests for non-matrix AbstractFloat addition expression +Execution Tests for non-matrix abstract-float addition expression `; import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeAbstractFloat, TypeVec } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { onlyConstInputSource, run } from '../expression.js'; import { d } from './af_addition.cache.js'; @@ -26,8 +26,8 @@ Accuracy: Correctly rounded await run( t, abstractFloatBinary('+'), - [TypeAbstractFloat, TypeAbstractFloat], - TypeAbstractFloat, + [Type.abstractFloat, Type.abstractFloat], + Type.abstractFloat, t.params, cases ); @@ -49,8 +49,8 @@ Accuracy: Correctly rounded await run( t, abstractFloatBinary('+'), - [TypeAbstractFloat, TypeAbstractFloat], - TypeAbstractFloat, + [Type.abstractFloat, Type.abstractFloat], + Type.abstractFloat, t.params, cases ); @@ -71,8 +71,8 @@ Accuracy: Correctly rounded await run( t, abstractFloatBinary('+'), - [TypeVec(dim, TypeAbstractFloat), TypeAbstractFloat], - TypeVec(dim, TypeAbstractFloat), + [Type.vec(dim, Type.abstractFloat), Type.abstractFloat], + Type.vec(dim, Type.abstractFloat), t.params, cases ); @@ -93,8 +93,8 @@ Accuracy: Correctly rounded await run( t, abstractFloatBinary('+'), - [TypeAbstractFloat, TypeVec(dim, TypeAbstractFloat)], - TypeVec(dim, TypeAbstractFloat), + [Type.abstractFloat, Type.vec(dim, Type.abstractFloat)], + Type.vec(dim, Type.abstractFloat), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/binary/af_comparison.cache.ts b/src/webgpu/shader/execution/expression/binary/af_comparison.cache.ts index 648ea5c0b0b8..e0002664018a 100644 --- a/src/webgpu/shader/execution/expression/binary/af_comparison.cache.ts +++ b/src/webgpu/shader/execution/expression/binary/af_comparison.cache.ts @@ -1,5 +1,5 @@ import { anyOf } from '../../../../util/compare.js'; -import { abstractFloat, bool, Scalar } from '../../../../util/conversion.js'; +import { abstractFloat, bool, ScalarValue } from '../../../../util/conversion.js'; import { flushSubnormalNumberF64, vectorF64Range } from '../../../../util/math.js'; import { Case } from '../case.js'; import { makeCaseCache } from '../case_cache.js'; @@ -11,7 +11,7 @@ import { makeCaseCache } from '../case_cache.js'; function makeCase( lhs: number, rhs: number, - truthFunc: (lhs: Scalar, rhs: Scalar) => boolean + truthFunc: (lhs: ScalarValue, rhs: ScalarValue) => boolean ): Case { // Subnormal float values may be flushed at any time. // https://www.w3.org/TR/WGSL/#floating-point-evaluation @@ -19,7 +19,7 @@ function makeCase( const af_rhs = abstractFloat(rhs); const lhs_options = new Set([af_lhs, abstractFloat(flushSubnormalNumberF64(lhs))]); const rhs_options = new Set([af_rhs, abstractFloat(flushSubnormalNumberF64(rhs))]); - const expected: Array = []; + const expected: Array = []; lhs_options.forEach(l => { rhs_options.forEach(r => { const result = bool(truthFunc(l, r)); @@ -34,7 +34,7 @@ function makeCase( export const d = makeCaseCache('binary/af_logical', { equals: () => { - const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + const truthFunc = (lhs: ScalarValue, rhs: ScalarValue): boolean => { return (lhs.value as number) === (rhs.value as number); }; @@ -43,7 +43,7 @@ export const d = makeCaseCache('binary/af_logical', { }); }, not_equals: () => { - const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + const truthFunc = (lhs: ScalarValue, rhs: ScalarValue): boolean => { return (lhs.value as number) !== (rhs.value as number); }; @@ -52,7 +52,7 @@ export const d = makeCaseCache('binary/af_logical', { }); }, less_than: () => { - const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + const truthFunc = (lhs: ScalarValue, rhs: ScalarValue): boolean => { return (lhs.value as number) < (rhs.value as number); }; @@ -61,7 +61,7 @@ export const d = makeCaseCache('binary/af_logical', { }); }, less_equals: () => { - const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + const truthFunc = (lhs: ScalarValue, rhs: ScalarValue): boolean => { return (lhs.value as number) <= (rhs.value as number); }; @@ -70,7 +70,7 @@ export const d = makeCaseCache('binary/af_logical', { }); }, greater_than: () => { - const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + const truthFunc = (lhs: ScalarValue, rhs: ScalarValue): boolean => { return (lhs.value as number) > (rhs.value as number); }; @@ -79,7 +79,7 @@ export const d = makeCaseCache('binary/af_logical', { }); }, greater_equals: () => { - const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + const truthFunc = (lhs: ScalarValue, rhs: ScalarValue): boolean => { return (lhs.value as number) >= (rhs.value as number); }; diff --git a/src/webgpu/shader/execution/expression/binary/af_comparison.spec.ts b/src/webgpu/shader/execution/expression/binary/af_comparison.spec.ts index cc03ee4367f2..3941e1253969 100644 --- a/src/webgpu/shader/execution/expression/binary/af_comparison.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/af_comparison.spec.ts @@ -1,10 +1,10 @@ export const description = ` -Execution Tests for the AbstractFloat comparison operations +Execution Tests for the abstract-float comparison operations `; import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeAbstractFloat, TypeBool } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { allInputSources, run } from '../expression.js'; import { d } from './af_comparison.cache.js'; @@ -27,7 +27,14 @@ Accuracy: Correct result ) .fn(async t => { const cases = await d.get('equals'); - await run(t, binary('=='), [TypeAbstractFloat, TypeAbstractFloat], TypeBool, t.params, cases); + await run( + t, + binary('=='), + [Type.abstractFloat, Type.abstractFloat], + Type.bool, + t.params, + cases + ); }); g.test('not_equals') @@ -45,7 +52,14 @@ Accuracy: Correct result ) .fn(async t => { const cases = await d.get('not_equals'); - await run(t, binary('!='), [TypeAbstractFloat, TypeAbstractFloat], TypeBool, t.params, cases); + await run( + t, + binary('!='), + [Type.abstractFloat, Type.abstractFloat], + Type.bool, + t.params, + cases + ); }); g.test('less_than') @@ -63,7 +77,7 @@ Accuracy: Correct result ) .fn(async t => { const cases = await d.get('less_than'); - await run(t, binary('<'), [TypeAbstractFloat, TypeAbstractFloat], TypeBool, t.params, cases); + await run(t, binary('<'), [Type.abstractFloat, Type.abstractFloat], Type.bool, t.params, cases); }); g.test('less_equals') @@ -81,7 +95,14 @@ Accuracy: Correct result ) .fn(async t => { const cases = await d.get('less_equals'); - await run(t, binary('<='), [TypeAbstractFloat, TypeAbstractFloat], TypeBool, t.params, cases); + await run( + t, + binary('<='), + [Type.abstractFloat, Type.abstractFloat], + Type.bool, + t.params, + cases + ); }); g.test('greater_than') @@ -99,7 +120,7 @@ Accuracy: Correct result ) .fn(async t => { const cases = await d.get('greater_than'); - await run(t, binary('>'), [TypeAbstractFloat, TypeAbstractFloat], TypeBool, t.params, cases); + await run(t, binary('>'), [Type.abstractFloat, Type.abstractFloat], Type.bool, t.params, cases); }); g.test('greater_equals') @@ -117,5 +138,12 @@ Accuracy: Correct result ) .fn(async t => { const cases = await d.get('greater_equals'); - await run(t, binary('>='), [TypeAbstractFloat, TypeAbstractFloat], TypeBool, t.params, cases); + await run( + t, + binary('>='), + [Type.abstractFloat, Type.abstractFloat], + Type.bool, + t.params, + cases + ); }); diff --git a/src/webgpu/shader/execution/expression/binary/af_division.spec.ts b/src/webgpu/shader/execution/expression/binary/af_division.spec.ts index 5080e62264d2..0ebe30b6ccc9 100644 --- a/src/webgpu/shader/execution/expression/binary/af_division.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/af_division.spec.ts @@ -1,10 +1,10 @@ export const description = ` -Execution Tests for non-matrix AbstractFloat division expression +Execution Tests for non-matrix abstract-float division expression `; import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeAbstractFloat, TypeVec } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { onlyConstInputSource, run } from '../expression.js'; import { d } from './af_division.cache.js'; @@ -26,8 +26,8 @@ Accuracy: 2.5 ULP for |y| in the range [2^-126, 2^126] await run( t, abstractFloatBinary('/'), - [TypeAbstractFloat, TypeAbstractFloat], - TypeAbstractFloat, + [Type.abstractFloat, Type.abstractFloat], + Type.abstractFloat, t.params, cases ); @@ -49,8 +49,8 @@ Accuracy: 2.5 ULP for |y| in the range [2^-126, 2^126] await run( t, abstractFloatBinary('/'), - [TypeAbstractFloat, TypeAbstractFloat], - TypeAbstractFloat, + [Type.abstractFloat, Type.abstractFloat], + Type.abstractFloat, t.params, cases ); @@ -71,8 +71,8 @@ Accuracy: Correctly rounded await run( t, abstractFloatBinary('/'), - [TypeVec(dim, TypeAbstractFloat), TypeAbstractFloat], - TypeVec(dim, TypeAbstractFloat), + [Type.vec(dim, Type.abstractFloat), Type.abstractFloat], + Type.vec(dim, Type.abstractFloat), t.params, cases ); @@ -93,8 +93,8 @@ Accuracy: Correctly rounded await run( t, abstractFloatBinary('/'), - [TypeAbstractFloat, TypeVec(dim, TypeAbstractFloat)], - TypeVec(dim, TypeAbstractFloat), + [Type.abstractFloat, Type.vec(dim, Type.abstractFloat)], + Type.vec(dim, Type.abstractFloat), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/binary/af_matrix_addition.cache.ts b/src/webgpu/shader/execution/expression/binary/af_matrix_addition.cache.ts index 75c13d7702b6..e89250f57bd4 100644 --- a/src/webgpu/shader/execution/expression/binary/af_matrix_addition.cache.ts +++ b/src/webgpu/shader/execution/expression/binary/af_matrix_addition.cache.ts @@ -1,5 +1,6 @@ import { FP } from '../../../../util/floating_point.js'; import { sparseMatrixF64Range } from '../../../../util/math.js'; +import { selectNCases } from '../case.js'; import { makeCaseCache } from '../case_cache.js'; // Cases: matCxR @@ -7,11 +8,15 @@ const mat_cases = ([2, 3, 4] as const) .flatMap(cols => ([2, 3, 4] as const).map(rows => ({ [`mat${cols}x${rows}`]: () => { - return FP.abstract.generateMatrixPairToMatrixCases( - sparseMatrixF64Range(cols, rows), - sparseMatrixF64Range(cols, rows), - 'finite', - FP.abstract.additionMatrixMatrixInterval + return selectNCases( + 'binary/af_matrix_addition', + 50, + FP.abstract.generateMatrixPairToMatrixCases( + sparseMatrixF64Range(cols, rows), + sparseMatrixF64Range(cols, rows), + 'finite', + FP.abstract.additionMatrixMatrixInterval + ) ); }, })) diff --git a/src/webgpu/shader/execution/expression/binary/af_matrix_addition.spec.ts b/src/webgpu/shader/execution/expression/binary/af_matrix_addition.spec.ts index 7f6019f53127..49c746c53e74 100644 --- a/src/webgpu/shader/execution/expression/binary/af_matrix_addition.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/af_matrix_addition.spec.ts @@ -1,10 +1,10 @@ export const description = ` -Execution Tests for matrix AbstractFloat addition expressions +Execution Tests for matrix abstract-float addition expressions `; import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeAbstractFloat, TypeMat } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { onlyConstInputSource, run } from '../expression.js'; import { d } from './af_matrix_addition.cache.js'; @@ -33,8 +33,8 @@ Accuracy: Correctly rounded await run( t, abstractFloatBinary('+'), - [TypeMat(cols, rows, TypeAbstractFloat), TypeMat(cols, rows, TypeAbstractFloat)], - TypeMat(cols, rows, TypeAbstractFloat), + [Type.mat(cols, rows, Type.abstractFloat), Type.mat(cols, rows, Type.abstractFloat)], + Type.mat(cols, rows, Type.abstractFloat), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/binary/af_matrix_matrix_multiplication.cache.ts b/src/webgpu/shader/execution/expression/binary/af_matrix_matrix_multiplication.cache.ts index c7540083d6ff..e539ee1db5da 100644 --- a/src/webgpu/shader/execution/expression/binary/af_matrix_matrix_multiplication.cache.ts +++ b/src/webgpu/shader/execution/expression/binary/af_matrix_matrix_multiplication.cache.ts @@ -11,7 +11,7 @@ const mat_mat_cases = ([2, 3, 4] as const) [`mat${k}x${rows}_mat${cols}x${k}`]: () => { return selectNCases( 'binary/af_matrix_matrix_multiplication', - 50, + 10, FP.abstract.generateMatrixPairToMatrixCases( sparseMatrixF64Range(k, rows), sparseMatrixF64Range(cols, k), diff --git a/src/webgpu/shader/execution/expression/binary/af_matrix_matrix_multiplication.spec.ts b/src/webgpu/shader/execution/expression/binary/af_matrix_matrix_multiplication.spec.ts index bb7fd668c296..9320fb1226bf 100644 --- a/src/webgpu/shader/execution/expression/binary/af_matrix_matrix_multiplication.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/af_matrix_matrix_multiplication.spec.ts @@ -4,7 +4,7 @@ Execution Tests for matrix-matrix AbstractFloat multiplication expression import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeAbstractFloat, TypeMat } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { onlyConstInputSource, run } from '../expression.js'; import { d } from './af_matrix_matrix_multiplication.cache.js'; @@ -27,9 +27,6 @@ Accuracy: Correctly rounded .combine('x_rows', [2, 3, 4] as const) .combine('y_cols', [2, 3, 4] as const) ) - .beforeAllSubcases(t => { - t.selectDeviceOrSkipTestCase({ requiredFeatures: ['shader-f16'] }); - }) .fn(async t => { const x_cols = t.params.common_dim; const x_rows = t.params.x_rows; @@ -40,8 +37,8 @@ Accuracy: Correctly rounded await run( t, abstractFloatBinary('*'), - [TypeMat(x_cols, x_rows, TypeAbstractFloat), TypeMat(y_cols, y_rows, TypeAbstractFloat)], - TypeMat(y_cols, x_rows, TypeAbstractFloat), + [Type.mat(x_cols, x_rows, Type.abstractFloat), Type.mat(y_cols, y_rows, Type.abstractFloat)], + Type.mat(y_cols, x_rows, Type.abstractFloat), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/binary/af_matrix_scalar_multiplication.spec.ts b/src/webgpu/shader/execution/expression/binary/af_matrix_scalar_multiplication.spec.ts index 05afa31275d6..c6faabbc8453 100644 --- a/src/webgpu/shader/execution/expression/binary/af_matrix_scalar_multiplication.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/af_matrix_scalar_multiplication.spec.ts @@ -4,7 +4,7 @@ Execution Tests for matrix-scalar and scalar-matrix AbstractFloat multiplication import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeAbstractFloat, TypeMat } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { onlyConstInputSource, run } from '../expression.js'; import { d } from './af_matrix_scalar_multiplication.cache.js'; @@ -33,8 +33,8 @@ Accuracy: Correctly rounded await run( t, abstractFloatBinary('*'), - [TypeMat(cols, rows, TypeAbstractFloat), TypeAbstractFloat], - TypeMat(cols, rows, TypeAbstractFloat), + [Type.mat(cols, rows, Type.abstractFloat), Type.abstractFloat], + Type.mat(cols, rows, Type.abstractFloat), t.params, cases ); @@ -61,8 +61,8 @@ Accuracy: Correctly rounded await run( t, abstractFloatBinary('*'), - [TypeAbstractFloat, TypeMat(cols, rows, TypeAbstractFloat)], - TypeMat(cols, rows, TypeAbstractFloat), + [Type.abstractFloat, Type.mat(cols, rows, Type.abstractFloat)], + Type.mat(cols, rows, Type.abstractFloat), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/binary/af_matrix_subtraction.cache.ts b/src/webgpu/shader/execution/expression/binary/af_matrix_subtraction.cache.ts index b030f369e3d3..c3e5e856dc26 100644 --- a/src/webgpu/shader/execution/expression/binary/af_matrix_subtraction.cache.ts +++ b/src/webgpu/shader/execution/expression/binary/af_matrix_subtraction.cache.ts @@ -1,5 +1,6 @@ import { FP } from '../../../../util/floating_point.js'; import { sparseMatrixF64Range } from '../../../../util/math.js'; +import { selectNCases } from '../case.js'; import { makeCaseCache } from '../case_cache.js'; // Cases: matCxR @@ -7,11 +8,15 @@ const mat_cases = ([2, 3, 4] as const) .flatMap(cols => ([2, 3, 4] as const).map(rows => ({ [`mat${cols}x${rows}`]: () => { - return FP.abstract.generateMatrixPairToMatrixCases( - sparseMatrixF64Range(cols, rows), - sparseMatrixF64Range(cols, rows), - 'finite', - FP.abstract.subtractionMatrixMatrixInterval + return selectNCases( + 'binary/af_matrix_subtraction', + 50, + FP.abstract.generateMatrixPairToMatrixCases( + sparseMatrixF64Range(cols, rows), + sparseMatrixF64Range(cols, rows), + 'finite', + FP.abstract.subtractionMatrixMatrixInterval + ) ); }, })) diff --git a/src/webgpu/shader/execution/expression/binary/af_matrix_subtraction.spec.ts b/src/webgpu/shader/execution/expression/binary/af_matrix_subtraction.spec.ts index 4c6d1d423234..9b240fdee903 100644 --- a/src/webgpu/shader/execution/expression/binary/af_matrix_subtraction.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/af_matrix_subtraction.spec.ts @@ -1,10 +1,10 @@ export const description = ` -Execution Tests for matrix AbstractFloat subtraction expression +Execution Tests for matrix abstract-float subtraction expression `; import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeAbstractFloat, TypeMat } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { onlyConstInputSource, run } from '../expression.js'; import { d } from './af_matrix_subtraction.cache.js'; @@ -33,8 +33,8 @@ Accuracy: Correctly rounded await run( t, abstractFloatBinary('-'), - [TypeMat(cols, rows, TypeAbstractFloat), TypeMat(cols, rows, TypeAbstractFloat)], - TypeMat(cols, rows, TypeAbstractFloat), + [Type.mat(cols, rows, Type.abstractFloat), Type.mat(cols, rows, Type.abstractFloat)], + Type.mat(cols, rows, Type.abstractFloat), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/binary/af_matrix_vector_multiplication.spec.ts b/src/webgpu/shader/execution/expression/binary/af_matrix_vector_multiplication.spec.ts index c464c442aa85..5db78f8369f7 100644 --- a/src/webgpu/shader/execution/expression/binary/af_matrix_vector_multiplication.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/af_matrix_vector_multiplication.spec.ts @@ -4,7 +4,7 @@ Execution Tests for matrix-vector and vector-matrix AbstractFloat multiplication import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeAbstractFloat, TypeMat, TypeVec } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { onlyConstInputSource, run } from '../expression.js'; import { d } from './af_matrix_vector_multiplication.cache.js'; @@ -33,8 +33,8 @@ Accuracy: Correctly rounded await run( t, abstractFloatBinary('*'), - [TypeMat(cols, rows, TypeAbstractFloat), TypeVec(cols, TypeAbstractFloat)], - TypeVec(rows, TypeAbstractFloat), + [Type.mat(cols, rows, Type.abstractFloat), Type.vec(cols, Type.abstractFloat)], + Type.vec(rows, Type.abstractFloat), t.params, cases ); @@ -61,8 +61,8 @@ Accuracy: Correctly rounded await run( t, abstractFloatBinary('*'), - [TypeVec(rows, TypeAbstractFloat), TypeMat(cols, rows, TypeAbstractFloat)], - TypeVec(cols, TypeAbstractFloat), + [Type.vec(rows, Type.abstractFloat), Type.mat(cols, rows, Type.abstractFloat)], + Type.vec(cols, Type.abstractFloat), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/binary/af_multiplication.spec.ts b/src/webgpu/shader/execution/expression/binary/af_multiplication.spec.ts index 57cf0dbc4768..405de758bd76 100644 --- a/src/webgpu/shader/execution/expression/binary/af_multiplication.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/af_multiplication.spec.ts @@ -1,10 +1,10 @@ export const description = ` -Execution Tests for non-matrix AbstractFloat multiplication expression +Execution Tests for non-matrix abstract-float multiplication expression `; import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeAbstractFloat, TypeVec } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { onlyConstInputSource, run } from '../expression.js'; import { d } from './af_multiplication.cache.js'; @@ -26,8 +26,8 @@ Accuracy: Correctly rounded await run( t, abstractFloatBinary('*'), - [TypeAbstractFloat, TypeAbstractFloat], - TypeAbstractFloat, + [Type.abstractFloat, Type.abstractFloat], + Type.abstractFloat, t.params, cases ); @@ -49,8 +49,8 @@ Accuracy: Correctly rounded await run( t, abstractFloatBinary('*'), - [TypeAbstractFloat, TypeAbstractFloat], - TypeAbstractFloat, + [Type.abstractFloat, Type.abstractFloat], + Type.abstractFloat, t.params, cases ); @@ -71,8 +71,8 @@ Accuracy: Correctly rounded await run( t, abstractFloatBinary('*'), - [TypeVec(dim, TypeAbstractFloat), TypeAbstractFloat], - TypeVec(dim, TypeAbstractFloat), + [Type.vec(dim, Type.abstractFloat), Type.abstractFloat], + Type.vec(dim, Type.abstractFloat), t.params, cases ); @@ -93,8 +93,8 @@ Accuracy: Correctly rounded await run( t, abstractFloatBinary('*'), - [TypeAbstractFloat, TypeVec(dim, TypeAbstractFloat)], - TypeVec(dim, TypeAbstractFloat), + [Type.abstractFloat, Type.vec(dim, Type.abstractFloat)], + Type.vec(dim, Type.abstractFloat), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/binary/af_remainder.spec.ts b/src/webgpu/shader/execution/expression/binary/af_remainder.spec.ts index 31a0991e02c4..d743f85ed653 100644 --- a/src/webgpu/shader/execution/expression/binary/af_remainder.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/af_remainder.spec.ts @@ -4,7 +4,7 @@ Execution Tests for non-matrix abstract float remainder expression import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeAbstractFloat, TypeVec } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { onlyConstInputSource, run } from '../expression.js'; import { d } from './af_remainder.cache.js'; @@ -26,8 +26,8 @@ Accuracy: Derived from x - y * trunc(x/y) await run( t, abstractFloatBinary('%'), - [TypeAbstractFloat, TypeAbstractFloat], - TypeAbstractFloat, + [Type.abstractFloat, Type.abstractFloat], + Type.abstractFloat, t.params, cases ); @@ -49,8 +49,8 @@ Accuracy: Derived from x - y * trunc(x/y) await run( t, abstractFloatBinary('%'), - [TypeAbstractFloat, TypeAbstractFloat], - TypeAbstractFloat, + [Type.abstractFloat, Type.abstractFloat], + Type.abstractFloat, t.params, cases ); @@ -71,8 +71,8 @@ Accuracy: Correctly rounded await run( t, abstractFloatBinary('%'), - [TypeVec(dim, TypeAbstractFloat), TypeAbstractFloat], - TypeVec(dim, TypeAbstractFloat), + [Type.vec(dim, Type.abstractFloat), Type.abstractFloat], + Type.vec(dim, Type.abstractFloat), t.params, cases ); @@ -93,8 +93,8 @@ Accuracy: Correctly rounded await run( t, abstractFloatBinary('%'), - [TypeAbstractFloat, TypeVec(dim, TypeAbstractFloat)], - TypeVec(dim, TypeAbstractFloat), + [Type.abstractFloat, Type.vec(dim, Type.abstractFloat)], + Type.vec(dim, Type.abstractFloat), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/binary/af_subtraction.spec.ts b/src/webgpu/shader/execution/expression/binary/af_subtraction.spec.ts index 72004cfb1cee..2874a744da2e 100644 --- a/src/webgpu/shader/execution/expression/binary/af_subtraction.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/af_subtraction.spec.ts @@ -1,10 +1,10 @@ export const description = ` -Execution Tests for non-matrix AbstractFloat subtraction expression +Execution Tests for non-matrix abstract-float subtraction expression `; import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeAbstractFloat, TypeVec } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { onlyConstInputSource, run } from '../expression.js'; import { d } from './af_subtraction.cache.js'; @@ -26,8 +26,8 @@ Accuracy: Correctly rounded await run( t, abstractFloatBinary('-'), - [TypeAbstractFloat, TypeAbstractFloat], - TypeAbstractFloat, + [Type.abstractFloat, Type.abstractFloat], + Type.abstractFloat, t.params, cases ); @@ -49,8 +49,8 @@ Accuracy: Correctly rounded await run( t, abstractFloatBinary('-'), - [TypeAbstractFloat, TypeAbstractFloat], - TypeAbstractFloat, + [Type.abstractFloat, Type.abstractFloat], + Type.abstractFloat, t.params, cases ); @@ -71,8 +71,8 @@ Accuracy: Correctly rounded await run( t, abstractFloatBinary('-'), - [TypeVec(dim, TypeAbstractFloat), TypeAbstractFloat], - TypeVec(dim, TypeAbstractFloat), + [Type.vec(dim, Type.abstractFloat), Type.abstractFloat], + Type.vec(dim, Type.abstractFloat), t.params, cases ); @@ -93,8 +93,8 @@ Accuracy: Correctly rounded await run( t, abstractFloatBinary('-'), - [TypeAbstractFloat, TypeVec(dim, TypeAbstractFloat)], - TypeVec(dim, TypeAbstractFloat), + [Type.abstractFloat, Type.vec(dim, Type.abstractFloat)], + Type.vec(dim, Type.abstractFloat), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/binary/ai_arithmetic.spec.ts b/src/webgpu/shader/execution/expression/binary/ai_arithmetic.spec.ts index ae8b6ccf483b..ef211af3ed4b 100644 --- a/src/webgpu/shader/execution/expression/binary/ai_arithmetic.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/ai_arithmetic.spec.ts @@ -4,7 +4,7 @@ Execution Tests for the abstract int arithmetic binary expression operations import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeAbstractInt, TypeVec } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { onlyConstInputSource, run } from '../expression.js'; import { d } from './ai_arithmetic.cache.js'; @@ -29,8 +29,8 @@ Expression: x + y await run( t, abstractIntBinary('+'), - [TypeAbstractInt, TypeAbstractInt], - TypeAbstractInt, + [Type.abstractInt, Type.abstractInt], + Type.abstractInt, t.params, cases ); @@ -48,9 +48,9 @@ Expression: x + y ) .fn(async t => { const vec_size = t.params.vectorize_rhs; - const vec_type = TypeVec(vec_size, TypeAbstractInt); + const vec_type = Type.vec(vec_size, Type.abstractInt); const cases = await d.get(`addition_scalar_vector${vec_size}`); - await run(t, abstractIntBinary('+'), [TypeAbstractInt, vec_type], vec_type, t.params, cases); + await run(t, abstractIntBinary('+'), [Type.abstractInt, vec_type], vec_type, t.params, cases); }); g.test('addition_vector_scalar') @@ -65,9 +65,9 @@ Expression: x + y ) .fn(async t => { const vec_size = t.params.vectorize_lhs; - const vec_type = TypeVec(vec_size, TypeAbstractInt); + const vec_type = Type.vec(vec_size, Type.abstractInt); const cases = await d.get(`addition_vector${vec_size}_scalar`); - await run(t, abstractIntBinary('+'), [vec_type, TypeAbstractInt], vec_type, t.params, cases); + await run(t, abstractIntBinary('+'), [vec_type, Type.abstractInt], vec_type, t.params, cases); }); g.test('division') @@ -87,8 +87,8 @@ Expression: x / y await run( t, abstractIntBinary('/'), - [TypeAbstractInt, TypeAbstractInt], - TypeAbstractInt, + [Type.abstractInt, Type.abstractInt], + Type.abstractInt, t.params, cases ); @@ -106,9 +106,9 @@ Expression: x / y ) .fn(async t => { const vec_size = t.params.vectorize_rhs; - const vec_type = TypeVec(vec_size, TypeAbstractInt); + const vec_type = Type.vec(vec_size, Type.abstractInt); const cases = await d.get(`division_scalar_vector${vec_size}`); - await run(t, abstractIntBinary('/'), [TypeAbstractInt, vec_type], vec_type, t.params, cases); + await run(t, abstractIntBinary('/'), [Type.abstractInt, vec_type], vec_type, t.params, cases); }); g.test('division_vector_scalar') @@ -123,9 +123,9 @@ Expression: x / y ) .fn(async t => { const vec_size = t.params.vectorize_lhs; - const vec_type = TypeVec(vec_size, TypeAbstractInt); + const vec_type = Type.vec(vec_size, Type.abstractInt); const cases = await d.get(`division_vector${vec_size}_scalar`); - await run(t, abstractIntBinary('/'), [vec_type, TypeAbstractInt], vec_type, t.params, cases); + await run(t, abstractIntBinary('/'), [vec_type, Type.abstractInt], vec_type, t.params, cases); }); g.test('multiplication') @@ -145,8 +145,8 @@ Expression: x * y await run( t, abstractIntBinary('*'), - [TypeAbstractInt, TypeAbstractInt], - TypeAbstractInt, + [Type.abstractInt, Type.abstractInt], + Type.abstractInt, t.params, cases ); @@ -164,9 +164,9 @@ Expression: x * y ) .fn(async t => { const vec_size = t.params.vectorize_rhs; - const vec_type = TypeVec(vec_size, TypeAbstractInt); + const vec_type = Type.vec(vec_size, Type.abstractInt); const cases = await d.get(`multiplication_scalar_vector${vec_size}`); - await run(t, abstractIntBinary('*'), [TypeAbstractInt, vec_type], vec_type, t.params, cases); + await run(t, abstractIntBinary('*'), [Type.abstractInt, vec_type], vec_type, t.params, cases); }); g.test('multiplication_vector_scalar') @@ -181,9 +181,9 @@ Expression: x * y ) .fn(async t => { const vec_size = t.params.vectorize_lhs; - const vec_type = TypeVec(vec_size, TypeAbstractInt); + const vec_type = Type.vec(vec_size, Type.abstractInt); const cases = await d.get(`multiplication_vector${vec_size}_scalar`); - await run(t, abstractIntBinary('*'), [vec_type, TypeAbstractInt], vec_type, t.params, cases); + await run(t, abstractIntBinary('*'), [vec_type, Type.abstractInt], vec_type, t.params, cases); }); g.test('remainder') @@ -203,8 +203,8 @@ Expression: x % y await run( t, abstractIntBinary('%'), - [TypeAbstractInt, TypeAbstractInt], - TypeAbstractInt, + [Type.abstractInt, Type.abstractInt], + Type.abstractInt, t.params, cases ); @@ -222,9 +222,9 @@ Expression: x % y ) .fn(async t => { const vec_size = t.params.vectorize_rhs; - const vec_type = TypeVec(vec_size, TypeAbstractInt); + const vec_type = Type.vec(vec_size, Type.abstractInt); const cases = await d.get(`remainder_scalar_vector${vec_size}`); - await run(t, abstractIntBinary('%'), [TypeAbstractInt, vec_type], vec_type, t.params, cases); + await run(t, abstractIntBinary('%'), [Type.abstractInt, vec_type], vec_type, t.params, cases); }); g.test('remainder_vector_scalar') @@ -239,9 +239,9 @@ Expression: x % y ) .fn(async t => { const vec_size = t.params.vectorize_lhs; - const vec_type = TypeVec(vec_size, TypeAbstractInt); + const vec_type = Type.vec(vec_size, Type.abstractInt); const cases = await d.get(`remainder_vector${vec_size}_scalar`); - await run(t, abstractIntBinary('%'), [vec_type, TypeAbstractInt], vec_type, t.params, cases); + await run(t, abstractIntBinary('%'), [vec_type, Type.abstractInt], vec_type, t.params, cases); }); g.test('subtraction') @@ -261,8 +261,8 @@ Expression: x - y await run( t, abstractIntBinary('-'), - [TypeAbstractInt, TypeAbstractInt], - TypeAbstractInt, + [Type.abstractInt, Type.abstractInt], + Type.abstractInt, t.params, cases ); @@ -280,9 +280,9 @@ Expression: x - y ) .fn(async t => { const vec_size = t.params.vectorize_rhs; - const vec_type = TypeVec(vec_size, TypeAbstractInt); + const vec_type = Type.vec(vec_size, Type.abstractInt); const cases = await d.get(`subtraction_scalar_vector${vec_size}`); - await run(t, abstractIntBinary('-'), [TypeAbstractInt, vec_type], vec_type, t.params, cases); + await run(t, abstractIntBinary('-'), [Type.abstractInt, vec_type], vec_type, t.params, cases); }); g.test('subtraction_vector_scalar') @@ -297,7 +297,7 @@ Expression: x - y ) .fn(async t => { const vec_size = t.params.vectorize_lhs; - const vec_type = TypeVec(vec_size, TypeAbstractInt); + const vec_type = Type.vec(vec_size, Type.abstractInt); const cases = await d.get(`subtraction_vector${vec_size}_scalar`); - await run(t, abstractIntBinary('-'), [vec_type, TypeAbstractInt], vec_type, t.params, cases); + await run(t, abstractIntBinary('-'), [vec_type, Type.abstractInt], vec_type, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/binary/ai_comparison.spec.ts b/src/webgpu/shader/execution/expression/binary/ai_comparison.spec.ts index 9d00d0769c18..899e651054ef 100644 --- a/src/webgpu/shader/execution/expression/binary/ai_comparison.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/ai_comparison.spec.ts @@ -1,10 +1,10 @@ export const description = ` -Execution Tests for the abstract int comparison expressions +Execution Tests for the abstract-int comparison expressions `; import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeBool, TypeAbstractInt, bool, abstractInt } from '../../../../util/conversion.js'; +import { bool, abstractInt, Type } from '../../../../util/conversion.js'; import { vectorI64Range } from '../../../../util/math.js'; import { Case } from '../case.js'; import { onlyConstInputSource, run } from '../expression.js'; @@ -35,7 +35,7 @@ Expression: x == y ) .fn(async t => { const cases = vectorI64Range(2).map(v => makeCase(v[0], v[1], v[0] === v[1])); - await run(t, binary('=='), [TypeAbstractInt, TypeAbstractInt], TypeBool, t.params, cases); + await run(t, binary('=='), [Type.abstractInt, Type.abstractInt], Type.bool, t.params, cases); }); g.test('not_equals') @@ -52,7 +52,7 @@ Expression: x != y ) .fn(async t => { const cases = vectorI64Range(2).map(v => makeCase(v[0], v[1], v[0] !== v[1])); - await run(t, binary('!='), [TypeAbstractInt, TypeAbstractInt], TypeBool, t.params, cases); + await run(t, binary('!='), [Type.abstractInt, Type.abstractInt], Type.bool, t.params, cases); }); g.test('less_than') @@ -69,7 +69,7 @@ Expression: x < y ) .fn(async t => { const cases = vectorI64Range(2).map(v => makeCase(v[0], v[1], v[0] < v[1])); - await run(t, binary('<'), [TypeAbstractInt, TypeAbstractInt], TypeBool, t.params, cases); + await run(t, binary('<'), [Type.abstractInt, Type.abstractInt], Type.bool, t.params, cases); }); g.test('less_equals') @@ -86,7 +86,7 @@ Expression: x <= y ) .fn(async t => { const cases = vectorI64Range(2).map(v => makeCase(v[0], v[1], v[0] <= v[1])); - await run(t, binary('<='), [TypeAbstractInt, TypeAbstractInt], TypeBool, t.params, cases); + await run(t, binary('<='), [Type.abstractInt, Type.abstractInt], Type.bool, t.params, cases); }); g.test('greater_than') @@ -103,7 +103,7 @@ Expression: x > y ) .fn(async t => { const cases = vectorI64Range(2).map(v => makeCase(v[0], v[1], v[0] > v[1])); - await run(t, binary('>'), [TypeAbstractInt, TypeAbstractInt], TypeBool, t.params, cases); + await run(t, binary('>'), [Type.abstractInt, Type.abstractInt], Type.bool, t.params, cases); }); g.test('greater_equals') @@ -120,5 +120,5 @@ Expression: x >= y ) .fn(async t => { const cases = vectorI64Range(2).map(v => makeCase(v[0], v[1], v[0] >= v[1])); - await run(t, binary('>='), [TypeAbstractInt, TypeAbstractInt], TypeBool, t.params, cases); + await run(t, binary('>='), [Type.abstractInt, Type.abstractInt], Type.bool, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/binary/bitwise.spec.ts b/src/webgpu/shader/execution/expression/binary/bitwise.spec.ts index ead7258635c2..b6e9a45e9de8 100644 --- a/src/webgpu/shader/execution/expression/binary/bitwise.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/bitwise.spec.ts @@ -7,11 +7,9 @@ import { assert } from '../../../../../common/util/util.js'; import { GPUTest } from '../../../../gpu_test.js'; import { abstractIntBits, - i32, i32Bits, - Scalar, + ScalarValue, scalarType, - u32, u32Bits, } from '../../../../util/conversion.js'; import { allInputSources, onlyConstInputSource, run } from '../expression.js'; @@ -27,27 +25,27 @@ export const g = makeTestGroup(GPUTest); interface ScalarImpl { // builder is a mostly a wrapper around type builders like 'i32Bits' that // handles the (number|bigint) type check. - builder: (bits: bigint | number) => Scalar; + builder: (bits: bigint | number) => ScalarValue; size: 32 | 64; } const kScalarImpls = { i32: { - builder: (bits: bigint | number): Scalar => { + builder: (bits: bigint | number): ScalarValue => { assert(typeof bits === 'number'); return i32Bits(bits); }, size: 32, } as ScalarImpl, u32: { - builder: (bits: bigint | number): Scalar => { + builder: (bits: bigint | number): ScalarValue => { assert(typeof bits === 'number'); return u32Bits(bits); }, size: 32, } as ScalarImpl, 'abstract-int': { - builder: (bits: bigint | number): Scalar => { + builder: (bits: bigint | number): ScalarValue => { assert(typeof bits === 'bigint'); return abstractIntBits(bits); }, @@ -221,59 +219,137 @@ Bitwise-or. Component-wise when T is a vector. await run(t, compoundBinary('|='), [type, type], type, t.params, cases); }); -function makeBitwiseAndCases(inputType: string) { - const V = inputType === 'i32' ? i32 : u32; - const cases = [ - // Static patterns +/** Manually calculated bitwise-and cases used a check that the CTS test is correct */ +const kBitwiseAndStaticPatterns = { + 32: [ { - input: [V(0b00000000000000000000000000000000), V(0b00000000000000000000000000000000)], - expected: V(0b00000000000000000000000000000000), + input: [0b00000000000000000000000000000000, 0b00000000000000000000000000000000], + expected: 0b00000000000000000000000000000000, }, { - input: [V(0b11111111111111111111111111111111), V(0b00000000000000000000000000000000)], - expected: V(0b00000000000000000000000000000000), + input: [0b11111111111111111111111111111111, 0b00000000000000000000000000000000], + expected: 0b00000000000000000000000000000000, }, { - input: [V(0b00000000000000000000000000000000), V(0b11111111111111111111111111111111)], - expected: V(0b00000000000000000000000000000000), + input: [0b00000000000000000000000000000000, 0b11111111111111111111111111111111], + expected: 0b00000000000000000000000000000000, }, { - input: [V(0b11111111111111111111111111111111), V(0b11111111111111111111111111111111)], - expected: V(0b11111111111111111111111111111111), + input: [0b11111111111111111111111111111111, 0b11111111111111111111111111111111], + expected: 0b11111111111111111111111111111111, }, { - input: [V(0b10100100010010100100010010100100), V(0b00000000000000000000000000000000)], - expected: V(0b00000000000000000000000000000000), + input: [0b10100100010010100100010010100100, 0b00000000000000000000000000000000], + expected: 0b00000000000000000000000000000000, }, { - input: [V(0b10100100010010100100010010100100), V(0b11111111111111111111111111111111)], - expected: V(0b10100100010010100100010010100100), + input: [0b10100100010010100100010010100100, 0b11111111111111111111111111111111], + expected: 0b10100100010010100100010010100100, }, { - input: [V(0b00000000000000000000000000000000), V(0b10100100010010100100010010100100)], - expected: V(0b00000000000000000000000000000000), + input: [0b00000000000000000000000000000000, 0b10100100010010100100010010100100], + expected: 0b00000000000000000000000000000000, }, { - input: [V(0b11111111111111111111111111111111), V(0b10100100010010100100010010100100)], - expected: V(0b10100100010010100100010010100100), + input: [0b11111111111111111111111111111111, 0b10100100010010100100010010100100], + expected: 0b10100100010010100100010010100100, }, { - input: [V(0b01010010001001010010001001010010), V(0b01011011101101011011101101011011)], - expected: V(0b01010010001001010010001001010010), + input: [0b01010010001001010010001001010010, 0b01011011101101011011101101011011], + expected: 0b01010010001001010010001001010010, }, - ]; - // Permute all combinations of a single bit being set for the LHS and all but one bit set for the RHS - for (let i = 0; i < 32; i++) { - const lhs = 1 << i; - for (let j = 0; j < 32; j++) { - const rhs = 0xffffffff ^ (1 << j); - cases.push({ - input: [V(lhs), V(rhs)], - expected: V(lhs & rhs), + ], + 64: [ + { + input: [ + 0b0000000000000000000000000000000000000000000000000000000000000000n, + 0b0000000000000000000000000000000000000000000000000000000000000000n, + ], + expected: 0b0000000000000000000000000000000000000000000000000000000000000000n, + }, + { + input: [ + 0b1111111111111111111111111111111111111111111111111111111111111111n, + 0b0000000000000000000000000000000000000000000000000000000000000000n, + ], + expected: 0b0000000000000000000000000000000000000000000000000000000000000000n, + }, + { + input: [ + 0b0000000000000000000000000000000000000000000000000000000000000000n, + 0b1111111111111111111111111111111111111111111111111111111111111111n, + ], + expected: 0b0000000000000000000000000000000000000000000000000000000000000000n, + }, + { + input: [ + 0b1111111111111111111111111111111111111111111111111111111111111111n, + 0b1111111111111111111111111111111111111111111111111111111111111111n, + ], + expected: 0b1111111111111111111111111111111111111111111111111111111111111111n, + }, + { + input: [ + 0b1010010001001010010001001010010010100100010010100100010010100100n, + 0b0000000000000000000000000000000000000000000000000000000000000000n, + ], + expected: 0b0000000000000000000000000000000000000000000000000000000000000000n, + }, + { + input: [ + 0b1010010001001010010001001010010010100100010010100100010010100100n, + 0b1111111111111111111111111111111111111111111111111111111111111111n, + ], + expected: 0b1010010001001010010001001010010010100100010010100100010010100100n, + }, + { + input: [ + 0b0000000000000000000000000000000000000000000000000000000000000000n, + 0b1010010001001010010001001010010010100100010010100100010010100100n, + ], + expected: 0b0000000000000000000000000000000000000000000000000000000000000000n, + }, + { + input: [ + 0b1111111111111111111111111111111111111111111111111111111111111111n, + 0b1010010001001010010001001010010010100100010010100100010010100100n, + ], + expected: 0b1010010001001010010001001010010010100100010010100100010010100100n, + }, + { + input: [ + 0b0101001000100101001000100101001001010010001001010010001001010010n, + 0b0101101110110101101110110101101101011011101101011011101101011011n, + ], + expected: 0b0101001000100101001000100101001001010010001001010010001001010010n, + }, + ], +}; + +/** @returns a set of bitwise-or cases for the specific input type */ +function makeBitwiseAndCases(inputType: string) { + const impl = scalarImplForInputType(inputType); + const indices = + impl.size === 64 ? [...Array(impl.size).keys()].map(BigInt) : [...Array(impl.size).keys()]; + + return [ + ...kBitwiseAndStaticPatterns[impl.size].map(c => { + return { + input: c.input.map(impl.builder), + expected: impl.builder(c.expected), + }; + }), + // Permute all combinations of a single bit being set for the LHS and all but one bit set for the RHS + ...indices.flatMap(i => { + const lhs = typeof i === 'bigint' ? 1n << i : 1 << i; + return indices.map(j => { + const rhs = typeof j === 'bigint' ? 0xffffffffffffffffn ^ (1n << j) : 0xffffffff ^ (1 << j); + assert(typeof lhs === typeof rhs); + const result = typeof lhs === 'bigint' ? lhs & (rhs as bigint) : lhs & (rhs as number); + return { input: [impl.builder(lhs), impl.builder(rhs)], expected: impl.builder(result) }; }); - } - } - return cases; + }), + ]; } g.test('bitwise_and') @@ -281,21 +357,25 @@ g.test('bitwise_and') .desc( ` e1 & e2: T -T is i32, u32, vecN, or vecN +T is i32, u32, AbstractInt, vecN, vecN, or vecN Bitwise-and. Component-wise when T is a vector. ` ) .params(u => u - .combine('type', ['i32', 'u32'] as const) + .combine('type', ['i32', 'u32', 'abstract-int'] as const) .combine('inputSource', allInputSources) .combine('vectorize', [undefined, 2, 3, 4] as const) ) .fn(async t => { + t.skipIf( + t.params.type === 'abstract-int' && !onlyConstInputSource.includes(t.params.inputSource) + ); const type = scalarType(t.params.type); const cases = makeBitwiseAndCases(t.params.type); - await run(t, binary('&'), [type, type], type, t.params, cases); + const builder = t.params.type === 'abstract-int' ? abstractIntBinary('&') : binary('&'); + await run(t, builder, [type, type], type, t.params, cases); }); g.test('bitwise_and_compound') diff --git a/src/webgpu/shader/execution/expression/binary/bitwise_shift.spec.ts b/src/webgpu/shader/execution/expression/binary/bitwise_shift.spec.ts index cea6b86c602a..e2ed29d3c2ff 100644 --- a/src/webgpu/shader/execution/expression/binary/bitwise_shift.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/bitwise_shift.spec.ts @@ -4,7 +4,7 @@ Execution Tests for the bitwise shift binary expression operations import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { i32, scalarType, ScalarType, TypeU32, u32 } from '../../../../util/conversion.js'; +import { i32, scalarType, ScalarType, Type, u32 } from '../../../../util/conversion.js'; import { Case } from '../case.js'; import { allInputSources, run } from '../expression.js'; @@ -194,7 +194,7 @@ Shift left (shifted value is concrete) .fn(async t => { const type = scalarType(t.params.type); const cases = makeShiftLeftConcreteCases(t.params.type, t.params.inputSource, type); - await run(t, binary('<<'), [type, TypeU32], type, t.params, cases); + await run(t, binary('<<'), [type, Type.u32], type, t.params, cases); }); g.test('shift_left_concrete_compound') @@ -215,7 +215,7 @@ Shift left (shifted value is concrete) .fn(async t => { const type = scalarType(t.params.type); const cases = makeShiftLeftConcreteCases(t.params.type, t.params.inputSource, type); - await run(t, compoundBinary('<<='), [type, TypeU32], type, t.params, cases); + await run(t, compoundBinary('<<='), [type, Type.u32], type, t.params, cases); }); function makeShiftRightConcreteCases(inputType: string, inputSource: string, type: ScalarType) { @@ -319,7 +319,7 @@ Shift right (shifted value is concrete) .fn(async t => { const type = scalarType(t.params.type); const cases = makeShiftRightConcreteCases(t.params.type, t.params.inputSource, type); - await run(t, binary('>>'), [type, TypeU32], type, t.params, cases); + await run(t, binary('>>'), [type, Type.u32], type, t.params, cases); }); g.test('shift_right_concrete_compound') @@ -340,5 +340,5 @@ Shift right (shifted value is concrete) .fn(async t => { const type = scalarType(t.params.type); const cases = makeShiftRightConcreteCases(t.params.type, t.params.inputSource, type); - await run(t, compoundBinary('>>='), [type, TypeU32], type, t.params, cases); + await run(t, compoundBinary('>>='), [type, Type.u32], type, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/binary/bool_logical.spec.ts b/src/webgpu/shader/execution/expression/binary/bool_logical.spec.ts index e3aa448fe3c4..0e76f508240c 100644 --- a/src/webgpu/shader/execution/expression/binary/bool_logical.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/bool_logical.spec.ts @@ -4,7 +4,7 @@ Execution Tests for the boolean binary logical expression operations import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { bool, TypeBool } from '../../../../util/conversion.js'; +import { bool, Type } from '../../../../util/conversion.js'; import { allInputSources, run } from '../expression.js'; import { binary, compoundBinary } from './binary.js'; @@ -33,7 +33,7 @@ Logical "and". Component-wise when T is a vector. Evaluates both e1 and e2. { input: [bool(true), bool(true)], expected: bool(true) }, ]; - await run(t, binary('&'), [TypeBool, TypeBool], TypeBool, t.params, cases); + await run(t, binary('&'), [Type.bool, Type.bool], Type.bool, t.params, cases); }); g.test('and_compound') @@ -55,7 +55,7 @@ Logical "and". Component-wise when T is a vector. Evaluates both e1 and e2. { input: [bool(true), bool(true)], expected: bool(true) }, ]; - await run(t, compoundBinary('&='), [TypeBool, TypeBool], TypeBool, t.params, cases); + await run(t, compoundBinary('&='), [Type.bool, Type.bool], Type.bool, t.params, cases); }); g.test('and_short_circuit') @@ -75,7 +75,7 @@ short_circuiting "and". Yields true if both e1 and e2 are true; evaluates e2 onl { input: [bool(true), bool(true)], expected: bool(true) }, ]; - await run(t, binary('&&'), [TypeBool, TypeBool], TypeBool, t.params, cases); + await run(t, binary('&&'), [Type.bool, Type.bool], Type.bool, t.params, cases); }); g.test('or') @@ -97,7 +97,7 @@ Logical "or". Component-wise when T is a vector. Evaluates both e1 and e2. { input: [bool(true), bool(true)], expected: bool(true) }, ]; - await run(t, binary('|'), [TypeBool, TypeBool], TypeBool, t.params, cases); + await run(t, binary('|'), [Type.bool, Type.bool], Type.bool, t.params, cases); }); g.test('or_compound') @@ -119,7 +119,7 @@ Logical "or". Component-wise when T is a vector. Evaluates both e1 and e2. { input: [bool(true), bool(true)], expected: bool(true) }, ]; - await run(t, compoundBinary('|='), [TypeBool, TypeBool], TypeBool, t.params, cases); + await run(t, compoundBinary('|='), [Type.bool, Type.bool], Type.bool, t.params, cases); }); g.test('or_short_circuit') @@ -139,7 +139,7 @@ short_circuiting "and". Yields true if both e1 and e2 are true; evaluates e2 onl { input: [bool(true), bool(true)], expected: bool(true) }, ]; - await run(t, binary('||'), [TypeBool, TypeBool], TypeBool, t.params, cases); + await run(t, binary('||'), [Type.bool, Type.bool], Type.bool, t.params, cases); }); g.test('equals') @@ -161,7 +161,7 @@ Equality. Component-wise when T is a vector. { input: [bool(true), bool(true)], expected: bool(true) }, ]; - await run(t, binary('=='), [TypeBool, TypeBool], TypeBool, t.params, cases); + await run(t, binary('=='), [Type.bool, Type.bool], Type.bool, t.params, cases); }); g.test('not_equals') @@ -183,5 +183,5 @@ Equality. Component-wise when T is a vector. { input: [bool(true), bool(true)], expected: bool(false) }, ]; - await run(t, binary('!='), [TypeBool, TypeBool], TypeBool, t.params, cases); + await run(t, binary('!='), [Type.bool, Type.bool], Type.bool, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/binary/f16_addition.spec.ts b/src/webgpu/shader/execution/expression/binary/f16_addition.spec.ts index 7f94c7e307a9..d9aa44bba0e2 100644 --- a/src/webgpu/shader/execution/expression/binary/f16_addition.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/f16_addition.spec.ts @@ -4,7 +4,7 @@ Execution Tests for non-matrix f16 addition expression import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeF16, TypeVec } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { allInputSources, run } from '../expression.js'; import { binary, compoundBinary } from './binary.js'; @@ -28,7 +28,7 @@ Accuracy: Correctly rounded const cases = await d.get( t.params.inputSource === 'const' ? 'scalar_const' : 'scalar_non_const' ); - await run(t, binary('+'), [TypeF16, TypeF16], TypeF16, t.params, cases); + await run(t, binary('+'), [Type.f16, Type.f16], Type.f16, t.params, cases); }); g.test('vector') @@ -47,7 +47,7 @@ Accuracy: Correctly rounded const cases = await d.get( t.params.inputSource === 'const' ? 'scalar_const' : 'scalar_non_const' // Using vectorize to generate vector cases based on scalar cases ); - await run(t, binary('+'), [TypeF16, TypeF16], TypeF16, t.params, cases); + await run(t, binary('+'), [Type.f16, Type.f16], Type.f16, t.params, cases); }); g.test('scalar_compound') @@ -68,7 +68,7 @@ Accuracy: Correctly rounded const cases = await d.get( t.params.inputSource === 'const' ? 'scalar_const' : 'scalar_non_const' ); - await run(t, compoundBinary('+='), [TypeF16, TypeF16], TypeF16, t.params, cases); + await run(t, compoundBinary('+='), [Type.f16, Type.f16], Type.f16, t.params, cases); }); g.test('vector_scalar') @@ -91,8 +91,8 @@ Accuracy: Correctly rounded await run( t, binary('+'), - [TypeVec(dim, TypeF16), TypeF16], - TypeVec(dim, TypeF16), + [Type.vec(dim, Type.f16), Type.f16], + Type.vec(dim, Type.f16), t.params, cases ); @@ -118,8 +118,8 @@ Accuracy: Correctly rounded await run( t, compoundBinary('+='), - [TypeVec(dim, TypeF16), TypeF16], - TypeVec(dim, TypeF16), + [Type.vec(dim, Type.f16), Type.f16], + Type.vec(dim, Type.f16), t.params, cases ); @@ -145,8 +145,8 @@ Accuracy: Correctly rounded await run( t, binary('+'), - [TypeF16, TypeVec(dim, TypeF16)], - TypeVec(dim, TypeF16), + [Type.f16, Type.vec(dim, Type.f16)], + Type.vec(dim, Type.f16), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/binary/f16_comparison.cache.ts b/src/webgpu/shader/execution/expression/binary/f16_comparison.cache.ts index 92d926a412b9..c0c0d4f8a4a6 100644 --- a/src/webgpu/shader/execution/expression/binary/f16_comparison.cache.ts +++ b/src/webgpu/shader/execution/expression/binary/f16_comparison.cache.ts @@ -1,5 +1,5 @@ import { anyOf } from '../../../../util/compare.js'; -import { bool, f16, Scalar } from '../../../../util/conversion.js'; +import { bool, f16, ScalarValue } from '../../../../util/conversion.js'; import { flushSubnormalNumberF16, vectorF16Range } from '../../../../util/math.js'; import { Case } from '../case.js'; import { makeCaseCache } from '../case_cache.js'; @@ -11,7 +11,7 @@ import { makeCaseCache } from '../case_cache.js'; function makeCase( lhs: number, rhs: number, - truthFunc: (lhs: Scalar, rhs: Scalar) => boolean + truthFunc: (lhs: ScalarValue, rhs: ScalarValue) => boolean ): Case { // Subnormal float values may be flushed at any time. // https://www.w3.org/TR/WGSL/#floating-point-evaluation @@ -19,7 +19,7 @@ function makeCase( const f16_rhs = f16(rhs); const lhs_options = new Set([f16_lhs, f16(flushSubnormalNumberF16(lhs))]); const rhs_options = new Set([f16_rhs, f16(flushSubnormalNumberF16(rhs))]); - const expected: Array = []; + const expected: Array = []; lhs_options.forEach(l => { rhs_options.forEach(r => { const result = bool(truthFunc(l, r)); @@ -34,7 +34,7 @@ function makeCase( export const d = makeCaseCache('binary/f16_logical', { equals_non_const: () => { - const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + const truthFunc = (lhs: ScalarValue, rhs: ScalarValue): boolean => { return (lhs.value as number) === (rhs.value as number); }; @@ -43,7 +43,7 @@ export const d = makeCaseCache('binary/f16_logical', { }); }, equals_const: () => { - const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + const truthFunc = (lhs: ScalarValue, rhs: ScalarValue): boolean => { return (lhs.value as number) === (rhs.value as number); }; @@ -52,7 +52,7 @@ export const d = makeCaseCache('binary/f16_logical', { }); }, not_equals_non_const: () => { - const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + const truthFunc = (lhs: ScalarValue, rhs: ScalarValue): boolean => { return (lhs.value as number) !== (rhs.value as number); }; @@ -61,7 +61,7 @@ export const d = makeCaseCache('binary/f16_logical', { }); }, not_equals_const: () => { - const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + const truthFunc = (lhs: ScalarValue, rhs: ScalarValue): boolean => { return (lhs.value as number) !== (rhs.value as number); }; @@ -70,7 +70,7 @@ export const d = makeCaseCache('binary/f16_logical', { }); }, less_than_non_const: () => { - const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + const truthFunc = (lhs: ScalarValue, rhs: ScalarValue): boolean => { return (lhs.value as number) < (rhs.value as number); }; @@ -79,7 +79,7 @@ export const d = makeCaseCache('binary/f16_logical', { }); }, less_than_const: () => { - const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + const truthFunc = (lhs: ScalarValue, rhs: ScalarValue): boolean => { return (lhs.value as number) < (rhs.value as number); }; @@ -88,7 +88,7 @@ export const d = makeCaseCache('binary/f16_logical', { }); }, less_equals_non_const: () => { - const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + const truthFunc = (lhs: ScalarValue, rhs: ScalarValue): boolean => { return (lhs.value as number) <= (rhs.value as number); }; @@ -97,7 +97,7 @@ export const d = makeCaseCache('binary/f16_logical', { }); }, less_equals_const: () => { - const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + const truthFunc = (lhs: ScalarValue, rhs: ScalarValue): boolean => { return (lhs.value as number) <= (rhs.value as number); }; @@ -106,7 +106,7 @@ export const d = makeCaseCache('binary/f16_logical', { }); }, greater_than_non_const: () => { - const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + const truthFunc = (lhs: ScalarValue, rhs: ScalarValue): boolean => { return (lhs.value as number) > (rhs.value as number); }; @@ -115,7 +115,7 @@ export const d = makeCaseCache('binary/f16_logical', { }); }, greater_than_const: () => { - const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + const truthFunc = (lhs: ScalarValue, rhs: ScalarValue): boolean => { return (lhs.value as number) > (rhs.value as number); }; @@ -124,7 +124,7 @@ export const d = makeCaseCache('binary/f16_logical', { }); }, greater_equals_non_const: () => { - const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + const truthFunc = (lhs: ScalarValue, rhs: ScalarValue): boolean => { return (lhs.value as number) >= (rhs.value as number); }; @@ -133,7 +133,7 @@ export const d = makeCaseCache('binary/f16_logical', { }); }, greater_equals_const: () => { - const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + const truthFunc = (lhs: ScalarValue, rhs: ScalarValue): boolean => { return (lhs.value as number) >= (rhs.value as number); }; diff --git a/src/webgpu/shader/execution/expression/binary/f16_comparison.spec.ts b/src/webgpu/shader/execution/expression/binary/f16_comparison.spec.ts index c84080983de5..b978cd3c99fe 100644 --- a/src/webgpu/shader/execution/expression/binary/f16_comparison.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/f16_comparison.spec.ts @@ -4,7 +4,7 @@ Execution Tests for the f16 comparison operations import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeBool, TypeF16 } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { allInputSources, run } from '../expression.js'; import { binary } from './binary.js'; @@ -30,7 +30,7 @@ Accuracy: Correct result const cases = await d.get( t.params.inputSource === 'const' ? 'equals_const' : 'equals_non_const' ); - await run(t, binary('=='), [TypeF16, TypeF16], TypeBool, t.params, cases); + await run(t, binary('=='), [Type.f16, Type.f16], Type.bool, t.params, cases); }); g.test('not_equals') @@ -51,7 +51,7 @@ Accuracy: Correct result const cases = await d.get( t.params.inputSource === 'const' ? 'not_equals_const' : 'not_equals_non_const' ); - await run(t, binary('!='), [TypeF16, TypeF16], TypeBool, t.params, cases); + await run(t, binary('!='), [Type.f16, Type.f16], Type.bool, t.params, cases); }); g.test('less_than') @@ -72,7 +72,7 @@ Accuracy: Correct result const cases = await d.get( t.params.inputSource === 'const' ? 'less_than_const' : 'less_than_non_const' ); - await run(t, binary('<'), [TypeF16, TypeF16], TypeBool, t.params, cases); + await run(t, binary('<'), [Type.f16, Type.f16], Type.bool, t.params, cases); }); g.test('less_equals') @@ -93,7 +93,7 @@ Accuracy: Correct result const cases = await d.get( t.params.inputSource === 'const' ? 'less_equals_const' : 'less_equals_non_const' ); - await run(t, binary('<='), [TypeF16, TypeF16], TypeBool, t.params, cases); + await run(t, binary('<='), [Type.f16, Type.f16], Type.bool, t.params, cases); }); g.test('greater_than') @@ -114,7 +114,7 @@ Accuracy: Correct result const cases = await d.get( t.params.inputSource === 'const' ? 'greater_than_const' : 'greater_than_non_const' ); - await run(t, binary('>'), [TypeF16, TypeF16], TypeBool, t.params, cases); + await run(t, binary('>'), [Type.f16, Type.f16], Type.bool, t.params, cases); }); g.test('greater_equals') @@ -135,5 +135,5 @@ Accuracy: Correct result const cases = await d.get( t.params.inputSource === 'const' ? 'greater_equals_const' : 'greater_equals_non_const' ); - await run(t, binary('>='), [TypeF16, TypeF16], TypeBool, t.params, cases); + await run(t, binary('>='), [Type.f16, Type.f16], Type.bool, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/binary/f16_division.spec.ts b/src/webgpu/shader/execution/expression/binary/f16_division.spec.ts index 7dfc13f81a2f..8a155024db98 100644 --- a/src/webgpu/shader/execution/expression/binary/f16_division.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/f16_division.spec.ts @@ -4,7 +4,7 @@ Execution Tests for non-matrix f16 division expression import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeF16, TypeVec } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { allInputSources, run } from '../expression.js'; import { binary, compoundBinary } from './binary.js'; @@ -28,7 +28,7 @@ Accuracy: 2.5 ULP for |y| in the range [2^-126, 2^126] const cases = await d.get( t.params.inputSource === 'const' ? 'scalar_const' : 'scalar_non_const' ); - await run(t, binary('/'), [TypeF16, TypeF16], TypeF16, t.params, cases); + await run(t, binary('/'), [Type.f16, Type.f16], Type.f16, t.params, cases); }); g.test('vector') @@ -47,7 +47,7 @@ Accuracy: 2.5 ULP for |y| in the range [2^-126, 2^126] const cases = await d.get( t.params.inputSource === 'const' ? 'scalar_const' : 'scalar_non_const' // Using vectorize to generate vector cases based on scalar cases ); - await run(t, binary('/'), [TypeF16, TypeF16], TypeF16, t.params, cases); + await run(t, binary('/'), [Type.f16, Type.f16], Type.f16, t.params, cases); }); g.test('scalar_compound') @@ -68,7 +68,7 @@ Accuracy: 2.5 ULP for |y| in the range [2^-126, 2^126] const cases = await d.get( t.params.inputSource === 'const' ? 'scalar_const' : 'scalar_non_const' ); - await run(t, compoundBinary('/='), [TypeF16, TypeF16], TypeF16, t.params, cases); + await run(t, compoundBinary('/='), [Type.f16, Type.f16], Type.f16, t.params, cases); }); g.test('vector_scalar') @@ -91,8 +91,8 @@ Accuracy: Correctly rounded await run( t, binary('/'), - [TypeVec(dim, TypeF16), TypeF16], - TypeVec(dim, TypeF16), + [Type.vec(dim, Type.f16), Type.f16], + Type.vec(dim, Type.f16), t.params, cases ); @@ -118,8 +118,8 @@ Accuracy: Correctly rounded await run( t, compoundBinary('/='), - [TypeVec(dim, TypeF16), TypeF16], - TypeVec(dim, TypeF16), + [Type.vec(dim, Type.f16), Type.f16], + Type.vec(dim, Type.f16), t.params, cases ); @@ -145,8 +145,8 @@ Accuracy: Correctly rounded await run( t, binary('/'), - [TypeF16, TypeVec(dim, TypeF16)], - TypeVec(dim, TypeF16), + [Type.f16, Type.vec(dim, Type.f16)], + Type.vec(dim, Type.f16), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/binary/f16_matrix_addition.spec.ts b/src/webgpu/shader/execution/expression/binary/f16_matrix_addition.spec.ts index daf768a5365c..7c34b0cadd87 100644 --- a/src/webgpu/shader/execution/expression/binary/f16_matrix_addition.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/f16_matrix_addition.spec.ts @@ -4,7 +4,7 @@ Execution Tests for matrix f16 addition expression import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeF16, TypeMat } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { allInputSources, run } from '../expression.js'; import { binary, compoundBinary } from './binary.js'; @@ -38,8 +38,8 @@ Accuracy: Correctly rounded await run( t, binary('+'), - [TypeMat(cols, rows, TypeF16), TypeMat(cols, rows, TypeF16)], - TypeMat(cols, rows, TypeF16), + [Type.mat(cols, rows, Type.f16), Type.mat(cols, rows, Type.f16)], + Type.mat(cols, rows, Type.f16), t.params, cases ); @@ -71,8 +71,8 @@ Accuracy: Correctly rounded await run( t, compoundBinary('+='), - [TypeMat(cols, rows, TypeF16), TypeMat(cols, rows, TypeF16)], - TypeMat(cols, rows, TypeF16), + [Type.mat(cols, rows, Type.f16), Type.mat(cols, rows, Type.f16)], + Type.mat(cols, rows, Type.f16), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/binary/f16_matrix_matrix_multiplication.spec.ts b/src/webgpu/shader/execution/expression/binary/f16_matrix_matrix_multiplication.spec.ts index 69c56c60c368..80ca78f7f5bd 100644 --- a/src/webgpu/shader/execution/expression/binary/f16_matrix_matrix_multiplication.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/f16_matrix_matrix_multiplication.spec.ts @@ -4,7 +4,7 @@ Execution Tests for matrix-matrix f16 multiplication expression import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeF16, TypeMat } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { allInputSources, run } from '../expression.js'; import { binary, compoundBinary } from './binary.js'; @@ -44,8 +44,8 @@ Accuracy: Correctly rounded await run( t, binary('*'), - [TypeMat(x_cols, x_rows, TypeF16), TypeMat(y_cols, y_rows, TypeF16)], - TypeMat(y_cols, x_rows, TypeF16), + [Type.mat(x_cols, x_rows, Type.f16), Type.mat(y_cols, y_rows, Type.f16)], + Type.mat(y_cols, x_rows, Type.f16), t.params, cases ); @@ -82,8 +82,8 @@ Accuracy: Correctly rounded await run( t, compoundBinary('*='), - [TypeMat(x_cols, x_rows, TypeF16), TypeMat(y_cols, y_rows, TypeF16)], - TypeMat(y_cols, x_rows, TypeF16), + [Type.mat(x_cols, x_rows, Type.f16), Type.mat(y_cols, y_rows, Type.f16)], + Type.mat(y_cols, x_rows, Type.f16), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/binary/f16_matrix_scalar_multiplication.spec.ts b/src/webgpu/shader/execution/expression/binary/f16_matrix_scalar_multiplication.spec.ts index 338d6d021bb5..aa7087738a5e 100644 --- a/src/webgpu/shader/execution/expression/binary/f16_matrix_scalar_multiplication.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/f16_matrix_scalar_multiplication.spec.ts @@ -4,7 +4,7 @@ Execution Tests for matrix-scalar and scalar-matrix f16 multiplication expressio import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeF16, TypeMat } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { allInputSources, run } from '../expression.js'; import { binary, compoundBinary } from './binary.js'; @@ -40,8 +40,8 @@ Accuracy: Correctly rounded await run( t, binary('*'), - [TypeMat(cols, rows, TypeF16), TypeF16], - TypeMat(cols, rows, TypeF16), + [Type.mat(cols, rows, Type.f16), Type.f16], + Type.mat(cols, rows, Type.f16), t.params, cases ); @@ -75,8 +75,8 @@ Accuracy: Correctly rounded await run( t, compoundBinary('*='), - [TypeMat(cols, rows, TypeF16), TypeF16], - TypeMat(cols, rows, TypeF16), + [Type.mat(cols, rows, Type.f16), Type.f16], + Type.mat(cols, rows, Type.f16), t.params, cases ); @@ -110,8 +110,8 @@ Accuracy: Correctly rounded await run( t, binary('*'), - [TypeF16, TypeMat(cols, rows, TypeF16)], - TypeMat(cols, rows, TypeF16), + [Type.f16, Type.mat(cols, rows, Type.f16)], + Type.mat(cols, rows, Type.f16), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/binary/f16_matrix_subtraction.spec.ts b/src/webgpu/shader/execution/expression/binary/f16_matrix_subtraction.spec.ts index 442c31ef82e9..e8e13d902a0e 100644 --- a/src/webgpu/shader/execution/expression/binary/f16_matrix_subtraction.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/f16_matrix_subtraction.spec.ts @@ -4,7 +4,7 @@ Execution Tests for matrix f16 subtraction expression import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeF16, TypeMat } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { allInputSources, run } from '../expression.js'; import { binary, compoundBinary } from './binary.js'; @@ -38,8 +38,8 @@ Accuracy: Correctly rounded await run( t, binary('-'), - [TypeMat(cols, rows, TypeF16), TypeMat(cols, rows, TypeF16)], - TypeMat(cols, rows, TypeF16), + [Type.mat(cols, rows, Type.f16), Type.mat(cols, rows, Type.f16)], + Type.mat(cols, rows, Type.f16), t.params, cases ); @@ -71,8 +71,8 @@ Accuracy: Correctly rounded await run( t, compoundBinary('-='), - [TypeMat(cols, rows, TypeF16), TypeMat(cols, rows, TypeF16)], - TypeMat(cols, rows, TypeF16), + [Type.mat(cols, rows, Type.f16), Type.mat(cols, rows, Type.f16)], + Type.mat(cols, rows, Type.f16), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/binary/f16_matrix_vector_multiplication.spec.ts b/src/webgpu/shader/execution/expression/binary/f16_matrix_vector_multiplication.spec.ts index 9715fe681e35..557a7cead847 100644 --- a/src/webgpu/shader/execution/expression/binary/f16_matrix_vector_multiplication.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/f16_matrix_vector_multiplication.spec.ts @@ -4,7 +4,7 @@ Execution Tests for matrix-vector and vector-matrix f16 multiplication expressio import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeF16, TypeMat, TypeVec } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { allInputSources, run } from '../expression.js'; import { binary, compoundBinary } from './binary.js'; @@ -40,8 +40,8 @@ Accuracy: Correctly rounded await run( t, binary('*'), - [TypeMat(cols, rows, TypeF16), TypeVec(cols, TypeF16)], - TypeVec(rows, TypeF16), + [Type.mat(cols, rows, Type.f16), Type.vec(cols, Type.f16)], + Type.vec(rows, Type.f16), t.params, cases ); @@ -75,8 +75,8 @@ Accuracy: Correctly rounded await run( t, binary('*'), - [TypeVec(rows, TypeF16), TypeMat(cols, rows, TypeF16)], - TypeVec(cols, TypeF16), + [Type.vec(rows, Type.f16), Type.mat(cols, rows, Type.f16)], + Type.vec(cols, Type.f16), t.params, cases ); @@ -105,8 +105,8 @@ Accuracy: Correctly rounded await run( t, compoundBinary('*='), - [TypeVec(rows, TypeF16), TypeMat(cols, rows, TypeF16)], - TypeVec(cols, TypeF16), + [Type.vec(rows, Type.f16), Type.mat(cols, rows, Type.f16)], + Type.vec(cols, Type.f16), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/binary/f16_multiplication.spec.ts b/src/webgpu/shader/execution/expression/binary/f16_multiplication.spec.ts index 005a9a1e64af..81339d9266b5 100644 --- a/src/webgpu/shader/execution/expression/binary/f16_multiplication.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/f16_multiplication.spec.ts @@ -4,7 +4,7 @@ Execution Tests for non-matrix f16 multiplication expression import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeF16, TypeVec } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { allInputSources, run } from '../expression.js'; import { binary, compoundBinary } from './binary.js'; @@ -28,7 +28,7 @@ Accuracy: Correctly rounded const cases = await d.get( t.params.inputSource === 'const' ? 'scalar_const' : 'scalar_non_const' ); - await run(t, binary('*'), [TypeF16, TypeF16], TypeF16, t.params, cases); + await run(t, binary('*'), [Type.f16, Type.f16], Type.f16, t.params, cases); }); g.test('vector') @@ -47,7 +47,7 @@ Accuracy: Correctly rounded const cases = await d.get( t.params.inputSource === 'const' ? 'scalar_const' : 'scalar_non_const' // Using vectorize to generate vector cases based on scalar cases ); - await run(t, binary('*'), [TypeF16, TypeF16], TypeF16, t.params, cases); + await run(t, binary('*'), [Type.f16, Type.f16], Type.f16, t.params, cases); }); g.test('scalar_compound') @@ -68,7 +68,7 @@ Accuracy: Correctly rounded const cases = await d.get( t.params.inputSource === 'const' ? 'scalar_const' : 'scalar_non_const' ); - await run(t, compoundBinary('*='), [TypeF16, TypeF16], TypeF16, t.params, cases); + await run(t, compoundBinary('*='), [Type.f16, Type.f16], Type.f16, t.params, cases); }); g.test('vector_scalar') @@ -91,8 +91,8 @@ Accuracy: Correctly rounded await run( t, binary('*'), - [TypeVec(dim, TypeF16), TypeF16], - TypeVec(dim, TypeF16), + [Type.vec(dim, Type.f16), Type.f16], + Type.vec(dim, Type.f16), t.params, cases ); @@ -118,8 +118,8 @@ Accuracy: Correctly rounded await run( t, compoundBinary('*='), - [TypeVec(dim, TypeF16), TypeF16], - TypeVec(dim, TypeF16), + [Type.vec(dim, Type.f16), Type.f16], + Type.vec(dim, Type.f16), t.params, cases ); @@ -145,8 +145,8 @@ Accuracy: Correctly rounded await run( t, binary('*'), - [TypeF16, TypeVec(dim, TypeF16)], - TypeVec(dim, TypeF16), + [Type.f16, Type.vec(dim, Type.f16)], + Type.vec(dim, Type.f16), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/binary/f16_remainder.spec.ts b/src/webgpu/shader/execution/expression/binary/f16_remainder.spec.ts index c2f5cd7af11f..0fe1cc53c662 100644 --- a/src/webgpu/shader/execution/expression/binary/f16_remainder.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/f16_remainder.spec.ts @@ -4,7 +4,7 @@ Execution Tests for non-matrix f16 remainder expression import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeF16, TypeVec } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { allInputSources, run } from '../expression.js'; import { binary, compoundBinary } from './binary.js'; @@ -28,7 +28,7 @@ Accuracy: Derived from x - y * trunc(x/y) const cases = await d.get( t.params.inputSource === 'const' ? 'scalar_const' : 'scalar_non_const' ); - await run(t, binary('%'), [TypeF16, TypeF16], TypeF16, t.params, cases); + await run(t, binary('%'), [Type.f16, Type.f16], Type.f16, t.params, cases); }); g.test('vector') @@ -47,7 +47,7 @@ Accuracy: Derived from x - y * trunc(x/y) const cases = await d.get( t.params.inputSource === 'const' ? 'scalar_const' : 'scalar_non_const' ); - await run(t, binary('%'), [TypeF16, TypeF16], TypeF16, t.params, cases); + await run(t, binary('%'), [Type.f16, Type.f16], Type.f16, t.params, cases); }); g.test('scalar_compound') @@ -68,7 +68,7 @@ Accuracy: Derived from x - y * trunc(x/y) const cases = await d.get( t.params.inputSource === 'const' ? 'scalar_const' : 'scalar_non_const' ); - await run(t, compoundBinary('%='), [TypeF16, TypeF16], TypeF16, t.params, cases); + await run(t, compoundBinary('%='), [Type.f16, Type.f16], Type.f16, t.params, cases); }); g.test('vector_scalar') @@ -91,8 +91,8 @@ Accuracy: Correctly rounded await run( t, binary('%'), - [TypeVec(dim, TypeF16), TypeF16], - TypeVec(dim, TypeF16), + [Type.vec(dim, Type.f16), Type.f16], + Type.vec(dim, Type.f16), t.params, cases ); @@ -118,8 +118,8 @@ Accuracy: Correctly rounded await run( t, compoundBinary('%='), - [TypeVec(dim, TypeF16), TypeF16], - TypeVec(dim, TypeF16), + [Type.vec(dim, Type.f16), Type.f16], + Type.vec(dim, Type.f16), t.params, cases ); @@ -145,8 +145,8 @@ Accuracy: Correctly rounded await run( t, binary('%'), - [TypeF16, TypeVec(dim, TypeF16)], - TypeVec(dim, TypeF16), + [Type.f16, Type.vec(dim, Type.f16)], + Type.vec(dim, Type.f16), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/binary/f16_subtraction.spec.ts b/src/webgpu/shader/execution/expression/binary/f16_subtraction.spec.ts index a458885ae8ce..6b29aad6ad78 100644 --- a/src/webgpu/shader/execution/expression/binary/f16_subtraction.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/f16_subtraction.spec.ts @@ -4,7 +4,7 @@ Execution Tests for non-matrix f16 subtraction expression import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeF16, TypeVec } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { allInputSources, run } from '../expression.js'; import { binary, compoundBinary } from './binary.js'; @@ -28,7 +28,7 @@ Accuracy: Correctly rounded const cases = await d.get( t.params.inputSource === 'const' ? 'scalar_const' : 'scalar_non_const' ); - await run(t, binary('-'), [TypeF16, TypeF16], TypeF16, t.params, cases); + await run(t, binary('-'), [Type.f16, Type.f16], Type.f16, t.params, cases); }); g.test('vector') @@ -47,7 +47,7 @@ Accuracy: Correctly rounded const cases = await d.get( t.params.inputSource === 'const' ? 'scalar_const' : 'scalar_non_const' // Using vectorize to generate vector cases based on scalar cases ); - await run(t, binary('-'), [TypeF16, TypeF16], TypeF16, t.params, cases); + await run(t, binary('-'), [Type.f16, Type.f16], Type.f16, t.params, cases); }); g.test('scalar_compound') @@ -68,7 +68,7 @@ Accuracy: Correctly rounded const cases = await d.get( t.params.inputSource === 'const' ? 'scalar_const' : 'scalar_non_const' ); - await run(t, compoundBinary('-='), [TypeF16, TypeF16], TypeF16, t.params, cases); + await run(t, compoundBinary('-='), [Type.f16, Type.f16], Type.f16, t.params, cases); }); g.test('vector_scalar') @@ -91,8 +91,8 @@ Accuracy: Correctly rounded await run( t, binary('-'), - [TypeVec(dim, TypeF16), TypeF16], - TypeVec(dim, TypeF16), + [Type.vec(dim, Type.f16), Type.f16], + Type.vec(dim, Type.f16), t.params, cases ); @@ -118,8 +118,8 @@ Accuracy: Correctly rounded await run( t, compoundBinary('-='), - [TypeVec(dim, TypeF16), TypeF16], - TypeVec(dim, TypeF16), + [Type.vec(dim, Type.f16), Type.f16], + Type.vec(dim, Type.f16), t.params, cases ); @@ -145,8 +145,8 @@ Accuracy: Correctly rounded await run( t, binary('-'), - [TypeF16, TypeVec(dim, TypeF16)], - TypeVec(dim, TypeF16), + [Type.f16, Type.vec(dim, Type.f16)], + Type.vec(dim, Type.f16), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/binary/f32_addition.spec.ts b/src/webgpu/shader/execution/expression/binary/f32_addition.spec.ts index 6bd8b0e7bdb7..9a502ae67719 100644 --- a/src/webgpu/shader/execution/expression/binary/f32_addition.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/f32_addition.spec.ts @@ -4,7 +4,7 @@ Execution Tests for non-matrix f32 addition expression import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeF32, TypeVec } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { allInputSources, run } from '../expression.js'; import { binary, compoundBinary } from './binary.js'; @@ -25,7 +25,7 @@ Accuracy: Correctly rounded const cases = await d.get( t.params.inputSource === 'const' ? 'scalar_const' : 'scalar_non_const' ); - await run(t, binary('+'), [TypeF32, TypeF32], TypeF32, t.params, cases); + await run(t, binary('+'), [Type.f32, Type.f32], Type.f32, t.params, cases); }); g.test('vector') @@ -41,7 +41,7 @@ Accuracy: Correctly rounded const cases = await d.get( t.params.inputSource === 'const' ? 'scalar_const' : 'scalar_non_const' // Using vectorize to generate vector cases based on scalar cases ); - await run(t, binary('+'), [TypeF32, TypeF32], TypeF32, t.params, cases); + await run(t, binary('+'), [Type.f32, Type.f32], Type.f32, t.params, cases); }); g.test('scalar_compound') @@ -59,7 +59,7 @@ Accuracy: Correctly rounded const cases = await d.get( t.params.inputSource === 'const' ? 'scalar_const' : 'scalar_non_const' ); - await run(t, compoundBinary('+='), [TypeF32, TypeF32], TypeF32, t.params, cases); + await run(t, compoundBinary('+='), [Type.f32, Type.f32], Type.f32, t.params, cases); }); g.test('vector_scalar') @@ -79,8 +79,8 @@ Accuracy: Correctly rounded await run( t, binary('+'), - [TypeVec(dim, TypeF32), TypeF32], - TypeVec(dim, TypeF32), + [Type.vec(dim, Type.f32), Type.f32], + Type.vec(dim, Type.f32), t.params, cases ); @@ -103,8 +103,8 @@ Accuracy: Correctly rounded await run( t, compoundBinary('+='), - [TypeVec(dim, TypeF32), TypeF32], - TypeVec(dim, TypeF32), + [Type.vec(dim, Type.f32), Type.f32], + Type.vec(dim, Type.f32), t.params, cases ); @@ -127,8 +127,8 @@ Accuracy: Correctly rounded await run( t, binary('+'), - [TypeF32, TypeVec(dim, TypeF32)], - TypeVec(dim, TypeF32), + [Type.f32, Type.vec(dim, Type.f32)], + Type.vec(dim, Type.f32), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/binary/f32_comparison.cache.ts b/src/webgpu/shader/execution/expression/binary/f32_comparison.cache.ts index 4c16fc55f0e5..28fb22e8202a 100644 --- a/src/webgpu/shader/execution/expression/binary/f32_comparison.cache.ts +++ b/src/webgpu/shader/execution/expression/binary/f32_comparison.cache.ts @@ -1,5 +1,5 @@ import { anyOf } from '../../../../util/compare.js'; -import { bool, f32, Scalar } from '../../../../util/conversion.js'; +import { bool, f32, ScalarValue } from '../../../../util/conversion.js'; import { flushSubnormalNumberF32, vectorF32Range } from '../../../../util/math.js'; import { Case } from '../case.js'; import { makeCaseCache } from '../case_cache.js'; @@ -11,7 +11,7 @@ import { makeCaseCache } from '../case_cache.js'; function makeCase( lhs: number, rhs: number, - truthFunc: (lhs: Scalar, rhs: Scalar) => boolean + truthFunc: (lhs: ScalarValue, rhs: ScalarValue) => boolean ): Case { // Subnormal float values may be flushed at any time. // https://www.w3.org/TR/WGSL/#floating-point-evaluation @@ -19,7 +19,7 @@ function makeCase( const f32_rhs = f32(rhs); const lhs_options = new Set([f32_lhs, f32(flushSubnormalNumberF32(lhs))]); const rhs_options = new Set([f32_rhs, f32(flushSubnormalNumberF32(rhs))]); - const expected: Array = []; + const expected: Array = []; lhs_options.forEach(l => { rhs_options.forEach(r => { const result = bool(truthFunc(l, r)); @@ -34,7 +34,7 @@ function makeCase( export const d = makeCaseCache('binary/f32_logical', { equals_non_const: () => { - const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + const truthFunc = (lhs: ScalarValue, rhs: ScalarValue): boolean => { return (lhs.value as number) === (rhs.value as number); }; @@ -43,7 +43,7 @@ export const d = makeCaseCache('binary/f32_logical', { }); }, equals_const: () => { - const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + const truthFunc = (lhs: ScalarValue, rhs: ScalarValue): boolean => { return (lhs.value as number) === (rhs.value as number); }; @@ -52,7 +52,7 @@ export const d = makeCaseCache('binary/f32_logical', { }); }, not_equals_non_const: () => { - const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + const truthFunc = (lhs: ScalarValue, rhs: ScalarValue): boolean => { return (lhs.value as number) !== (rhs.value as number); }; @@ -61,7 +61,7 @@ export const d = makeCaseCache('binary/f32_logical', { }); }, not_equals_const: () => { - const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + const truthFunc = (lhs: ScalarValue, rhs: ScalarValue): boolean => { return (lhs.value as number) !== (rhs.value as number); }; @@ -70,7 +70,7 @@ export const d = makeCaseCache('binary/f32_logical', { }); }, less_than_non_const: () => { - const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + const truthFunc = (lhs: ScalarValue, rhs: ScalarValue): boolean => { return (lhs.value as number) < (rhs.value as number); }; @@ -79,7 +79,7 @@ export const d = makeCaseCache('binary/f32_logical', { }); }, less_than_const: () => { - const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + const truthFunc = (lhs: ScalarValue, rhs: ScalarValue): boolean => { return (lhs.value as number) < (rhs.value as number); }; @@ -88,7 +88,7 @@ export const d = makeCaseCache('binary/f32_logical', { }); }, less_equals_non_const: () => { - const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + const truthFunc = (lhs: ScalarValue, rhs: ScalarValue): boolean => { return (lhs.value as number) <= (rhs.value as number); }; @@ -97,7 +97,7 @@ export const d = makeCaseCache('binary/f32_logical', { }); }, less_equals_const: () => { - const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + const truthFunc = (lhs: ScalarValue, rhs: ScalarValue): boolean => { return (lhs.value as number) <= (rhs.value as number); }; @@ -106,7 +106,7 @@ export const d = makeCaseCache('binary/f32_logical', { }); }, greater_than_non_const: () => { - const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + const truthFunc = (lhs: ScalarValue, rhs: ScalarValue): boolean => { return (lhs.value as number) > (rhs.value as number); }; @@ -115,7 +115,7 @@ export const d = makeCaseCache('binary/f32_logical', { }); }, greater_than_const: () => { - const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + const truthFunc = (lhs: ScalarValue, rhs: ScalarValue): boolean => { return (lhs.value as number) > (rhs.value as number); }; @@ -124,7 +124,7 @@ export const d = makeCaseCache('binary/f32_logical', { }); }, greater_equals_non_const: () => { - const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + const truthFunc = (lhs: ScalarValue, rhs: ScalarValue): boolean => { return (lhs.value as number) >= (rhs.value as number); }; @@ -133,7 +133,7 @@ export const d = makeCaseCache('binary/f32_logical', { }); }, greater_equals_const: () => { - const truthFunc = (lhs: Scalar, rhs: Scalar): boolean => { + const truthFunc = (lhs: ScalarValue, rhs: ScalarValue): boolean => { return (lhs.value as number) >= (rhs.value as number); }; diff --git a/src/webgpu/shader/execution/expression/binary/f32_comparison.spec.ts b/src/webgpu/shader/execution/expression/binary/f32_comparison.spec.ts index e5833a0f9f33..42eb8934a440 100644 --- a/src/webgpu/shader/execution/expression/binary/f32_comparison.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/f32_comparison.spec.ts @@ -4,7 +4,7 @@ Execution Tests for the f32 comparison operations import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeBool, TypeF32 } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { allInputSources, run } from '../expression.js'; import { binary } from './binary.js'; @@ -27,7 +27,7 @@ Accuracy: Correct result const cases = await d.get( t.params.inputSource === 'const' ? 'equals_const' : 'equals_non_const' ); - await run(t, binary('=='), [TypeF32, TypeF32], TypeBool, t.params, cases); + await run(t, binary('=='), [Type.f32, Type.f32], Type.bool, t.params, cases); }); g.test('not_equals') @@ -45,7 +45,7 @@ Accuracy: Correct result const cases = await d.get( t.params.inputSource === 'const' ? 'not_equals_const' : 'not_equals_non_const' ); - await run(t, binary('!='), [TypeF32, TypeF32], TypeBool, t.params, cases); + await run(t, binary('!='), [Type.f32, Type.f32], Type.bool, t.params, cases); }); g.test('less_than') @@ -63,7 +63,7 @@ Accuracy: Correct result const cases = await d.get( t.params.inputSource === 'const' ? 'less_than_const' : 'less_than_non_const' ); - await run(t, binary('<'), [TypeF32, TypeF32], TypeBool, t.params, cases); + await run(t, binary('<'), [Type.f32, Type.f32], Type.bool, t.params, cases); }); g.test('less_equals') @@ -81,7 +81,7 @@ Accuracy: Correct result const cases = await d.get( t.params.inputSource === 'const' ? 'less_equals_const' : 'less_equals_non_const' ); - await run(t, binary('<='), [TypeF32, TypeF32], TypeBool, t.params, cases); + await run(t, binary('<='), [Type.f32, Type.f32], Type.bool, t.params, cases); }); g.test('greater_than') @@ -99,7 +99,7 @@ Accuracy: Correct result const cases = await d.get( t.params.inputSource === 'const' ? 'greater_than_const' : 'greater_than_non_const' ); - await run(t, binary('>'), [TypeF32, TypeF32], TypeBool, t.params, cases); + await run(t, binary('>'), [Type.f32, Type.f32], Type.bool, t.params, cases); }); g.test('greater_equals') @@ -117,5 +117,5 @@ Accuracy: Correct result const cases = await d.get( t.params.inputSource === 'const' ? 'greater_equals_const' : 'greater_equals_non_const' ); - await run(t, binary('>='), [TypeF32, TypeF32], TypeBool, t.params, cases); + await run(t, binary('>='), [Type.f32, Type.f32], Type.bool, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/binary/f32_division.spec.ts b/src/webgpu/shader/execution/expression/binary/f32_division.spec.ts index 0c8dd293f57d..bdd71e69eb52 100644 --- a/src/webgpu/shader/execution/expression/binary/f32_division.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/f32_division.spec.ts @@ -4,7 +4,7 @@ Execution Tests for non-matrix f32 division expression import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeF32, TypeVec } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { allInputSources, run } from '../expression.js'; import { binary, compoundBinary } from './binary.js'; @@ -25,7 +25,7 @@ Accuracy: 2.5 ULP for |y| in the range [2^-126, 2^126] const cases = await d.get( t.params.inputSource === 'const' ? 'scalar_const' : 'scalar_non_const' ); - await run(t, binary('/'), [TypeF32, TypeF32], TypeF32, t.params, cases); + await run(t, binary('/'), [Type.f32, Type.f32], Type.f32, t.params, cases); }); g.test('vector') @@ -41,7 +41,7 @@ Accuracy: 2.5 ULP for |y| in the range [2^-126, 2^126] const cases = await d.get( t.params.inputSource === 'const' ? 'scalar_const' : 'scalar_non_const' // Using vectorize to generate vector cases based on scalar cases ); - await run(t, binary('/'), [TypeF32, TypeF32], TypeF32, t.params, cases); + await run(t, binary('/'), [Type.f32, Type.f32], Type.f32, t.params, cases); }); g.test('scalar_compound') @@ -59,7 +59,7 @@ Accuracy: 2.5 ULP for |y| in the range [2^-126, 2^126] const cases = await d.get( t.params.inputSource === 'const' ? 'scalar_const' : 'scalar_non_const' ); - await run(t, compoundBinary('/='), [TypeF32, TypeF32], TypeF32, t.params, cases); + await run(t, compoundBinary('/='), [Type.f32, Type.f32], Type.f32, t.params, cases); }); g.test('vector_scalar') @@ -79,8 +79,8 @@ Accuracy: Correctly rounded await run( t, binary('/'), - [TypeVec(dim, TypeF32), TypeF32], - TypeVec(dim, TypeF32), + [Type.vec(dim, Type.f32), Type.f32], + Type.vec(dim, Type.f32), t.params, cases ); @@ -103,8 +103,8 @@ Accuracy: Correctly rounded await run( t, compoundBinary('/='), - [TypeVec(dim, TypeF32), TypeF32], - TypeVec(dim, TypeF32), + [Type.vec(dim, Type.f32), Type.f32], + Type.vec(dim, Type.f32), t.params, cases ); @@ -127,8 +127,8 @@ Accuracy: Correctly rounded await run( t, binary('/'), - [TypeF32, TypeVec(dim, TypeF32)], - TypeVec(dim, TypeF32), + [Type.f32, Type.vec(dim, Type.f32)], + Type.vec(dim, Type.f32), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/binary/f32_matrix_addition.spec.ts b/src/webgpu/shader/execution/expression/binary/f32_matrix_addition.spec.ts index 4fcb4d08927d..06a4ac47cc5b 100644 --- a/src/webgpu/shader/execution/expression/binary/f32_matrix_addition.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/f32_matrix_addition.spec.ts @@ -4,7 +4,7 @@ Execution Tests for matrix f32 addition expression import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeF32, TypeMat } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { allInputSources, run } from '../expression.js'; import { binary, compoundBinary } from './binary.js'; @@ -35,8 +35,8 @@ Accuracy: Correctly rounded await run( t, binary('+'), - [TypeMat(cols, rows, TypeF32), TypeMat(cols, rows, TypeF32)], - TypeMat(cols, rows, TypeF32), + [Type.mat(cols, rows, Type.f32), Type.mat(cols, rows, Type.f32)], + Type.mat(cols, rows, Type.f32), t.params, cases ); @@ -65,8 +65,8 @@ Accuracy: Correctly rounded await run( t, compoundBinary('+='), - [TypeMat(cols, rows, TypeF32), TypeMat(cols, rows, TypeF32)], - TypeMat(cols, rows, TypeF32), + [Type.mat(cols, rows, Type.f32), Type.mat(cols, rows, Type.f32)], + Type.mat(cols, rows, Type.f32), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/binary/f32_matrix_matrix_multiplication.spec.ts b/src/webgpu/shader/execution/expression/binary/f32_matrix_matrix_multiplication.spec.ts index ad34d642d26e..1ff7799f4625 100644 --- a/src/webgpu/shader/execution/expression/binary/f32_matrix_matrix_multiplication.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/f32_matrix_matrix_multiplication.spec.ts @@ -4,7 +4,7 @@ Execution Tests for matrix-matrix f32 multiplication expression import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeF32, TypeMat } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { allInputSources, run } from '../expression.js'; import { binary, compoundBinary } from './binary.js'; @@ -41,8 +41,8 @@ Accuracy: Correctly rounded await run( t, binary('*'), - [TypeMat(x_cols, x_rows, TypeF32), TypeMat(y_cols, y_rows, TypeF32)], - TypeMat(y_cols, x_rows, TypeF32), + [Type.mat(x_cols, x_rows, Type.f32), Type.mat(y_cols, y_rows, Type.f32)], + Type.mat(y_cols, x_rows, Type.f32), t.params, cases ); @@ -76,8 +76,8 @@ Accuracy: Correctly rounded await run( t, compoundBinary('*='), - [TypeMat(x_cols, x_rows, TypeF32), TypeMat(y_cols, y_rows, TypeF32)], - TypeMat(y_cols, x_rows, TypeF32), + [Type.mat(x_cols, x_rows, Type.f32), Type.mat(y_cols, y_rows, Type.f32)], + Type.mat(y_cols, x_rows, Type.f32), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/binary/f32_matrix_scalar_multiplication.spec.ts b/src/webgpu/shader/execution/expression/binary/f32_matrix_scalar_multiplication.spec.ts index 0558862d065d..e8771d19eb5d 100644 --- a/src/webgpu/shader/execution/expression/binary/f32_matrix_scalar_multiplication.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/f32_matrix_scalar_multiplication.spec.ts @@ -4,7 +4,7 @@ Execution Tests for matrix-scalar and scalar-matrix f32 multiplication expressio import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeF32, TypeMat } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { allInputSources, run } from '../expression.js'; import { binary, compoundBinary } from './binary.js'; @@ -37,8 +37,8 @@ Accuracy: Correctly rounded await run( t, binary('*'), - [TypeMat(cols, rows, TypeF32), TypeF32], - TypeMat(cols, rows, TypeF32), + [Type.mat(cols, rows, Type.f32), Type.f32], + Type.mat(cols, rows, Type.f32), t.params, cases ); @@ -69,8 +69,8 @@ Accuracy: Correctly rounded await run( t, compoundBinary('*='), - [TypeMat(cols, rows, TypeF32), TypeF32], - TypeMat(cols, rows, TypeF32), + [Type.mat(cols, rows, Type.f32), Type.f32], + Type.mat(cols, rows, Type.f32), t.params, cases ); @@ -101,8 +101,8 @@ Accuracy: Correctly rounded await run( t, binary('*'), - [TypeF32, TypeMat(cols, rows, TypeF32)], - TypeMat(cols, rows, TypeF32), + [Type.f32, Type.mat(cols, rows, Type.f32)], + Type.mat(cols, rows, Type.f32), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/binary/f32_matrix_subtraction.spec.ts b/src/webgpu/shader/execution/expression/binary/f32_matrix_subtraction.spec.ts index 8bcf9a47895c..31565ba598d5 100644 --- a/src/webgpu/shader/execution/expression/binary/f32_matrix_subtraction.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/f32_matrix_subtraction.spec.ts @@ -4,7 +4,7 @@ Execution Tests for matrix f32 subtraction expression import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeF32, TypeMat } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { allInputSources, run } from '../expression.js'; import { binary, compoundBinary } from './binary.js'; @@ -35,8 +35,8 @@ Accuracy: Correctly rounded await run( t, binary('-'), - [TypeMat(cols, rows, TypeF32), TypeMat(cols, rows, TypeF32)], - TypeMat(cols, rows, TypeF32), + [Type.mat(cols, rows, Type.f32), Type.mat(cols, rows, Type.f32)], + Type.mat(cols, rows, Type.f32), t.params, cases ); @@ -65,8 +65,8 @@ Accuracy: Correctly rounded await run( t, compoundBinary('-='), - [TypeMat(cols, rows, TypeF32), TypeMat(cols, rows, TypeF32)], - TypeMat(cols, rows, TypeF32), + [Type.mat(cols, rows, Type.f32), Type.mat(cols, rows, Type.f32)], + Type.mat(cols, rows, Type.f32), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/binary/f32_matrix_vector_multiplication.spec.ts b/src/webgpu/shader/execution/expression/binary/f32_matrix_vector_multiplication.spec.ts index a04a28cfeff3..8cd7ed49fe0a 100644 --- a/src/webgpu/shader/execution/expression/binary/f32_matrix_vector_multiplication.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/f32_matrix_vector_multiplication.spec.ts @@ -4,7 +4,7 @@ Execution Tests for matrix-vector and vector-matrix f32 multiplication expressio import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeF32, TypeMat, TypeVec } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { allInputSources, run } from '../expression.js'; import { binary, compoundBinary } from './binary.js'; @@ -37,8 +37,8 @@ Accuracy: Correctly rounded await run( t, binary('*'), - [TypeMat(cols, rows, TypeF32), TypeVec(cols, TypeF32)], - TypeVec(rows, TypeF32), + [Type.mat(cols, rows, Type.f32), Type.vec(cols, Type.f32)], + Type.vec(rows, Type.f32), t.params, cases ); @@ -69,8 +69,8 @@ Accuracy: Correctly rounded await run( t, binary('*'), - [TypeVec(rows, TypeF32), TypeMat(cols, rows, TypeF32)], - TypeVec(cols, TypeF32), + [Type.vec(rows, Type.f32), Type.mat(cols, rows, Type.f32)], + Type.vec(cols, Type.f32), t.params, cases ); @@ -96,8 +96,8 @@ Accuracy: Correctly rounded await run( t, compoundBinary('*='), - [TypeVec(rows, TypeF32), TypeMat(cols, rows, TypeF32)], - TypeVec(cols, TypeF32), + [Type.vec(rows, Type.f32), Type.mat(cols, rows, Type.f32)], + Type.vec(cols, Type.f32), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/binary/f32_multiplication.spec.ts b/src/webgpu/shader/execution/expression/binary/f32_multiplication.spec.ts index 77e670795d2d..478ca71ef0fc 100644 --- a/src/webgpu/shader/execution/expression/binary/f32_multiplication.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/f32_multiplication.spec.ts @@ -4,7 +4,7 @@ Execution Tests for non-matrix f32 multiplication expression import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeF32, TypeVec } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { allInputSources, run } from '../expression.js'; import { binary, compoundBinary } from './binary.js'; @@ -25,7 +25,7 @@ Accuracy: Correctly rounded const cases = await d.get( t.params.inputSource === 'const' ? 'scalar_const' : 'scalar_non_const' ); - await run(t, binary('*'), [TypeF32, TypeF32], TypeF32, t.params, cases); + await run(t, binary('*'), [Type.f32, Type.f32], Type.f32, t.params, cases); }); g.test('vector') @@ -41,7 +41,7 @@ Accuracy: Correctly rounded const cases = await d.get( t.params.inputSource === 'const' ? 'scalar_const' : 'scalar_non_const' // Using vectorize to generate vector cases based on scalar cases ); - await run(t, binary('*'), [TypeF32, TypeF32], TypeF32, t.params, cases); + await run(t, binary('*'), [Type.f32, Type.f32], Type.f32, t.params, cases); }); g.test('scalar_compound') @@ -59,7 +59,7 @@ Accuracy: Correctly rounded const cases = await d.get( t.params.inputSource === 'const' ? 'scalar_const' : 'scalar_non_const' ); - await run(t, compoundBinary('*='), [TypeF32, TypeF32], TypeF32, t.params, cases); + await run(t, compoundBinary('*='), [Type.f32, Type.f32], Type.f32, t.params, cases); }); g.test('vector_scalar') @@ -79,8 +79,8 @@ Accuracy: Correctly rounded await run( t, binary('*'), - [TypeVec(dim, TypeF32), TypeF32], - TypeVec(dim, TypeF32), + [Type.vec(dim, Type.f32), Type.f32], + Type.vec(dim, Type.f32), t.params, cases ); @@ -103,8 +103,8 @@ Accuracy: Correctly rounded await run( t, compoundBinary('*='), - [TypeVec(dim, TypeF32), TypeF32], - TypeVec(dim, TypeF32), + [Type.vec(dim, Type.f32), Type.f32], + Type.vec(dim, Type.f32), t.params, cases ); @@ -127,8 +127,8 @@ Accuracy: Correctly rounded await run( t, binary('*'), - [TypeF32, TypeVec(dim, TypeF32)], - TypeVec(dim, TypeF32), + [Type.f32, Type.vec(dim, Type.f32)], + Type.vec(dim, Type.f32), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/binary/f32_remainder.spec.ts b/src/webgpu/shader/execution/expression/binary/f32_remainder.spec.ts index b61d3ecc633a..3a9acb02e095 100644 --- a/src/webgpu/shader/execution/expression/binary/f32_remainder.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/f32_remainder.spec.ts @@ -4,7 +4,7 @@ Execution Tests for non-matrix f32 remainder expression import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeF32, TypeVec } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { allInputSources, run } from '../expression.js'; import { binary, compoundBinary } from './binary.js'; @@ -25,7 +25,7 @@ Accuracy: Derived from x - y * trunc(x/y) const cases = await d.get( t.params.inputSource === 'const' ? 'scalar_const' : 'scalar_non_const' ); - await run(t, binary('%'), [TypeF32, TypeF32], TypeF32, t.params, cases); + await run(t, binary('%'), [Type.f32, Type.f32], Type.f32, t.params, cases); }); g.test('vector') @@ -41,7 +41,7 @@ Accuracy: Derived from x - y * trunc(x/y) const cases = await d.get( t.params.inputSource === 'const' ? 'scalar_const' : 'scalar_non_const' // Using vectorize to generate vector cases based on scalar cases ); - await run(t, binary('%'), [TypeF32, TypeF32], TypeF32, t.params, cases); + await run(t, binary('%'), [Type.f32, Type.f32], Type.f32, t.params, cases); }); g.test('scalar_compound') @@ -59,7 +59,7 @@ Accuracy: Derived from x - y * trunc(x/y) const cases = await d.get( t.params.inputSource === 'const' ? 'scalar_const' : 'scalar_non_const' ); - await run(t, compoundBinary('%='), [TypeF32, TypeF32], TypeF32, t.params, cases); + await run(t, compoundBinary('%='), [Type.f32, Type.f32], Type.f32, t.params, cases); }); g.test('vector_scalar') @@ -79,8 +79,8 @@ Accuracy: Correctly rounded await run( t, binary('%'), - [TypeVec(dim, TypeF32), TypeF32], - TypeVec(dim, TypeF32), + [Type.vec(dim, Type.f32), Type.f32], + Type.vec(dim, Type.f32), t.params, cases ); @@ -103,8 +103,8 @@ Accuracy: Correctly rounded await run( t, compoundBinary('%='), - [TypeVec(dim, TypeF32), TypeF32], - TypeVec(dim, TypeF32), + [Type.vec(dim, Type.f32), Type.f32], + Type.vec(dim, Type.f32), t.params, cases ); @@ -127,8 +127,8 @@ Accuracy: Correctly rounded await run( t, binary('%'), - [TypeF32, TypeVec(dim, TypeF32)], - TypeVec(dim, TypeF32), + [Type.f32, Type.vec(dim, Type.f32)], + Type.vec(dim, Type.f32), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/binary/f32_subtraction.spec.ts b/src/webgpu/shader/execution/expression/binary/f32_subtraction.spec.ts index e873c6ebc3b1..55097390e935 100644 --- a/src/webgpu/shader/execution/expression/binary/f32_subtraction.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/f32_subtraction.spec.ts @@ -4,7 +4,7 @@ Execution Tests for non-matrix f32 subtraction expression import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeF32, TypeVec } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { allInputSources, run } from '../expression.js'; import { binary, compoundBinary } from './binary.js'; @@ -25,7 +25,7 @@ Accuracy: Correctly rounded const cases = await d.get( t.params.inputSource === 'const' ? 'scalar_const' : 'scalar_non_const' ); - await run(t, binary('-'), [TypeF32, TypeF32], TypeF32, t.params, cases); + await run(t, binary('-'), [Type.f32, Type.f32], Type.f32, t.params, cases); }); g.test('vector') @@ -41,7 +41,7 @@ Accuracy: Correctly rounded const cases = await d.get( t.params.inputSource === 'const' ? 'scalar_const' : 'scalar_non_const' // Using vectorize to generate vector cases based on scalar cases ); - await run(t, binary('-'), [TypeF32, TypeF32], TypeF32, t.params, cases); + await run(t, binary('-'), [Type.f32, Type.f32], Type.f32, t.params, cases); }); g.test('scalar_compound') @@ -59,7 +59,7 @@ Accuracy: Correctly rounded const cases = await d.get( t.params.inputSource === 'const' ? 'scalar_const' : 'scalar_non_const' ); - await run(t, compoundBinary('-='), [TypeF32, TypeF32], TypeF32, t.params, cases); + await run(t, compoundBinary('-='), [Type.f32, Type.f32], Type.f32, t.params, cases); }); g.test('vector_scalar') @@ -79,8 +79,8 @@ Accuracy: Correctly rounded await run( t, binary('-'), - [TypeVec(dim, TypeF32), TypeF32], - TypeVec(dim, TypeF32), + [Type.vec(dim, Type.f32), Type.f32], + Type.vec(dim, Type.f32), t.params, cases ); @@ -103,8 +103,8 @@ Accuracy: Correctly rounded await run( t, compoundBinary('-='), - [TypeVec(dim, TypeF32), TypeF32], - TypeVec(dim, TypeF32), + [Type.vec(dim, Type.f32), Type.f32], + Type.vec(dim, Type.f32), t.params, cases ); @@ -127,8 +127,8 @@ Accuracy: Correctly rounded await run( t, binary('-'), - [TypeF32, TypeVec(dim, TypeF32)], - TypeVec(dim, TypeF32), + [Type.f32, Type.vec(dim, Type.f32)], + Type.vec(dim, Type.f32), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/binary/i32_arithmetic.spec.ts b/src/webgpu/shader/execution/expression/binary/i32_arithmetic.spec.ts index ef201f66689f..ef8ea0044782 100644 --- a/src/webgpu/shader/execution/expression/binary/i32_arithmetic.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/i32_arithmetic.spec.ts @@ -4,7 +4,7 @@ Execution Tests for the i32 arithmetic binary expression operations import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeI32, TypeVec } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { allInputSources, run } from '../expression.js'; import { binary, compoundBinary } from './binary.js'; @@ -24,7 +24,7 @@ Expression: x + y ) .fn(async t => { const cases = await d.get('addition'); - await run(t, binary('+'), [TypeI32, TypeI32], TypeI32, t.params, cases); + await run(t, binary('+'), [Type.i32, Type.i32], Type.i32, t.params, cases); }); g.test('addition_compound') @@ -39,7 +39,7 @@ Expression: x += y ) .fn(async t => { const cases = await d.get('addition'); - await run(t, compoundBinary('+='), [TypeI32, TypeI32], TypeI32, t.params, cases); + await run(t, compoundBinary('+='), [Type.i32, Type.i32], Type.i32, t.params, cases); }); g.test('subtraction') @@ -54,7 +54,7 @@ Expression: x - y ) .fn(async t => { const cases = await d.get('subtraction'); - await run(t, binary('-'), [TypeI32, TypeI32], TypeI32, t.params, cases); + await run(t, binary('-'), [Type.i32, Type.i32], Type.i32, t.params, cases); }); g.test('subtraction_compound') @@ -69,7 +69,7 @@ Expression: x -= y ) .fn(async t => { const cases = await d.get('subtraction'); - await run(t, compoundBinary('-='), [TypeI32, TypeI32], TypeI32, t.params, cases); + await run(t, compoundBinary('-='), [Type.i32, Type.i32], Type.i32, t.params, cases); }); g.test('multiplication') @@ -84,7 +84,7 @@ Expression: x * y ) .fn(async t => { const cases = await d.get('multiplication'); - await run(t, binary('*'), [TypeI32, TypeI32], TypeI32, t.params, cases); + await run(t, binary('*'), [Type.i32, Type.i32], Type.i32, t.params, cases); }); g.test('multiplication_compound') @@ -99,7 +99,7 @@ Expression: x *= y ) .fn(async t => { const cases = await d.get('multiplication'); - await run(t, compoundBinary('*='), [TypeI32, TypeI32], TypeI32, t.params, cases); + await run(t, compoundBinary('*='), [Type.i32, Type.i32], Type.i32, t.params, cases); }); g.test('division') @@ -116,7 +116,7 @@ Expression: x / y const cases = await d.get( t.params.inputSource === 'const' ? 'division_const' : 'division_non_const' ); - await run(t, binary('/'), [TypeI32, TypeI32], TypeI32, t.params, cases); + await run(t, binary('/'), [Type.i32, Type.i32], Type.i32, t.params, cases); }); g.test('division_compound') @@ -133,7 +133,7 @@ Expression: x /= y const cases = await d.get( t.params.inputSource === 'const' ? 'division_const' : 'division_non_const' ); - await run(t, compoundBinary('/='), [TypeI32, TypeI32], TypeI32, t.params, cases); + await run(t, compoundBinary('/='), [Type.i32, Type.i32], Type.i32, t.params, cases); }); g.test('remainder') @@ -150,7 +150,7 @@ Expression: x % y const cases = await d.get( t.params.inputSource === 'const' ? 'remainder_const' : 'remainder_non_const' ); - await run(t, binary('%'), [TypeI32, TypeI32], TypeI32, t.params, cases); + await run(t, binary('%'), [Type.i32, Type.i32], Type.i32, t.params, cases); }); g.test('remainder_compound') @@ -167,7 +167,7 @@ Expression: x %= y const cases = await d.get( t.params.inputSource === 'const' ? 'remainder_const' : 'remainder_non_const' ); - await run(t, compoundBinary('%='), [TypeI32, TypeI32], TypeI32, t.params, cases); + await run(t, compoundBinary('%='), [Type.i32, Type.i32], Type.i32, t.params, cases); }); g.test('addition_scalar_vector') @@ -182,9 +182,9 @@ Expression: x + y ) .fn(async t => { const vec_size = t.params.vectorize_rhs; - const vec_type = TypeVec(vec_size, TypeI32); + const vec_type = Type.vec(vec_size, Type.i32); const cases = await d.get(`addition_scalar_vector${vec_size}`); - await run(t, binary('+'), [TypeI32, vec_type], vec_type, t.params, cases); + await run(t, binary('+'), [Type.i32, vec_type], vec_type, t.params, cases); }); g.test('addition_vector_scalar') @@ -199,9 +199,9 @@ Expression: x + y ) .fn(async t => { const vec_size = t.params.vectorize_lhs; - const vec_type = TypeVec(vec_size, TypeI32); + const vec_type = Type.vec(vec_size, Type.i32); const cases = await d.get(`addition_vector${vec_size}_scalar`); - await run(t, binary('+'), [vec_type, TypeI32], vec_type, t.params, cases); + await run(t, binary('+'), [vec_type, Type.i32], vec_type, t.params, cases); }); g.test('addition_vector_scalar_compound') @@ -216,9 +216,9 @@ Expression: x += y ) .fn(async t => { const vec_size = t.params.vectorize_lhs; - const vec_type = TypeVec(vec_size, TypeI32); + const vec_type = Type.vec(vec_size, Type.i32); const cases = await d.get(`addition_vector${vec_size}_scalar`); - await run(t, compoundBinary('+='), [vec_type, TypeI32], vec_type, t.params, cases); + await run(t, compoundBinary('+='), [vec_type, Type.i32], vec_type, t.params, cases); }); g.test('subtraction_scalar_vector') @@ -233,9 +233,9 @@ Expression: x - y ) .fn(async t => { const vec_size = t.params.vectorize_rhs; - const vec_type = TypeVec(vec_size, TypeI32); + const vec_type = Type.vec(vec_size, Type.i32); const cases = await d.get(`subtraction_scalar_vector${vec_size}`); - await run(t, binary('-'), [TypeI32, vec_type], vec_type, t.params, cases); + await run(t, binary('-'), [Type.i32, vec_type], vec_type, t.params, cases); }); g.test('subtraction_vector_scalar') @@ -250,9 +250,9 @@ Expression: x - y ) .fn(async t => { const vec_size = t.params.vectorize_lhs; - const vec_type = TypeVec(vec_size, TypeI32); + const vec_type = Type.vec(vec_size, Type.i32); const cases = await d.get(`subtraction_vector${vec_size}_scalar`); - await run(t, binary('-'), [vec_type, TypeI32], vec_type, t.params, cases); + await run(t, binary('-'), [vec_type, Type.i32], vec_type, t.params, cases); }); g.test('subtraction_vector_scalar_compound') @@ -267,9 +267,9 @@ Expression: x -= y ) .fn(async t => { const vec_size = t.params.vectorize_lhs; - const vec_type = TypeVec(vec_size, TypeI32); + const vec_type = Type.vec(vec_size, Type.i32); const cases = await d.get(`subtraction_vector${vec_size}_scalar`); - await run(t, compoundBinary('-='), [vec_type, TypeI32], vec_type, t.params, cases); + await run(t, compoundBinary('-='), [vec_type, Type.i32], vec_type, t.params, cases); }); g.test('multiplication_scalar_vector') @@ -284,9 +284,9 @@ Expression: x * y ) .fn(async t => { const vec_size = t.params.vectorize_rhs; - const vec_type = TypeVec(vec_size, TypeI32); + const vec_type = Type.vec(vec_size, Type.i32); const cases = await d.get(`multiplication_scalar_vector${vec_size}`); - await run(t, binary('*'), [TypeI32, vec_type], vec_type, t.params, cases); + await run(t, binary('*'), [Type.i32, vec_type], vec_type, t.params, cases); }); g.test('multiplication_vector_scalar') @@ -301,9 +301,9 @@ Expression: x * y ) .fn(async t => { const vec_size = t.params.vectorize_lhs; - const vec_type = TypeVec(vec_size, TypeI32); + const vec_type = Type.vec(vec_size, Type.i32); const cases = await d.get(`multiplication_vector${vec_size}_scalar`); - await run(t, binary('*'), [vec_type, TypeI32], vec_type, t.params, cases); + await run(t, binary('*'), [vec_type, Type.i32], vec_type, t.params, cases); }); g.test('multiplication_vector_scalar_compound') @@ -318,9 +318,9 @@ Expression: x *= y ) .fn(async t => { const vec_size = t.params.vectorize_lhs; - const vec_type = TypeVec(vec_size, TypeI32); + const vec_type = Type.vec(vec_size, Type.i32); const cases = await d.get(`multiplication_vector${vec_size}_scalar`); - await run(t, compoundBinary('*='), [vec_type, TypeI32], vec_type, t.params, cases); + await run(t, compoundBinary('*='), [vec_type, Type.i32], vec_type, t.params, cases); }); g.test('division_scalar_vector') @@ -335,10 +335,10 @@ Expression: x / y ) .fn(async t => { const vec_size = t.params.vectorize_rhs; - const vec_type = TypeVec(vec_size, TypeI32); + const vec_type = Type.vec(vec_size, Type.i32); const source = t.params.inputSource === 'const' ? 'const' : 'non_const'; const cases = await d.get(`division_scalar_vector${vec_size}_${source}`); - await run(t, binary('/'), [TypeI32, vec_type], vec_type, t.params, cases); + await run(t, binary('/'), [Type.i32, vec_type], vec_type, t.params, cases); }); g.test('division_vector_scalar') @@ -353,10 +353,10 @@ Expression: x / y ) .fn(async t => { const vec_size = t.params.vectorize_lhs; - const vec_type = TypeVec(vec_size, TypeI32); + const vec_type = Type.vec(vec_size, Type.i32); const source = t.params.inputSource === 'const' ? 'const' : 'non_const'; const cases = await d.get(`division_vector${vec_size}_scalar_${source}`); - await run(t, binary('/'), [vec_type, TypeI32], vec_type, t.params, cases); + await run(t, binary('/'), [vec_type, Type.i32], vec_type, t.params, cases); }); g.test('division_vector_scalar_compound') @@ -371,10 +371,10 @@ Expression: x /= y ) .fn(async t => { const vec_size = t.params.vectorize_lhs; - const vec_type = TypeVec(vec_size, TypeI32); + const vec_type = Type.vec(vec_size, Type.i32); const source = t.params.inputSource === 'const' ? 'const' : 'non_const'; const cases = await d.get(`division_vector${vec_size}_scalar_${source}`); - await run(t, compoundBinary('/='), [vec_type, TypeI32], vec_type, t.params, cases); + await run(t, compoundBinary('/='), [vec_type, Type.i32], vec_type, t.params, cases); }); g.test('remainder_scalar_vector') @@ -389,10 +389,10 @@ Expression: x % y ) .fn(async t => { const vec_size = t.params.vectorize_rhs; - const vec_type = TypeVec(vec_size, TypeI32); + const vec_type = Type.vec(vec_size, Type.i32); const source = t.params.inputSource === 'const' ? 'const' : 'non_const'; const cases = await d.get(`remainder_scalar_vector${vec_size}_${source}`); - await run(t, binary('%'), [TypeI32, vec_type], vec_type, t.params, cases); + await run(t, binary('%'), [Type.i32, vec_type], vec_type, t.params, cases); }); g.test('remainder_vector_scalar') @@ -407,10 +407,10 @@ Expression: x % y ) .fn(async t => { const vec_size = t.params.vectorize_lhs; - const vec_type = TypeVec(vec_size, TypeI32); + const vec_type = Type.vec(vec_size, Type.i32); const source = t.params.inputSource === 'const' ? 'const' : 'non_const'; const cases = await d.get(`remainder_vector${vec_size}_scalar_${source}`); - await run(t, binary('%'), [vec_type, TypeI32], vec_type, t.params, cases); + await run(t, binary('%'), [vec_type, Type.i32], vec_type, t.params, cases); }); g.test('remainder_vector_scalar_compound') @@ -425,8 +425,8 @@ Expression: x %= y ) .fn(async t => { const vec_size = t.params.vectorize_lhs; - const vec_type = TypeVec(vec_size, TypeI32); + const vec_type = Type.vec(vec_size, Type.i32); const source = t.params.inputSource === 'const' ? 'const' : 'non_const'; const cases = await d.get(`remainder_vector${vec_size}_scalar_${source}`); - await run(t, compoundBinary('%='), [vec_type, TypeI32], vec_type, t.params, cases); + await run(t, compoundBinary('%='), [vec_type, Type.i32], vec_type, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/binary/i32_comparison.spec.ts b/src/webgpu/shader/execution/expression/binary/i32_comparison.spec.ts index c07d09a058ed..9b6566c9a4a8 100644 --- a/src/webgpu/shader/execution/expression/binary/i32_comparison.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/i32_comparison.spec.ts @@ -4,7 +4,7 @@ Execution Tests for the i32 comparison expressions import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeBool, TypeI32 } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { allInputSources, run } from '../expression.js'; import { binary } from './binary.js'; @@ -24,7 +24,7 @@ Expression: x == y ) .fn(async t => { const cases = await d.get('equals'); - await run(t, binary('=='), [TypeI32, TypeI32], TypeBool, t.params, cases); + await run(t, binary('=='), [Type.i32, Type.i32], Type.bool, t.params, cases); }); g.test('not_equals') @@ -39,7 +39,7 @@ Expression: x != y ) .fn(async t => { const cases = await d.get('not_equals'); - await run(t, binary('!='), [TypeI32, TypeI32], TypeBool, t.params, cases); + await run(t, binary('!='), [Type.i32, Type.i32], Type.bool, t.params, cases); }); g.test('less_than') @@ -54,7 +54,7 @@ Expression: x < y ) .fn(async t => { const cases = await d.get('less_than'); - await run(t, binary('<'), [TypeI32, TypeI32], TypeBool, t.params, cases); + await run(t, binary('<'), [Type.i32, Type.i32], Type.bool, t.params, cases); }); g.test('less_equals') @@ -69,7 +69,7 @@ Expression: x <= y ) .fn(async t => { const cases = await d.get('less_equal'); - await run(t, binary('<='), [TypeI32, TypeI32], TypeBool, t.params, cases); + await run(t, binary('<='), [Type.i32, Type.i32], Type.bool, t.params, cases); }); g.test('greater_than') @@ -84,7 +84,7 @@ Expression: x > y ) .fn(async t => { const cases = await d.get('greater_than'); - await run(t, binary('>'), [TypeI32, TypeI32], TypeBool, t.params, cases); + await run(t, binary('>'), [Type.i32, Type.i32], Type.bool, t.params, cases); }); g.test('greater_equals') @@ -99,5 +99,5 @@ Expression: x >= y ) .fn(async t => { const cases = await d.get('greater_equal'); - await run(t, binary('>='), [TypeI32, TypeI32], TypeBool, t.params, cases); + await run(t, binary('>='), [Type.i32, Type.i32], Type.bool, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/binary/u32_arithmetic.spec.ts b/src/webgpu/shader/execution/expression/binary/u32_arithmetic.spec.ts index 28c25fef8dc9..6df16f303c7f 100644 --- a/src/webgpu/shader/execution/expression/binary/u32_arithmetic.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/u32_arithmetic.spec.ts @@ -4,7 +4,7 @@ Execution Tests for the u32 arithmetic binary expression operations import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeU32, TypeVec } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { allInputSources, run } from '../expression.js'; import { binary, compoundBinary } from './binary.js'; @@ -24,7 +24,7 @@ Expression: x + y ) .fn(async t => { const cases = await d.get('addition'); - await run(t, binary('+'), [TypeU32, TypeU32], TypeU32, t.params, cases); + await run(t, binary('+'), [Type.u32, Type.u32], Type.u32, t.params, cases); }); g.test('addition_compound') @@ -39,7 +39,7 @@ Expression: x += y ) .fn(async t => { const cases = await d.get('addition'); - await run(t, compoundBinary('+='), [TypeU32, TypeU32], TypeU32, t.params, cases); + await run(t, compoundBinary('+='), [Type.u32, Type.u32], Type.u32, t.params, cases); }); g.test('subtraction') @@ -54,7 +54,7 @@ Expression: x - y ) .fn(async t => { const cases = await d.get('subtraction'); - await run(t, binary('-'), [TypeU32, TypeU32], TypeU32, t.params, cases); + await run(t, binary('-'), [Type.u32, Type.u32], Type.u32, t.params, cases); }); g.test('subtraction_compound') @@ -69,7 +69,7 @@ Expression: x -= y ) .fn(async t => { const cases = await d.get('subtraction'); - await run(t, compoundBinary('-='), [TypeU32, TypeU32], TypeU32, t.params, cases); + await run(t, compoundBinary('-='), [Type.u32, Type.u32], Type.u32, t.params, cases); }); g.test('multiplication') @@ -84,7 +84,7 @@ Expression: x * y ) .fn(async t => { const cases = await d.get('multiplication'); - await run(t, binary('*'), [TypeU32, TypeU32], TypeU32, t.params, cases); + await run(t, binary('*'), [Type.u32, Type.u32], Type.u32, t.params, cases); }); g.test('multiplication_compound') @@ -99,7 +99,7 @@ Expression: x *= y ) .fn(async t => { const cases = await d.get('multiplication'); - await run(t, compoundBinary('*='), [TypeU32, TypeU32], TypeU32, t.params, cases); + await run(t, compoundBinary('*='), [Type.u32, Type.u32], Type.u32, t.params, cases); }); g.test('division') @@ -116,7 +116,7 @@ Expression: x / y const cases = await d.get( t.params.inputSource === 'const' ? 'division_const' : 'division_non_const' ); - await run(t, binary('/'), [TypeU32, TypeU32], TypeU32, t.params, cases); + await run(t, binary('/'), [Type.u32, Type.u32], Type.u32, t.params, cases); }); g.test('division_compound') @@ -133,7 +133,7 @@ Expression: x /= y const cases = await d.get( t.params.inputSource === 'const' ? 'division_const' : 'division_non_const' ); - await run(t, compoundBinary('/='), [TypeU32, TypeU32], TypeU32, t.params, cases); + await run(t, compoundBinary('/='), [Type.u32, Type.u32], Type.u32, t.params, cases); }); g.test('remainder') @@ -150,7 +150,7 @@ Expression: x % y const cases = await d.get( t.params.inputSource === 'const' ? 'remainder_const' : 'remainder_non_const' ); - await run(t, binary('%'), [TypeU32, TypeU32], TypeU32, t.params, cases); + await run(t, binary('%'), [Type.u32, Type.u32], Type.u32, t.params, cases); }); g.test('remainder_compound') @@ -167,7 +167,7 @@ Expression: x %= y const cases = await d.get( t.params.inputSource === 'const' ? 'remainder_const' : 'remainder_non_const' ); - await run(t, compoundBinary('%='), [TypeU32, TypeU32], TypeU32, t.params, cases); + await run(t, compoundBinary('%='), [Type.u32, Type.u32], Type.u32, t.params, cases); }); g.test('addition_scalar_vector') @@ -182,9 +182,9 @@ Expression: x + y ) .fn(async t => { const vec_size = t.params.vectorize_rhs; - const vec_type = TypeVec(vec_size, TypeU32); + const vec_type = Type.vec(vec_size, Type.u32); const cases = await d.get(`addition_scalar_vector${vec_size}`); - await run(t, binary('+'), [TypeU32, vec_type], vec_type, t.params, cases); + await run(t, binary('+'), [Type.u32, vec_type], vec_type, t.params, cases); }); g.test('addition_vector_scalar') @@ -199,9 +199,9 @@ Expression: x + y ) .fn(async t => { const vec_size = t.params.vectorize_lhs; - const vec_type = TypeVec(vec_size, TypeU32); + const vec_type = Type.vec(vec_size, Type.u32); const cases = await d.get(`addition_vector${vec_size}_scalar`); - await run(t, binary('+'), [vec_type, TypeU32], vec_type, t.params, cases); + await run(t, binary('+'), [vec_type, Type.u32], vec_type, t.params, cases); }); g.test('addition_vector_scalar_compound') @@ -216,9 +216,9 @@ Expression: x += y ) .fn(async t => { const vec_size = t.params.vectorize_lhs; - const vec_type = TypeVec(vec_size, TypeU32); + const vec_type = Type.vec(vec_size, Type.u32); const cases = await d.get(`addition_vector${vec_size}_scalar`); - await run(t, compoundBinary('+='), [vec_type, TypeU32], vec_type, t.params, cases); + await run(t, compoundBinary('+='), [vec_type, Type.u32], vec_type, t.params, cases); }); g.test('subtraction_scalar_vector') @@ -233,9 +233,9 @@ Expression: x - y ) .fn(async t => { const vec_size = t.params.vectorize_rhs; - const vec_type = TypeVec(vec_size, TypeU32); + const vec_type = Type.vec(vec_size, Type.u32); const cases = await d.get(`subtraction_scalar_vector${vec_size}`); - await run(t, binary('-'), [TypeU32, vec_type], vec_type, t.params, cases); + await run(t, binary('-'), [Type.u32, vec_type], vec_type, t.params, cases); }); g.test('subtraction_vector_scalar') @@ -250,9 +250,9 @@ Expression: x - y ) .fn(async t => { const vec_size = t.params.vectorize_lhs; - const vec_type = TypeVec(vec_size, TypeU32); + const vec_type = Type.vec(vec_size, Type.u32); const cases = await d.get(`subtraction_vector${vec_size}_scalar`); - await run(t, binary('-'), [vec_type, TypeU32], vec_type, t.params, cases); + await run(t, binary('-'), [vec_type, Type.u32], vec_type, t.params, cases); }); g.test('subtraction_vector_scalar_compound') @@ -267,9 +267,9 @@ Expression: x -= y ) .fn(async t => { const vec_size = t.params.vectorize_lhs; - const vec_type = TypeVec(vec_size, TypeU32); + const vec_type = Type.vec(vec_size, Type.u32); const cases = await d.get(`subtraction_vector${vec_size}_scalar`); - await run(t, compoundBinary('-='), [vec_type, TypeU32], vec_type, t.params, cases); + await run(t, compoundBinary('-='), [vec_type, Type.u32], vec_type, t.params, cases); }); g.test('multiplication_scalar_vector') @@ -284,9 +284,9 @@ Expression: x * y ) .fn(async t => { const vec_size = t.params.vectorize_rhs; - const vec_type = TypeVec(vec_size, TypeU32); + const vec_type = Type.vec(vec_size, Type.u32); const cases = await d.get(`multiplication_scalar_vector${vec_size}`); - await run(t, binary('*'), [TypeU32, vec_type], vec_type, t.params, cases); + await run(t, binary('*'), [Type.u32, vec_type], vec_type, t.params, cases); }); g.test('multiplication_vector_scalar') @@ -301,9 +301,9 @@ Expression: x * y ) .fn(async t => { const vec_size = t.params.vectorize_lhs; - const vec_type = TypeVec(vec_size, TypeU32); + const vec_type = Type.vec(vec_size, Type.u32); const cases = await d.get(`multiplication_vector${vec_size}_scalar`); - await run(t, binary('*'), [vec_type, TypeU32], vec_type, t.params, cases); + await run(t, binary('*'), [vec_type, Type.u32], vec_type, t.params, cases); }); g.test('multiplication_vector_scalar_compound') @@ -318,9 +318,9 @@ Expression: x *= y ) .fn(async t => { const vec_size = t.params.vectorize_lhs; - const vec_type = TypeVec(vec_size, TypeU32); + const vec_type = Type.vec(vec_size, Type.u32); const cases = await d.get(`multiplication_vector${vec_size}_scalar`); - await run(t, compoundBinary('*='), [vec_type, TypeU32], vec_type, t.params, cases); + await run(t, compoundBinary('*='), [vec_type, Type.u32], vec_type, t.params, cases); }); g.test('division_scalar_vector') @@ -335,10 +335,10 @@ Expression: x / y ) .fn(async t => { const vec_size = t.params.vectorize_rhs; - const vec_type = TypeVec(vec_size, TypeU32); + const vec_type = Type.vec(vec_size, Type.u32); const source = t.params.inputSource === 'const' ? 'const' : 'non_const'; const cases = await d.get(`division_scalar_vector${vec_size}_${source}`); - await run(t, binary('/'), [TypeU32, vec_type], vec_type, t.params, cases); + await run(t, binary('/'), [Type.u32, vec_type], vec_type, t.params, cases); }); g.test('division_vector_scalar') @@ -353,10 +353,10 @@ Expression: x / y ) .fn(async t => { const vec_size = t.params.vectorize_lhs; - const vec_type = TypeVec(vec_size, TypeU32); + const vec_type = Type.vec(vec_size, Type.u32); const source = t.params.inputSource === 'const' ? 'const' : 'non_const'; const cases = await d.get(`division_vector${vec_size}_scalar_${source}`); - await run(t, binary('/'), [vec_type, TypeU32], vec_type, t.params, cases); + await run(t, binary('/'), [vec_type, Type.u32], vec_type, t.params, cases); }); g.test('division_vector_scalar_compound') @@ -371,10 +371,10 @@ Expression: x /= y ) .fn(async t => { const vec_size = t.params.vectorize_lhs; - const vec_type = TypeVec(vec_size, TypeU32); + const vec_type = Type.vec(vec_size, Type.u32); const source = t.params.inputSource === 'const' ? 'const' : 'non_const'; const cases = await d.get(`division_vector${vec_size}_scalar_${source}`); - await run(t, compoundBinary('/='), [vec_type, TypeU32], vec_type, t.params, cases); + await run(t, compoundBinary('/='), [vec_type, Type.u32], vec_type, t.params, cases); }); g.test('remainder_scalar_vector') @@ -389,10 +389,10 @@ Expression: x % y ) .fn(async t => { const vec_size = t.params.vectorize_rhs; - const vec_type = TypeVec(vec_size, TypeU32); + const vec_type = Type.vec(vec_size, Type.u32); const source = t.params.inputSource === 'const' ? 'const' : 'non_const'; const cases = await d.get(`remainder_scalar_vector${vec_size}_${source}`); - await run(t, binary('%'), [TypeU32, vec_type], vec_type, t.params, cases); + await run(t, binary('%'), [Type.u32, vec_type], vec_type, t.params, cases); }); g.test('remainder_vector_scalar') @@ -407,10 +407,10 @@ Expression: x % y ) .fn(async t => { const vec_size = t.params.vectorize_lhs; - const vec_type = TypeVec(vec_size, TypeU32); + const vec_type = Type.vec(vec_size, Type.u32); const source = t.params.inputSource === 'const' ? 'const' : 'non_const'; const cases = await d.get(`remainder_vector${vec_size}_scalar_${source}`); - await run(t, binary('%'), [vec_type, TypeU32], vec_type, t.params, cases); + await run(t, binary('%'), [vec_type, Type.u32], vec_type, t.params, cases); }); g.test('remainder_vector_scalar_compound') @@ -425,8 +425,8 @@ Expression: x %= y ) .fn(async t => { const vec_size = t.params.vectorize_lhs; - const vec_type = TypeVec(vec_size, TypeU32); + const vec_type = Type.vec(vec_size, Type.u32); const source = t.params.inputSource === 'const' ? 'const' : 'non_const'; const cases = await d.get(`remainder_vector${vec_size}_scalar_${source}`); - await run(t, compoundBinary('%='), [vec_type, TypeU32], vec_type, t.params, cases); + await run(t, compoundBinary('%='), [vec_type, Type.u32], vec_type, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/binary/u32_comparison.spec.ts b/src/webgpu/shader/execution/expression/binary/u32_comparison.spec.ts index fbf34b510394..5bb6767b01e0 100644 --- a/src/webgpu/shader/execution/expression/binary/u32_comparison.spec.ts +++ b/src/webgpu/shader/execution/expression/binary/u32_comparison.spec.ts @@ -4,7 +4,7 @@ Execution Tests for the u32 comparison expressions import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeBool, TypeU32 } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { allInputSources, run } from '../expression.js'; import { binary } from './binary.js'; @@ -24,7 +24,7 @@ Expression: x == y ) .fn(async t => { const cases = await d.get('equals'); - await run(t, binary('=='), [TypeU32, TypeU32], TypeBool, t.params, cases); + await run(t, binary('=='), [Type.u32, Type.u32], Type.bool, t.params, cases); }); g.test('not_equals') @@ -39,7 +39,7 @@ Expression: x != y ) .fn(async t => { const cases = await d.get('not_equals'); - await run(t, binary('!='), [TypeU32, TypeU32], TypeBool, t.params, cases); + await run(t, binary('!='), [Type.u32, Type.u32], Type.bool, t.params, cases); }); g.test('less_than') @@ -54,7 +54,7 @@ Expression: x < y ) .fn(async t => { const cases = await d.get('less_than'); - await run(t, binary('<'), [TypeU32, TypeU32], TypeBool, t.params, cases); + await run(t, binary('<'), [Type.u32, Type.u32], Type.bool, t.params, cases); }); g.test('less_equals') @@ -69,7 +69,7 @@ Expression: x <= y ) .fn(async t => { const cases = await d.get('less_equal'); - await run(t, binary('<='), [TypeU32, TypeU32], TypeBool, t.params, cases); + await run(t, binary('<='), [Type.u32, Type.u32], Type.bool, t.params, cases); }); g.test('greater_than') @@ -84,7 +84,7 @@ Expression: x > y ) .fn(async t => { const cases = await d.get('greater_than'); - await run(t, binary('>'), [TypeU32, TypeU32], TypeBool, t.params, cases); + await run(t, binary('>'), [Type.u32, Type.u32], Type.bool, t.params, cases); }); g.test('greater_equals') @@ -99,5 +99,5 @@ Expression: x >= y ) .fn(async t => { const cases = await d.get('greater_equal'); - await run(t, binary('>='), [TypeU32, TypeU32], TypeBool, t.params, cases); + await run(t, binary('>='), [Type.u32, Type.u32], Type.bool, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/abs.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/abs.spec.ts index c7f6d1d57cae..75d41ab16377 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/abs.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/abs.spec.ts @@ -1,14 +1,14 @@ export const description = ` Execution tests for the 'abs' builtin function -S is AbstractInt, i32, or u32 +S is abstract-int, i32, or u32 T is S or vecN @const fn abs(e: T ) -> T The absolute value of e. Component-wise when T is a vector. If e is a signed integral scalar type and evaluates to the largest negative value, then the result is e. If e is an unsigned integral type, then the result is e. -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn abs(e: T ) -> T Returns the absolute value of e (e.g. e with a positive sign bit). @@ -18,16 +18,7 @@ Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; import { kBit } from '../../../../../util/constants.js'; -import { - i32Bits, - TypeF32, - TypeF16, - TypeI32, - TypeU32, - u32Bits, - TypeAbstractFloat, - TypeAbstractInt, -} from '../../../../../util/conversion.js'; +import { Type, i32Bits, u32Bits } from '../../../../../util/conversion.js'; import { allInputSources, onlyConstInputSource, run } from '../../expression.js'; import { d } from './abs.cache.js'; @@ -45,7 +36,7 @@ g.test('abstract_int') ) .fn(async t => { const cases = await d.get('abstract_int'); - await run(t, abstractIntBuiltin('abs'), [TypeAbstractInt], TypeAbstractInt, t.params, cases); + await run(t, abstractIntBuiltin('abs'), [Type.abstractInt], Type.abstractInt, t.params, cases); }); g.test('u32') @@ -55,7 +46,7 @@ g.test('u32') u.combine('inputSource', allInputSources).combine('vectorize', [undefined, 2, 3, 4] as const) ) .fn(async t => { - await run(t, builtin('abs'), [TypeU32], TypeU32, t.params, [ + await run(t, builtin('abs'), [Type.u32], Type.u32, t.params, [ // Min and Max u32 { input: u32Bits(kBit.u32.min), expected: u32Bits(kBit.u32.min) }, { input: u32Bits(kBit.u32.max), expected: u32Bits(kBit.u32.max) }, @@ -102,7 +93,7 @@ g.test('i32') u.combine('inputSource', allInputSources).combine('vectorize', [undefined, 2, 3, 4] as const) ) .fn(async t => { - await run(t, builtin('abs'), [TypeI32], TypeI32, t.params, [ + await run(t, builtin('abs'), [Type.i32], Type.i32, t.params, [ // Min and max i32 // If e evaluates to the largest negative value, then the result is e. { input: i32Bits(kBit.i32.negative.min), expected: i32Bits(kBit.i32.negative.min) }, @@ -158,8 +149,8 @@ g.test('abstract_float') await run( t, abstractFloatBuiltin('abs'), - [TypeAbstractFloat], - TypeAbstractFloat, + [Type.abstractFloat], + Type.abstractFloat, t.params, cases ); @@ -173,7 +164,7 @@ g.test('f32') ) .fn(async t => { const cases = await d.get('f32'); - await run(t, builtin('abs'), [TypeF32], TypeF32, t.params, cases); + await run(t, builtin('abs'), [Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -187,5 +178,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get('f16'); - await run(t, builtin('abs'), [TypeF16], TypeF16, t.params, cases); + await run(t, builtin('abs'), [Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/acos.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/acos.spec.ts index 1d489e1191b8..7d6b224579a9 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/acos.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/acos.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'acos' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn acos(e: T ) -> T Returns the arc cosine of e. Component-wise when T is a vector. @@ -9,7 +9,7 @@ Returns the arc cosine of e. Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF32, TypeF16 } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { d } from './acos.cache.js'; @@ -33,7 +33,7 @@ g.test('f32') ) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f32_const' : 'f32_non_const'); - await run(t, builtin('acos'), [TypeF32], TypeF32, t.params, cases); + await run(t, builtin('acos'), [Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -47,5 +47,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f16_const' : 'f16_non_const'); - await run(t, builtin('acos'), [TypeF16], TypeF16, t.params, cases); + await run(t, builtin('acos'), [Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/acosh.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/acosh.spec.ts index 737bd5677241..ed34d326de1a 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/acosh.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/acosh.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'acosh' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn acosh(e: T ) -> T Returns the hyperbolic arc cosine of e. The result is 0 when e < 1. @@ -13,7 +13,7 @@ Note: The result is not mathematically meaningful when e < 1. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF16, TypeF32 } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { d } from './acosh.cache.js'; @@ -37,7 +37,7 @@ g.test('f32') ) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f32_const' : 'f32_non_const'); - await run(t, builtin('acosh'), [TypeF32], TypeF32, t.params, cases); + await run(t, builtin('acosh'), [Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -51,5 +51,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f16_const' : 'f16_non_const'); - await run(t, builtin('acosh'), [TypeF16], TypeF16, t.params, cases); + await run(t, builtin('acosh'), [Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/all.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/all.spec.ts index 9a2938c1d500..74e072703d94 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/all.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/all.spec.ts @@ -10,15 +10,7 @@ Returns true if each component of e is true if e is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { - False, - True, - TypeBool, - TypeVec, - vec2, - vec3, - vec4, -} from '../../../../../util/conversion.js'; +import { False, True, Type, vec2, vec3, vec4 } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -36,14 +28,14 @@ g.test('bool') .fn(async t => { const overloads = { scalar: { - type: TypeBool, + type: Type.bool, cases: [ { input: False, expected: False }, { input: True, expected: True }, ], }, vec2: { - type: TypeVec(2, TypeBool), + type: Type.vec(2, Type.bool), cases: [ { input: vec2(False, False), expected: False }, { input: vec2(True, False), expected: False }, @@ -52,7 +44,7 @@ g.test('bool') ], }, vec3: { - type: TypeVec(3, TypeBool), + type: Type.vec(3, Type.bool), cases: [ { input: vec3(False, False, False), expected: False }, { input: vec3(True, False, False), expected: False }, @@ -65,7 +57,7 @@ g.test('bool') ], }, vec4: { - type: TypeVec(4, TypeBool), + type: Type.vec(4, Type.bool), cases: [ { input: vec4(False, False, False, False), expected: False }, { input: vec4(False, True, False, False), expected: False }, @@ -88,5 +80,5 @@ g.test('bool') }; const overload = overloads[t.params.overload]; - await run(t, builtin('all'), [overload.type], TypeBool, t.params, overload.cases); + await run(t, builtin('all'), [overload.type], Type.bool, t.params, overload.cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/any.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/any.spec.ts index 19ed7d186f7b..43c599e2aa4b 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/any.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/any.spec.ts @@ -10,15 +10,7 @@ Returns true if any component of e is true if e is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { - False, - True, - TypeBool, - TypeVec, - vec2, - vec3, - vec4, -} from '../../../../../util/conversion.js'; +import { False, True, Type, vec2, vec3, vec4 } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -36,14 +28,14 @@ g.test('bool') .fn(async t => { const overloads = { scalar: { - type: TypeBool, + type: Type.bool, cases: [ { input: False, expected: False }, { input: True, expected: True }, ], }, vec2: { - type: TypeVec(2, TypeBool), + type: Type.vec(2, Type.bool), cases: [ { input: vec2(False, False), expected: False }, { input: vec2(True, False), expected: True }, @@ -52,7 +44,7 @@ g.test('bool') ], }, vec3: { - type: TypeVec(3, TypeBool), + type: Type.vec(3, Type.bool), cases: [ { input: vec3(False, False, False), expected: False }, { input: vec3(True, False, False), expected: True }, @@ -65,7 +57,7 @@ g.test('bool') ], }, vec4: { - type: TypeVec(4, TypeBool), + type: Type.vec(4, Type.bool), cases: [ { input: vec4(False, False, False, False), expected: False }, { input: vec4(False, True, False, False), expected: True }, @@ -88,5 +80,5 @@ g.test('bool') }; const overload = overloads[t.params.overload]; - await run(t, builtin('any'), [overload.type], TypeBool, t.params, overload.cases); + await run(t, builtin('any'), [overload.type], Type.bool, t.params, overload.cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/asin.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/asin.spec.ts index 8a7934936030..5ff882d28a34 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/asin.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/asin.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'asin' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn asin(e: T ) -> T Returns the arc sine of e. Component-wise when T is a vector. @@ -9,7 +9,7 @@ Returns the arc sine of e. Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF16, TypeF32 } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { d } from './asin.cache.js'; @@ -33,7 +33,7 @@ g.test('f32') ) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f32_const' : 'f32_non_const'); - await run(t, builtin('asin'), [TypeF32], TypeF32, t.params, cases); + await run(t, builtin('asin'), [Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -47,5 +47,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f16_const' : 'f16_non_const'); - await run(t, builtin('asin'), [TypeF16], TypeF16, t.params, cases); + await run(t, builtin('asin'), [Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/asinh.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/asinh.spec.ts index b5f362066b85..21f2584cac98 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/asinh.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/asinh.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'sinh' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn asinh(e: T ) -> T Returns the hyperbolic arc sine of e. @@ -12,7 +12,7 @@ Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF16, TypeF32 } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { d } from './asinh.cache.js'; @@ -36,7 +36,7 @@ g.test('f32') ) .fn(async t => { const cases = await d.get('f32'); - await run(t, builtin('asinh'), [TypeF32], TypeF32, t.params, cases); + await run(t, builtin('asinh'), [Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -50,5 +50,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get('f16'); - await run(t, builtin('asinh'), [TypeF16], TypeF16, t.params, cases); + await run(t, builtin('asinh'), [Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/atan.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/atan.spec.ts index 173fb0a0010e..355529eb8dfe 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/atan.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/atan.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'atan' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn atan(e: T ) -> T Returns the arc tangent of e. Component-wise when T is a vector. @@ -10,7 +10,7 @@ Returns the arc tangent of e. Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF16, TypeF32 } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { d } from './atan.cache.js'; @@ -40,7 +40,7 @@ TODO(#792): Decide what the ground-truth is for these tests. [1] ) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f32_const' : 'f32_non_const'); - await run(t, builtin('atan'), [TypeF32], TypeF32, t.params, cases); + await run(t, builtin('atan'), [Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -54,5 +54,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f16_const' : 'f16_non_const'); - await run(t, builtin('atan'), [TypeF16], TypeF16, t.params, cases); + await run(t, builtin('atan'), [Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/atan2.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/atan2.spec.ts index dff1d442f56b..707820c2abdb 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/atan2.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/atan2.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'atan2' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn atan2(e1: T ,e2: T ) -> T Returns the arc tangent of e1 over e2. Component-wise when T is a vector. @@ -9,7 +9,7 @@ Returns the arc tangent of e1 over e2. Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF16, TypeF32 } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { d } from './atan2.cache.js'; @@ -39,7 +39,7 @@ TODO(#792): Decide what the ground-truth is for these tests. [1] ) .fn(async t => { const cases = await d.get(`f32_${t.params.inputSource === 'const' ? 'const' : 'non_const'}`); - await run(t, builtin('atan2'), [TypeF32, TypeF32], TypeF32, t.params, cases); + await run(t, builtin('atan2'), [Type.f32, Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -53,5 +53,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get(`f16_${t.params.inputSource === 'const' ? 'const' : 'non_const'}`); - await run(t, builtin('atan2'), [TypeF16, TypeF16], TypeF16, t.params, cases); + await run(t, builtin('atan2'), [Type.f16, Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/atanh.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/atanh.spec.ts index 31c14110b662..fe43c2161336 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/atanh.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/atanh.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'atanh' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn atanh(e: T ) -> T Returns the hyperbolic arc tangent of e. The result is 0 when abs(e) ≥ 1. @@ -12,7 +12,7 @@ Note: The result is not mathematically meaningful when abs(e) >= 1. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF16, TypeF32 } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { d } from './atanh.cache.js'; @@ -36,7 +36,7 @@ g.test('f32') ) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f32_const' : 'f32_non_const'); - await run(t, builtin('atanh'), [TypeF32], TypeF32, t.params, cases); + await run(t, builtin('atanh'), [Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -50,5 +50,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f16_const' : 'f16_non_const'); - await run(t, builtin('atanh'), [TypeF16], TypeF16, t.params, cases); + await run(t, builtin('atanh'), [Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/bitcast.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/bitcast.cache.ts index a3f2ee35b29b..b64d3692121e 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/bitcast.cache.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/bitcast.cache.ts @@ -2,8 +2,8 @@ import { assert } from '../../../../../../common/util/util.js'; import { Comparator, alwaysPass, anyOf } from '../../../../../util/compare.js'; import { kBit, kValue } from '../../../../../util/constants.js'; import { - Scalar, - Vector, + ScalarValue, + VectorValue, f16, f32, i32, @@ -63,7 +63,7 @@ const f32ZerosInterval: FPInterval = new FPInterval('f32', -0.0, 0.0); const f32FiniteRange: number[] = [...scalarF32Range(), kValue.f32.negative.zero]; const f32RangeWithInfAndNaN: number[] = [...f32FiniteRange, ...f32InfAndNaNInF32]; -// F16 values, finite, Inf/NaN, and zeros. Represented in float and u16. +// Type.f16 values, finite, Inf/NaN, and zeros. Represented in float and u16. const f16FiniteInF16: number[] = [...scalarF16Range(), kValue.f16.negative.zero]; const f16FiniteInU16: number[] = f16FiniteInF16.map(u => reinterpretF16AsU16(u)); @@ -118,7 +118,7 @@ function u32ToU16x2(u32: number): number[] { /** * @returns a vec2 from an array of two u16, each reinterpreted as f16. */ -function u16x2ToVec2F16(u16x2: number[]): Vector { +function u16x2ToVec2F16(u16x2: number[]): VectorValue { assert(u16x2.length === 2); return toVector(u16x2.map(reinterpretU16AsF16), f16); } @@ -126,7 +126,7 @@ function u16x2ToVec2F16(u16x2: number[]): Vector { /** * @returns a vec4 from an array of four u16, each reinterpreted as f16. */ -function u16x4ToVec4F16(u16x4: number[]): Vector { +function u16x4ToVec4F16(u16x4: number[]): VectorValue { assert(u16x4.length === 4); return toVector(u16x4.map(reinterpretU16AsF16), f16); } @@ -433,7 +433,7 @@ function bitcastVec2F32ToVec4F16Comparator(f32x2: number[]): Comparator { interface ExpectionFor32BitsScalarFromF16x2 { // possibleExpectations is Scalar array if the expectation is for i32/u32 and FPInterval array for // f32. Note that if the expectation for i32/u32 is unbound, possibleExpectations is meaningless. - possibleExpectations: (Scalar | FPInterval)[]; + possibleExpectations: (ScalarValue | FPInterval)[]; isUnbounded: boolean; } @@ -458,8 +458,8 @@ function possible32BitScalarIntervalsFromF16x2( ): ExpectionFor32BitsScalarFromF16x2 { assert(f16x2InU16x2.length === 2); let reinterpretFromU32: (x: number) => number; - let expectationsForValue: (x: number) => Scalar[] | FPInterval[]; - let unboundedExpectations: FPInterval[] | Scalar[]; + let expectationsForValue: (x: number) => ScalarValue[] | FPInterval[]; + let unboundedExpectations: FPInterval[] | ScalarValue[]; if (type === 'u32') { reinterpretFromU32 = (x: number) => x; expectationsForValue = x => [u32(x)]; @@ -498,12 +498,12 @@ function possible32BitScalarIntervalsFromF16x2( return { possibleExpectations: unboundedExpectations, isUnbounded: true }; } const possibleU16Bits = f16x2InU16x2.map(possibleBitsInU16FromFiniteF16InU16); - const possibleExpectations = cartesianProduct(...possibleU16Bits).flatMap( - (possibleBitsU16x2: readonly number[]) => { - assert(possibleBitsU16x2.length === 2); - return expectationsForValue(reinterpretFromU32(u16x2ToU32(possibleBitsU16x2))); - } - ); + const possibleExpectations = cartesianProduct(...possibleU16Bits).flatMap< + ScalarValue | FPInterval + >((possibleBitsU16x2: readonly number[]) => { + assert(possibleBitsU16x2.length === 2); + return expectationsForValue(reinterpretFromU32(u16x2ToU32(possibleBitsU16x2))); + }); return { possibleExpectations, isUnbounded: false }; } @@ -566,7 +566,7 @@ function bitcastVec4F16ToVec2U32Comparator(vec4F16InU16x4: number[]): Comparator } return anyOf( ...cartesianProduct(...expectationsPerElement.map(e => e.possibleExpectations)).map( - e => new Vector(e as Scalar[]) + e => new VectorValue(e as ScalarValue[]) ) ); } @@ -588,7 +588,7 @@ function bitcastVec4F16ToVec2I32Comparator(vec4F16InU16x4: number[]): Comparator } return anyOf( ...cartesianProduct(...expectationsPerElement.map(e => e.possibleExpectations)).map( - e => new Vector(e as Scalar[]) + e => new VectorValue(e as ScalarValue[]) ) ); } diff --git a/src/webgpu/shader/execution/expression/call/builtin/bitcast.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/bitcast.spec.ts index 5e7add44048d..0ead5af05a5b 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/bitcast.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/bitcast.spec.ts @@ -11,8 +11,8 @@ S is i32, u32, f32 T is i32, u32, f32, and T is not S Reinterpretation of bits. Beware non-normal f32 values. -@const @must_use fn bitcast(e : AbstractInt) -> T -@const @must_use fn bitcast>(e : vecN) -> T +@const @must_use fn bitcast(e : Type.abstractInt) -> T +@const @must_use fn bitcast>(e : vecN) -> T @const @must_use fn bitcast(e: vec2 ) -> T @const @must_use fn bitcast>(e: vec4 ) -> vec2 @@ -26,18 +26,13 @@ import { makeTestGroup } from '../../../../../../common/framework/test_group.js' import { GPUTest } from '../../../../../gpu_test.js'; import { anyOf } from '../../../../../util/compare.js'; import { - TypeF16, - TypeF32, - TypeI32, - TypeU32, - TypeVec, - TypeAbstractFloat, f32, u32, i32, abstractFloat, uint32ToFloat32, u32Bits, + Type, } from '../../../../../util/conversion.js'; import { FP } from '../../../../../util/floating_point.js'; import { scalarF32Range } from '../../../../../util/math.js'; @@ -76,7 +71,7 @@ g.test('i32_to_i32') ) .fn(async t => { const cases = await d.get('i32_to_i32'); - await run(t, bitcastBuilder('i32', t.params), [TypeI32], TypeI32, t.params, cases); + await run(t, bitcastBuilder('i32', t.params), [Type.i32], Type.i32, t.params, cases); }); g.test('u32_to_u32') @@ -90,7 +85,7 @@ g.test('u32_to_u32') ) .fn(async t => { const cases = await d.get('u32_to_u32'); - await run(t, bitcastBuilder('u32', t.params), [TypeU32], TypeU32, t.params, cases); + await run(t, bitcastBuilder('u32', t.params), [Type.u32], Type.u32, t.params, cases); }); g.test('f32_to_f32') @@ -107,7 +102,7 @@ g.test('f32_to_f32') // Infinities and NaNs are errors in const-eval. t.params.inputSource === 'const' ? 'f32_to_f32' : 'f32_inf_nan_to_f32' ); - await run(t, bitcastBuilder('f32', t.params), [TypeF32], TypeF32, t.params, cases); + await run(t, bitcastBuilder('f32', t.params), [Type.f32], Type.f32, t.params, cases); }); // To i32 from u32, f32 @@ -122,7 +117,7 @@ g.test('u32_to_i32') ) .fn(async t => { const cases = await d.get('u32_to_i32'); - await run(t, bitcastBuilder('i32', t.params), [TypeU32], TypeI32, t.params, cases); + await run(t, bitcastBuilder('i32', t.params), [Type.u32], Type.i32, t.params, cases); }); g.test('f32_to_i32') @@ -139,7 +134,7 @@ g.test('f32_to_i32') // Infinities and NaNs are errors in const-eval. t.params.inputSource === 'const' ? 'f32_to_i32' : 'f32_inf_nan_to_i32' ); - await run(t, bitcastBuilder('i32', t.params), [TypeF32], TypeI32, t.params, cases); + await run(t, bitcastBuilder('i32', t.params), [Type.f32], Type.i32, t.params, cases); }); // To u32 from i32, f32 @@ -154,7 +149,7 @@ g.test('i32_to_u32') ) .fn(async t => { const cases = await d.get('i32_to_u32'); - await run(t, bitcastBuilder('u32', t.params), [TypeI32], TypeU32, t.params, cases); + await run(t, bitcastBuilder('u32', t.params), [Type.i32], Type.u32, t.params, cases); }); g.test('f32_to_u32') @@ -171,7 +166,7 @@ g.test('f32_to_u32') // Infinities and NaNs are errors in const-eval. t.params.inputSource === 'const' ? 'f32_to_u32' : 'f32_inf_nan_to_u32' ); - await run(t, bitcastBuilder('u32', t.params), [TypeF32], TypeU32, t.params, cases); + await run(t, bitcastBuilder('u32', t.params), [Type.f32], Type.u32, t.params, cases); }); // To f32 from i32, u32 @@ -189,7 +184,7 @@ g.test('i32_to_f32') // Infinities and NaNs are errors in const-eval. t.params.inputSource === 'const' ? 'i32_to_f32' : 'i32_to_f32_inf_nan' ); - await run(t, bitcastBuilder('f32', t.params), [TypeI32], TypeF32, t.params, cases); + await run(t, bitcastBuilder('f32', t.params), [Type.i32], Type.f32, t.params, cases); }); g.test('u32_to_f32') @@ -206,7 +201,7 @@ g.test('u32_to_f32') // Infinities and NaNs are errors in const-eval. t.params.inputSource === 'const' ? 'u32_to_f32' : 'u32_to_f32_inf_nan' ); - await run(t, bitcastBuilder('f32', t.params), [TypeU32], TypeF32, t.params, cases); + await run(t, bitcastBuilder('f32', t.params), [Type.u32], Type.f32, t.params, cases); }); // 16 bit types @@ -231,7 +226,7 @@ g.test('f16_to_f16') // Infinities and NaNs are errors in const-eval. t.params.inputSource === 'const' ? 'f16_to_f16' : 'f16_inf_nan_to_f16' ); - await run(t, bitcastBuilder('f16', t.params), [TypeF16], TypeF16, t.params, cases); + await run(t, bitcastBuilder('f16', t.params), [Type.f16], Type.f16, t.params, cases); }); // f16: 32-bit scalar numeric to vec2 @@ -247,14 +242,7 @@ g.test('i32_to_vec2h') // Infinities and NaNs are errors in const-eval. t.params.inputSource === 'const' ? 'i32_to_vec2_f16' : 'i32_to_vec2_f16_inf_nan' ); - await run( - t, - bitcastBuilder('vec2', t.params), - [TypeI32], - TypeVec(2, TypeF16), - t.params, - cases - ); + await run(t, bitcastBuilder('vec2', t.params), [Type.i32], Type.vec2h, t.params, cases); }); g.test('u32_to_vec2h') @@ -269,14 +257,7 @@ g.test('u32_to_vec2h') // Infinities and NaNs are errors in const-eval. t.params.inputSource === 'const' ? 'u32_to_vec2_f16' : 'u32_to_vec2_f16_inf_nan' ); - await run( - t, - bitcastBuilder('vec2', t.params), - [TypeU32], - TypeVec(2, TypeF16), - t.params, - cases - ); + await run(t, bitcastBuilder('vec2', t.params), [Type.u32], Type.vec2h, t.params, cases); }); g.test('f32_to_vec2h') @@ -291,14 +272,7 @@ g.test('f32_to_vec2h') // Infinities and NaNs are errors in const-eval. t.params.inputSource === 'const' ? 'f32_to_vec2_f16' : 'f32_inf_nan_to_vec2_f16_inf_nan' ); - await run( - t, - bitcastBuilder('vec2', t.params), - [TypeF32], - TypeVec(2, TypeF16), - t.params, - cases - ); + await run(t, bitcastBuilder('vec2', t.params), [Type.f32], Type.vec2h, t.params, cases); }); // f16: vec2<32-bit scalar numeric> to vec4 @@ -314,14 +288,7 @@ g.test('vec2i_to_vec4h') // Infinities and NaNs are errors in const-eval. t.params.inputSource === 'const' ? 'vec2_i32_to_vec4_f16' : 'vec2_i32_to_vec4_f16_inf_nan' ); - await run( - t, - bitcastBuilder('vec4', t.params), - [TypeVec(2, TypeI32)], - TypeVec(4, TypeF16), - t.params, - cases - ); + await run(t, bitcastBuilder('vec4', t.params), [Type.vec2i], Type.vec4h, t.params, cases); }); g.test('vec2u_to_vec4h') @@ -336,14 +303,7 @@ g.test('vec2u_to_vec4h') // Infinities and NaNs are errors in const-eval. t.params.inputSource === 'const' ? 'vec2_u32_to_vec4_f16' : 'vec2_u32_to_vec4_f16_inf_nan' ); - await run( - t, - bitcastBuilder('vec4', t.params), - [TypeVec(2, TypeU32)], - TypeVec(4, TypeF16), - t.params, - cases - ); + await run(t, bitcastBuilder('vec4', t.params), [Type.vec2u], Type.vec4h, t.params, cases); }); g.test('vec2f_to_vec4h') @@ -360,14 +320,7 @@ g.test('vec2f_to_vec4h') ? 'vec2_f32_to_vec4_f16' : 'vec2_f32_inf_nan_to_vec4_f16_inf_nan' ); - await run( - t, - bitcastBuilder('vec4', t.params), - [TypeVec(2, TypeF32)], - TypeVec(4, TypeF16), - t.params, - cases - ); + await run(t, bitcastBuilder('vec4', t.params), [Type.vec2f], Type.vec4h, t.params, cases); }); // f16: vec2 to 32-bit scalar numeric @@ -383,7 +336,7 @@ g.test('vec2h_to_i32') // Infinities and NaNs are errors in const-eval. t.params.inputSource === 'const' ? 'vec2_f16_to_i32' : 'vec2_f16_inf_nan_to_i32' ); - await run(t, bitcastBuilder('i32', t.params), [TypeVec(2, TypeF16)], TypeI32, t.params, cases); + await run(t, bitcastBuilder('i32', t.params), [Type.vec2h], Type.i32, t.params, cases); }); g.test('vec2h_to_u32') @@ -398,7 +351,7 @@ g.test('vec2h_to_u32') // Infinities and NaNs are errors in const-eval. t.params.inputSource === 'const' ? 'vec2_f16_to_u32' : 'vec2_f16_inf_nan_to_u32' ); - await run(t, bitcastBuilder('u32', t.params), [TypeVec(2, TypeF16)], TypeU32, t.params, cases); + await run(t, bitcastBuilder('u32', t.params), [Type.vec2h], Type.u32, t.params, cases); }); g.test('vec2h_to_f32') @@ -413,7 +366,7 @@ g.test('vec2h_to_f32') // Infinities and NaNs are errors in const-eval. t.params.inputSource === 'const' ? 'vec2_f16_to_f32_finite' : 'vec2_f16_inf_nan_to_f32' ); - await run(t, bitcastBuilder('f32', t.params), [TypeVec(2, TypeF16)], TypeF32, t.params, cases); + await run(t, bitcastBuilder('f32', t.params), [Type.vec2h], Type.f32, t.params, cases); }); // f16: vec4 to vec2<32-bit scalar numeric> @@ -429,14 +382,7 @@ g.test('vec4h_to_vec2i') // Infinities and NaNs are errors in const-eval. t.params.inputSource === 'const' ? 'vec4_f16_to_vec2_i32' : 'vec4_f16_inf_nan_to_vec2_i32' ); - await run( - t, - bitcastBuilder('vec2', t.params), - [TypeVec(4, TypeF16)], - TypeVec(2, TypeI32), - t.params, - cases - ); + await run(t, bitcastBuilder('vec2', t.params), [Type.vec4h], Type.vec2i, t.params, cases); }); g.test('vec4h_to_vec2u') @@ -451,14 +397,7 @@ g.test('vec4h_to_vec2u') // Infinities and NaNs are errors in const-eval. t.params.inputSource === 'const' ? 'vec4_f16_to_vec2_u32' : 'vec4_f16_inf_nan_to_vec2_u32' ); - await run( - t, - bitcastBuilder('vec2', t.params), - [TypeVec(4, TypeF16)], - TypeVec(2, TypeU32), - t.params, - cases - ); + await run(t, bitcastBuilder('vec2', t.params), [Type.vec4h], Type.vec2u, t.params, cases); }); g.test('vec4h_to_vec2f') @@ -475,14 +414,7 @@ g.test('vec4h_to_vec2f') ? 'vec4_f16_to_vec2_f32_finite' : 'vec4_f16_inf_nan_to_vec2_f32' ); - await run( - t, - bitcastBuilder('vec2', t.params), - [TypeVec(4, TypeF16)], - TypeVec(2, TypeF32), - t.params, - cases - ); + await run(t, bitcastBuilder('vec2', t.params), [Type.vec4h], Type.vec2f, t.params, cases); }); // Abstract Float @@ -505,7 +437,7 @@ g.test('af_to_f32') }; }); - await run(t, bitcastBuilder('f32', t.params), [TypeAbstractFloat], TypeF32, t.params, cases); + await run(t, bitcastBuilder('f32', t.params), [Type.abstractFloat], Type.f32, t.params, cases); }); g.test('af_to_i32') @@ -522,24 +454,24 @@ g.test('af_to_i32') 1, 10, 256, - u32Bits(0b11111111011111111111111111111111).value as number, - u32Bits(0b11111111010000000000000000000000).value as number, - u32Bits(0b11111110110000000000000000000000).value as number, - u32Bits(0b11111101110000000000000000000000).value as number, - u32Bits(0b11111011110000000000000000000000).value as number, - u32Bits(0b11110111110000000000000000000000).value as number, - u32Bits(0b11101111110000000000000000000000).value as number, - u32Bits(0b11011111110000000000000000000000).value as number, - u32Bits(0b10111111110000000000000000000000).value as number, - u32Bits(0b01111111011111111111111111111111).value as number, - u32Bits(0b01111111010000000000000000000000).value as number, - u32Bits(0b01111110110000000000000000000000).value as number, - u32Bits(0b01111101110000000000000000000000).value as number, - u32Bits(0b01111011110000000000000000000000).value as number, - u32Bits(0b01110111110000000000000000000000).value as number, - u32Bits(0b01101111110000000000000000000000).value as number, - u32Bits(0b01011111110000000000000000000000).value as number, - u32Bits(0b00111111110000000000000000000000).value as number, + u32Bits(0b11111111011111111111111111111111).value, + u32Bits(0b11111111010000000000000000000000).value, + u32Bits(0b11111110110000000000000000000000).value, + u32Bits(0b11111101110000000000000000000000).value, + u32Bits(0b11111011110000000000000000000000).value, + u32Bits(0b11110111110000000000000000000000).value, + u32Bits(0b11101111110000000000000000000000).value, + u32Bits(0b11011111110000000000000000000000).value, + u32Bits(0b10111111110000000000000000000000).value, + u32Bits(0b01111111011111111111111111111111).value, + u32Bits(0b01111111010000000000000000000000).value, + u32Bits(0b01111110110000000000000000000000).value, + u32Bits(0b01111101110000000000000000000000).value, + u32Bits(0b01111011110000000000000000000000).value, + u32Bits(0b01110111110000000000000000000000).value, + u32Bits(0b01101111110000000000000000000000).value, + u32Bits(0b01011111110000000000000000000000).value, + u32Bits(0b00111111110000000000000000000000).value, ]; const cases = values.map(u => { @@ -549,7 +481,7 @@ g.test('af_to_i32') }; }); - await run(t, bitcastBuilder('i32', t.params), [TypeAbstractFloat], TypeI32, t.params, cases); + await run(t, bitcastBuilder('i32', t.params), [Type.abstractFloat], Type.i32, t.params, cases); }); g.test('af_to_u32') @@ -566,24 +498,24 @@ g.test('af_to_u32') 1, 10, 256, - u32Bits(0b11111111011111111111111111111111).value as number, - u32Bits(0b11111111010000000000000000000000).value as number, - u32Bits(0b11111110110000000000000000000000).value as number, - u32Bits(0b11111101110000000000000000000000).value as number, - u32Bits(0b11111011110000000000000000000000).value as number, - u32Bits(0b11110111110000000000000000000000).value as number, - u32Bits(0b11101111110000000000000000000000).value as number, - u32Bits(0b11011111110000000000000000000000).value as number, - u32Bits(0b10111111110000000000000000000000).value as number, - u32Bits(0b01111111011111111111111111111111).value as number, - u32Bits(0b01111111010000000000000000000000).value as number, - u32Bits(0b01111110110000000000000000000000).value as number, - u32Bits(0b01111101110000000000000000000000).value as number, - u32Bits(0b01111011110000000000000000000000).value as number, - u32Bits(0b01110111110000000000000000000000).value as number, - u32Bits(0b01101111110000000000000000000000).value as number, - u32Bits(0b01011111110000000000000000000000).value as number, - u32Bits(0b00111111110000000000000000000000).value as number, + u32Bits(0b11111111011111111111111111111111).value, + u32Bits(0b11111111010000000000000000000000).value, + u32Bits(0b11111110110000000000000000000000).value, + u32Bits(0b11111101110000000000000000000000).value, + u32Bits(0b11111011110000000000000000000000).value, + u32Bits(0b11110111110000000000000000000000).value, + u32Bits(0b11101111110000000000000000000000).value, + u32Bits(0b11011111110000000000000000000000).value, + u32Bits(0b10111111110000000000000000000000).value, + u32Bits(0b01111111011111111111111111111111).value, + u32Bits(0b01111111010000000000000000000000).value, + u32Bits(0b01111110110000000000000000000000).value, + u32Bits(0b01111101110000000000000000000000).value, + u32Bits(0b01111011110000000000000000000000).value, + u32Bits(0b01110111110000000000000000000000).value, + u32Bits(0b01101111110000000000000000000000).value, + u32Bits(0b01011111110000000000000000000000).value, + u32Bits(0b00111111110000000000000000000000).value, ]; const cases = values.map(u => { @@ -593,7 +525,7 @@ g.test('af_to_u32') }; }); - await run(t, bitcastBuilder('u32', t.params), [TypeAbstractFloat], TypeU32, t.params, cases); + await run(t, bitcastBuilder('u32', t.params), [Type.abstractFloat], Type.u32, t.params, cases); }); g.test('af_to_vec2f16') @@ -609,8 +541,8 @@ g.test('af_to_vec2f16') await run( t, bitcastBuilder('vec2', t.params), - [TypeAbstractFloat], - TypeVec(2, TypeF16), + [Type.abstractFloat], + Type.vec2h, t.params, cases ); @@ -629,8 +561,8 @@ g.test('vec2af_to_vec4f16') await run( t, bitcastBuilder('vec4', t.params), - [TypeVec(2, TypeAbstractFloat)], - TypeVec(4, TypeF16), + [Type.vec(2, Type.abstractFloat)], + Type.vec4h, t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/call/builtin/ceil.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/ceil.cache.ts index 3141d1d1a16f..c0178d9b83ad 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/ceil.cache.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/ceil.cache.ts @@ -7,10 +7,11 @@ const kSmallMagnitudeTestValues = [0.1, 0.9, 1.0, 1.1, 1.9, -0.1, -0.9, -1.0, -1 const kIssue2766Value = { f32: 0x8000_0000, f16: 0x8000, + abstract: 0x8000_0000_0000_0000, }; // Cases: [f32|f16] -const cases = (['f32', 'f16'] as const) +const cases = (['f32', 'f16', 'abstract'] as const) .map(trait => ({ [`${trait}`]: () => { return FP[trait].generateScalarToIntervalCases( diff --git a/src/webgpu/shader/execution/expression/call/builtin/ceil.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/ceil.spec.ts index 18509efdffb9..842875f0940f 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/ceil.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/ceil.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'ceil' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn ceil(e: T ) -> T Returns the ceiling of e. Component-wise when T is a vector. @@ -10,10 +10,10 @@ Returns the ceiling of e. Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF16, TypeF32 } from '../../../../../util/conversion.js'; -import { allInputSources, run } from '../../expression.js'; +import { Type } from '../../../../../util/conversion.js'; +import { allInputSources, onlyConstInputSource, run } from '../../expression.js'; -import { builtin } from './builtin.js'; +import { abstractFloatBuiltin, builtin } from './builtin.js'; import { d } from './ceil.cache.js'; export const g = makeTestGroup(GPUTest); @@ -22,9 +22,21 @@ 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', [undefined, 2, 3, 4] as const) + u + .combine('inputSource', onlyConstInputSource) + .combine('vectorize', [undefined, 2, 3, 4] as const) ) - .unimplemented(); + .fn(async t => { + const cases = await d.get('abstract'); + await run( + t, + abstractFloatBuiltin('ceil'), + [Type.abstractFloat], + Type.abstractFloat, + t.params, + cases + ); + }); g.test('f32') .specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions') @@ -34,7 +46,7 @@ g.test('f32') ) .fn(async t => { const cases = await d.get('f32'); - await run(t, builtin('ceil'), [TypeF32], TypeF32, t.params, cases); + await run(t, builtin('ceil'), [Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -48,5 +60,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get('f16'); - await run(t, builtin('ceil'), [TypeF16], TypeF16, t.params, cases); + await run(t, builtin('ceil'), [Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/clamp.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/clamp.cache.ts index ef63fb385ba5..909d15e7e752 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/clamp.cache.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/clamp.cache.ts @@ -1,5 +1,5 @@ import { kValue } from '../../../../../util/constants.js'; -import { ScalarType, TypeAbstractInt, TypeI32, TypeU32 } from '../../../../../util/conversion.js'; +import { ScalarType, Type } from '../../../../../util/conversion.js'; import { FP } from '../../../../../util/floating_point.js'; import { maxBigInt, minBigInt } from '../../../../../util/math.js'; import { Case } from '../../case.js'; @@ -59,11 +59,11 @@ function generateAbstractIntegerTestCases(test_values: Array): Array ({ input: [ - TypeAbstractInt.create(e), - TypeAbstractInt.create(low), - TypeAbstractInt.create(high), + Type.abstractInt.create(e), + Type.abstractInt.create(low), + Type.abstractInt.create(high), ], - expected: TypeAbstractInt.create(minBigInt(maxBigInt(e, low), high)), + expected: Type.abstractInt.create(minBigInt(maxBigInt(e, low), high)), })) ) ); @@ -113,16 +113,16 @@ const fp_cases = (['f32', 'f16', 'abstract'] as const) export const d = makeCaseCache('clamp', { u32_non_const: () => { - return generateConcreteIntegerTestCases(u32Values, TypeU32, 'non_const'); + return generateConcreteIntegerTestCases(u32Values, Type.u32, 'non_const'); }, u32_const: () => { - return generateConcreteIntegerTestCases(u32Values, TypeU32, 'const'); + return generateConcreteIntegerTestCases(u32Values, Type.u32, 'const'); }, i32_non_const: () => { - return generateConcreteIntegerTestCases(i32Values, TypeI32, 'non_const'); + return generateConcreteIntegerTestCases(i32Values, Type.i32, 'non_const'); }, i32_const: () => { - return generateConcreteIntegerTestCases(i32Values, TypeI32, 'const'); + return generateConcreteIntegerTestCases(i32Values, Type.i32, 'const'); }, abstract_int: () => { return generateAbstractIntegerTestCases(abstractFloatValues); diff --git a/src/webgpu/shader/execution/expression/call/builtin/clamp.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/clamp.spec.ts index cc29ceba03f7..0b524bccf0d3 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/clamp.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/clamp.spec.ts @@ -1,12 +1,12 @@ export const description = ` Execution tests for the 'clamp' builtin function -S is AbstractInt, i32, or u32 +S is abstract-int, i32, or u32 T is S or vecN @const fn clamp(e: T , low: T, high: T) -> T Returns min(max(e,low),high). Component-wise when T is a vector. -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const clamp(e: T , low: T , high: T) -> T Returns either min(max(e,low),high), or the median of the three values e, low, high. @@ -15,14 +15,7 @@ Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { - TypeAbstractFloat, - TypeAbstractInt, - TypeF16, - TypeF32, - TypeI32, - TypeU32, -} from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, onlyConstInputSource, run } from '../../expression.js'; import { abstractFloatBuiltin, abstractIntBuiltin, builtin } from './builtin.js'; @@ -43,8 +36,8 @@ g.test('abstract_int') await run( t, abstractIntBuiltin('clamp'), - [TypeAbstractInt, TypeAbstractInt, TypeAbstractInt], - TypeAbstractInt, + [Type.abstractInt, Type.abstractInt, Type.abstractInt], + Type.abstractInt, t.params, cases ); @@ -58,7 +51,7 @@ g.test('u32') ) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'u32_const' : 'u32_non_const'); - await run(t, builtin('clamp'), [TypeU32, TypeU32, TypeU32], TypeU32, t.params, cases); + await run(t, builtin('clamp'), [Type.u32, Type.u32, Type.u32], Type.u32, t.params, cases); }); g.test('i32') @@ -69,7 +62,7 @@ g.test('i32') ) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'i32_const' : 'i32_non_const'); - await run(t, builtin('clamp'), [TypeI32, TypeI32, TypeI32], TypeI32, t.params, cases); + await run(t, builtin('clamp'), [Type.i32, Type.i32, Type.i32], Type.i32, t.params, cases); }); g.test('abstract_float') @@ -85,8 +78,8 @@ g.test('abstract_float') await run( t, abstractFloatBuiltin('clamp'), - [TypeAbstractFloat, TypeAbstractFloat, TypeAbstractFloat], - TypeAbstractFloat, + [Type.abstractFloat, Type.abstractFloat, Type.abstractFloat], + Type.abstractFloat, t.params, cases ); @@ -100,7 +93,7 @@ g.test('f32') ) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f32_const' : 'f32_non_const'); - await run(t, builtin('clamp'), [TypeF32, TypeF32, TypeF32], TypeF32, t.params, cases); + await run(t, builtin('clamp'), [Type.f32, Type.f32, Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -114,5 +107,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f16_const' : 'f16_non_const'); - await run(t, builtin('clamp'), [TypeF16, TypeF16, TypeF16], TypeF16, t.params, cases); + await run(t, builtin('clamp'), [Type.f16, Type.f16, Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/cos.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/cos.spec.ts index 5eb9081928d1..4e3756834def 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/cos.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/cos.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'cos' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn cos(e: T ) -> T Returns the cosine of e. Component-wise when T is a vector. @@ -9,7 +9,7 @@ Returns the cosine of e. Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF16, TypeF32 } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -39,7 +39,7 @@ TODO(#792): Decide what the ground-truth is for these tests. [1] ) .fn(async t => { const cases = await d.get('f32'); - await run(t, builtin('cos'), [TypeF32], TypeF32, t.params, cases); + await run(t, builtin('cos'), [Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -53,5 +53,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get('f16'); - await run(t, builtin('cos'), [TypeF16], TypeF16, t.params, cases); + await run(t, builtin('cos'), [Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/cosh.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/cosh.spec.ts index aba7212a06e3..70713a392751 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/cosh.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/cosh.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'cosh' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn cosh(e: T ) -> T Returns the hyperbolic cosine of e. Component-wise when T is a vector @@ -9,7 +9,7 @@ Returns the hyperbolic cosine of e. Component-wise when T is a vector import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF16, TypeF32 } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -33,7 +33,7 @@ g.test('f32') ) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f32_const' : 'f32_non_const'); - await run(t, builtin('cosh'), [TypeF32], TypeF32, t.params, cases); + await run(t, builtin('cosh'), [Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -47,5 +47,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f16_const' : 'f16_non_const'); - await run(t, builtin('cosh'), [TypeF16], TypeF16, t.params, cases); + await run(t, builtin('cosh'), [Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/countLeadingZeros.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/countLeadingZeros.spec.ts index cfae4bb6e03b..ea0c38ae58d9 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/countLeadingZeros.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/countLeadingZeros.spec.ts @@ -12,7 +12,7 @@ Also known as "clz" in some languages. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeU32, u32Bits, u32, TypeI32, i32Bits, i32 } from '../../../../../util/conversion.js'; +import { Type, u32Bits, u32, i32Bits, i32 } from '../../../../../util/conversion.js'; import { allInputSources, Config, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -27,7 +27,7 @@ g.test('u32') ) .fn(async t => { const cfg: Config = t.params; - await run(t, builtin('countLeadingZeros'), [TypeU32], TypeU32, cfg, [ + await run(t, builtin('countLeadingZeros'), [Type.u32], Type.u32, cfg, [ // Zero { input: u32Bits(0b00000000000000000000000000000000), expected: u32(32) }, @@ -142,7 +142,7 @@ g.test('i32') ) .fn(async t => { const cfg: Config = t.params; - await run(t, builtin('countLeadingZeros'), [TypeI32], TypeI32, cfg, [ + await run(t, builtin('countLeadingZeros'), [Type.i32], Type.i32, cfg, [ // Zero { input: i32Bits(0b00000000000000000000000000000000), expected: i32(32) }, diff --git a/src/webgpu/shader/execution/expression/call/builtin/countOneBits.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/countOneBits.spec.ts index f0be9162856a..1937e0428362 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/countOneBits.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/countOneBits.spec.ts @@ -11,7 +11,7 @@ Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeU32, u32Bits, u32, TypeI32, i32Bits, i32 } from '../../../../../util/conversion.js'; +import { Type, u32Bits, u32, i32Bits, i32 } from '../../../../../util/conversion.js'; import { allInputSources, Config, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -26,7 +26,7 @@ g.test('u32') ) .fn(async t => { const cfg: Config = t.params; - await run(t, builtin('countOneBits'), [TypeU32], TypeU32, cfg, [ + await run(t, builtin('countOneBits'), [Type.u32], Type.u32, cfg, [ // Zero { input: u32Bits(0b00000000000000000000000000000000), expected: u32(0) }, @@ -141,7 +141,7 @@ g.test('i32') ) .fn(async t => { const cfg: Config = t.params; - await run(t, builtin('countOneBits'), [TypeI32], TypeI32, cfg, [ + await run(t, builtin('countOneBits'), [Type.i32], Type.i32, cfg, [ // Zero { input: i32Bits(0b00000000000000000000000000000000), expected: i32(0) }, diff --git a/src/webgpu/shader/execution/expression/call/builtin/countTrailingZeros.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/countTrailingZeros.spec.ts index d0b3198f49c4..3392a47810cf 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/countTrailingZeros.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/countTrailingZeros.spec.ts @@ -12,7 +12,7 @@ Also known as "ctz" in some languages. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { i32, i32Bits, TypeI32, u32, TypeU32, u32Bits } from '../../../../../util/conversion.js'; +import { i32, i32Bits, Type, u32, u32Bits } from '../../../../../util/conversion.js'; import { allInputSources, Config, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -27,7 +27,7 @@ g.test('u32') ) .fn(async t => { const cfg: Config = t.params; - await run(t, builtin('countTrailingZeros'), [TypeU32], TypeU32, cfg, [ + await run(t, builtin('countTrailingZeros'), [Type.u32], Type.u32, cfg, [ // Zero { input: u32Bits(0b00000000000000000000000000000000), expected: u32(32) }, @@ -142,7 +142,7 @@ g.test('i32') ) .fn(async t => { const cfg: Config = t.params; - await run(t, builtin('countTrailingZeros'), [TypeI32], TypeI32, cfg, [ + await run(t, builtin('countTrailingZeros'), [Type.i32], Type.i32, cfg, [ // Zero { input: i32Bits(0b00000000000000000000000000000000), expected: i32(32) }, diff --git a/src/webgpu/shader/execution/expression/call/builtin/cross.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/cross.spec.ts index 95b39f45c5b3..cc32537076d1 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/cross.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/cross.spec.ts @@ -1,14 +1,14 @@ export const description = ` Execution tests for the 'cross' builtin function -T is AbstractFloat, f32, or f16 +T is abstract-float, f32, or f16 @const fn cross(e1: vec3 ,e2: vec3) -> vec3 Returns the cross product of e1 and e2. `; import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeAbstractFloat, TypeF16, TypeF32, TypeVec } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, onlyConstInputSource, run } from '../../expression.js'; import { abstractFloatBuiltin, builtin } from './builtin.js'; @@ -25,8 +25,8 @@ g.test('abstract_float') await run( t, abstractFloatBuiltin('cross'), - [TypeVec(3, TypeAbstractFloat), TypeVec(3, TypeAbstractFloat)], - TypeVec(3, TypeAbstractFloat), + [Type.vec(3, Type.abstractFloat), Type.vec(3, Type.abstractFloat)], + Type.vec(3, Type.abstractFloat), t.params, cases ); @@ -38,14 +38,7 @@ g.test('f32') .params(u => u.combine('inputSource', allInputSources)) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f32_const' : 'f32_non_const'); - await run( - t, - builtin('cross'), - [TypeVec(3, TypeF32), TypeVec(3, TypeF32)], - TypeVec(3, TypeF32), - t.params, - cases - ); + await run(t, builtin('cross'), [Type.vec3f, Type.vec3f], Type.vec3f, t.params, cases); }); g.test('f16') @@ -57,12 +50,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f16_const' : 'f16_non_const'); - await run( - t, - builtin('cross'), - [TypeVec(3, TypeF16), TypeVec(3, TypeF16)], - TypeVec(3, TypeF16), - t.params, - cases - ); + await run(t, builtin('cross'), [Type.vec3h, Type.vec3h], Type.vec3h, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/degrees.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/degrees.spec.ts index f69a92cf5f45..e8589c99332d 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/degrees.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/degrees.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'degrees' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn degrees(e1: T ) -> T Converts radians to degrees, approximating e1 × 180 ÷ π. Component-wise when T is a vector @@ -9,7 +9,7 @@ Converts radians to degrees, approximating e1 × 180 ÷ π. Component-wise when import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeAbstractFloat, TypeF16, TypeF32 } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, onlyConstInputSource, run } from '../../expression.js'; import { abstractFloatBuiltin, builtin } from './builtin.js'; @@ -30,8 +30,8 @@ g.test('abstract_float') await run( t, abstractFloatBuiltin('degrees'), - [TypeAbstractFloat], - TypeAbstractFloat, + [Type.abstractFloat], + Type.abstractFloat, t.params, cases ); @@ -45,7 +45,7 @@ g.test('f32') ) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f32_const' : 'f32_non_const'); - await run(t, builtin('degrees'), [TypeF32], TypeF32, t.params, cases); + await run(t, builtin('degrees'), [Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -59,5 +59,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f16_const' : 'f16_non_const'); - await run(t, builtin('degrees'), [TypeF16], TypeF16, t.params, cases); + await run(t, builtin('degrees'), [Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/determinant.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/determinant.cache.ts index 379b42b3e63c..4eab44009abe 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/determinant.cache.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/determinant.cache.ts @@ -78,7 +78,21 @@ const f16_cases = ([2, 3, 4] as const) ) .reduce((a, b) => ({ ...a, ...b }), {}); +// Cases: abstract_matDxD +const abstract_cases = ([2, 3, 4] as const) + .map(dim => ({ + [`abstract_mat${dim}x${dim}`]: () => { + return FP.abstract.generateMatrixToScalarCases( + kDeterminantMatrixValues[dim], + 'finite', + FP.abstract.determinantInterval + ); + }, + })) + .reduce((a, b) => ({ ...a, ...b }), {}); + export const d = makeCaseCache('determinant', { ...f32_cases, ...f16_cases, + ...abstract_cases, }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/determinant.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/determinant.spec.ts index c628623f4378..638af80acaf5 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/determinant.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/determinant.spec.ts @@ -1,17 +1,17 @@ export const description = ` Execution tests for the 'determinant' builtin function -T is AbstractFloat, f32, or f16 +T is abstract-float, f32, or f16 @const determinant(e: matCxC ) -> T Returns the determinant of e. `; import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF16, TypeF32, TypeMat } from '../../../../../util/conversion.js'; -import { allInputSources, run } from '../../expression.js'; +import { Type } from '../../../../../util/conversion.js'; +import { allInputSources, onlyConstInputSource, run } from '../../expression.js'; -import { builtin } from './builtin.js'; +import { abstractFloatBuiltin, builtin } from './builtin.js'; import { d } from './determinant.cache.js'; export const g = makeTestGroup(GPUTest); @@ -19,8 +19,19 @@ export const g = makeTestGroup(GPUTest); g.test('abstract_float') .specURL('https://www.w3.org/TR/WGSL/#matrix-builtin-functions') .desc(`abstract float tests`) - .params(u => u.combine('inputSource', allInputSources).combine('dimension', [2, 3, 4] as const)) - .unimplemented(); + .params(u => u.combine('inputSource', onlyConstInputSource).combine('dim', [2, 3, 4] as const)) + .fn(async t => { + const dim = t.params.dim; + const cases = await d.get(`abstract_mat${dim}x${dim}`); + await run( + t, + abstractFloatBuiltin('determinant'), + [Type.mat(dim, dim, Type.abstractFloat)], + Type.abstractFloat, + t.params, + cases + ); + }); g.test('f32') .specURL('https://www.w3.org/TR/WGSL/#matrix-builtin-functions') @@ -33,7 +44,7 @@ g.test('f32') ? `f32_mat${dim}x${dim}_const` : `f32_mat${dim}x${dim}_non_const` ); - await run(t, builtin('determinant'), [TypeMat(dim, dim, TypeF32)], TypeF32, t.params, cases); + await run(t, builtin('determinant'), [Type.mat(dim, dim, Type.f32)], Type.f32, t.params, cases); }); g.test('f16') @@ -50,5 +61,5 @@ g.test('f16') ? `f16_mat${dim}x${dim}_const` : `f16_mat${dim}x${dim}_non_const` ); - await run(t, builtin('determinant'), [TypeMat(dim, dim, TypeF16)], TypeF16, t.params, cases); + await run(t, builtin('determinant'), [Type.mat(dim, dim, Type.f16)], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/distance.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/distance.spec.ts index ab63029ca227..0f50cd30d37a 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/distance.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/distance.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'distance' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn distance(e1: T ,e2: T ) -> f32 Returns the distance between e1 and e2 (e.g. length(e1-e2)). @@ -10,7 +10,7 @@ Returns the distance between e1 and e2 (e.g. length(e1-e2)). import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF16, TypeF32, TypeVec } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -32,7 +32,7 @@ g.test('f32') .params(u => u.combine('inputSource', allInputSources)) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f32_const' : 'f32_non_const'); - await run(t, builtin('distance'), [TypeF32, TypeF32], TypeF32, t.params, cases); + await run(t, builtin('distance'), [Type.f32, Type.f32], Type.f32, t.params, cases); }); g.test('f32_vec2') @@ -43,14 +43,7 @@ g.test('f32_vec2') const cases = await d.get( t.params.inputSource === 'const' ? 'f32_vec2_const' : 'f32_vec2_non_const' ); - await run( - t, - builtin('distance'), - [TypeVec(2, TypeF32), TypeVec(2, TypeF32)], - TypeF32, - t.params, - cases - ); + await run(t, builtin('distance'), [Type.vec2f, Type.vec2f], Type.f32, t.params, cases); }); g.test('f32_vec3') @@ -61,14 +54,7 @@ g.test('f32_vec3') const cases = await d.get( t.params.inputSource === 'const' ? 'f32_vec3_const' : 'f32_vec3_non_const' ); - await run( - t, - builtin('distance'), - [TypeVec(3, TypeF32), TypeVec(3, TypeF32)], - TypeF32, - t.params, - cases - ); + await run(t, builtin('distance'), [Type.vec3f, Type.vec3f], Type.f32, t.params, cases); }); g.test('f32_vec4') @@ -79,14 +65,7 @@ g.test('f32_vec4') const cases = await d.get( t.params.inputSource === 'const' ? 'f32_vec4_const' : 'f32_vec4_non_const' ); - await run( - t, - builtin('distance'), - [TypeVec(4, TypeF32), TypeVec(4, TypeF32)], - TypeF32, - t.params, - cases - ); + await run(t, builtin('distance'), [Type.vec4f, Type.vec4f], Type.f32, t.params, cases); }); g.test('f16') @@ -98,7 +77,7 @@ g.test('f16') }) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f16_const' : 'f16_non_const'); - await run(t, builtin('distance'), [TypeF16, TypeF16], TypeF16, t.params, cases); + await run(t, builtin('distance'), [Type.f16, Type.f16], Type.f16, t.params, cases); }); g.test('f16_vec2') @@ -112,14 +91,7 @@ g.test('f16_vec2') const cases = await d.get( t.params.inputSource === 'const' ? 'f16_vec2_const' : 'f16_vec2_non_const' ); - await run( - t, - builtin('distance'), - [TypeVec(2, TypeF16), TypeVec(2, TypeF16)], - TypeF16, - t.params, - cases - ); + await run(t, builtin('distance'), [Type.vec2h, Type.vec2h], Type.f16, t.params, cases); }); g.test('f16_vec3') @@ -133,14 +105,7 @@ g.test('f16_vec3') const cases = await d.get( t.params.inputSource === 'const' ? 'f16_vec3_const' : 'f16_vec3_non_const' ); - await run( - t, - builtin('distance'), - [TypeVec(3, TypeF16), TypeVec(3, TypeF16)], - TypeF16, - t.params, - cases - ); + await run(t, builtin('distance'), [Type.vec3h, Type.vec3h], Type.f16, t.params, cases); }); g.test('f16_vec4') @@ -154,12 +119,5 @@ g.test('f16_vec4') const cases = await d.get( t.params.inputSource === 'const' ? 'f16_vec4_const' : 'f16_vec4_non_const' ); - await run( - t, - builtin('distance'), - [TypeVec(4, TypeF16), TypeVec(4, TypeF16)], - TypeF16, - t.params, - cases - ); + await run(t, builtin('distance'), [Type.vec4h, Type.vec4h], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/dot.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/dot.spec.ts index 5d27e5044dea..7d39aa0fbe25 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/dot.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/dot.spec.ts @@ -1,21 +1,14 @@ export const description = ` Execution tests for the 'dot' builtin function -T is AbstractInt, AbstractFloat, i32, u32, f32, or f16 +T is Type.abstractInt, Type.abstractFloat, i32, u32, f32, or f16 @const fn dot(e1: vecN,e2: vecN) -> T Returns the dot product of e1 and e2. `; import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { - TypeAbstractInt, - TypeF16, - TypeF32, - TypeI32, - TypeU32, - TypeVec, -} from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, onlyConstInputSource, run } from '../../expression.js'; import { abstractIntBuiltin, builtin } from './builtin.js'; @@ -32,8 +25,8 @@ g.test('abstract_int_vec2') await run( t, abstractIntBuiltin('dot'), - [TypeVec(2, TypeAbstractInt), TypeVec(2, TypeAbstractInt)], - TypeAbstractInt, + [Type.vec(2, Type.abstractInt), Type.vec(2, Type.abstractInt)], + Type.abstractInt, t.params, cases ); @@ -48,8 +41,8 @@ g.test('abstract_int_vec3') await run( t, abstractIntBuiltin('dot'), - [TypeVec(3, TypeAbstractInt), TypeVec(3, TypeAbstractInt)], - TypeAbstractInt, + [Type.vec(3, Type.abstractInt), Type.vec(3, Type.abstractInt)], + Type.abstractInt, t.params, cases ); @@ -64,8 +57,8 @@ g.test('abstract_int_vec4') await run( t, abstractIntBuiltin('dot'), - [TypeVec(4, TypeAbstractInt), TypeVec(4, TypeAbstractInt)], - TypeAbstractInt, + [Type.vec(4, Type.abstractInt), Type.vec(4, Type.abstractInt)], + Type.abstractInt, t.params, cases ); @@ -77,14 +70,7 @@ g.test('i32_vec2') .params(u => u.combine('inputSource', allInputSources)) .fn(async t => { const cases = await d.get('i32_vec2'); - await run( - t, - builtin('dot'), - [TypeVec(2, TypeI32), TypeVec(2, TypeI32)], - TypeI32, - t.params, - cases - ); + await run(t, builtin('dot'), [Type.vec2i, Type.vec2i], Type.i32, t.params, cases); }); g.test('i32_vec3') @@ -93,14 +79,7 @@ g.test('i32_vec3') .params(u => u.combine('inputSource', allInputSources)) .fn(async t => { const cases = await d.get('i32_vec3'); - await run( - t, - builtin('dot'), - [TypeVec(3, TypeI32), TypeVec(3, TypeI32)], - TypeI32, - t.params, - cases - ); + await run(t, builtin('dot'), [Type.vec3i, Type.vec3i], Type.i32, t.params, cases); }); g.test('i32_vec4') @@ -109,14 +88,7 @@ g.test('i32_vec4') .params(u => u.combine('inputSource', allInputSources)) .fn(async t => { const cases = await d.get('i32_vec4'); - await run( - t, - builtin('dot'), - [TypeVec(4, TypeI32), TypeVec(4, TypeI32)], - TypeI32, - t.params, - cases - ); + await run(t, builtin('dot'), [Type.vec4i, Type.vec4i], Type.i32, t.params, cases); }); g.test('u32_vec2') @@ -125,14 +97,7 @@ g.test('u32_vec2') .params(u => u.combine('inputSource', allInputSources)) .fn(async t => { const cases = await d.get('u32_vec2'); - await run( - t, - builtin('dot'), - [TypeVec(2, TypeU32), TypeVec(2, TypeU32)], - TypeU32, - t.params, - cases - ); + await run(t, builtin('dot'), [Type.vec2u, Type.vec2u], Type.u32, t.params, cases); }); g.test('u32_vec3') @@ -141,14 +106,7 @@ g.test('u32_vec3') .params(u => u.combine('inputSource', allInputSources)) .fn(async t => { const cases = await d.get('u32_vec3'); - await run( - t, - builtin('dot'), - [TypeVec(3, TypeU32), TypeVec(3, TypeU32)], - TypeU32, - t.params, - cases - ); + await run(t, builtin('dot'), [Type.vec3u, Type.vec3u], Type.u32, t.params, cases); }); g.test('u32_vec4') @@ -157,14 +115,7 @@ g.test('u32_vec4') .params(u => u.combine('inputSource', allInputSources)) .fn(async t => { const cases = await d.get('u32_vec4'); - await run( - t, - builtin('dot'), - [TypeVec(4, TypeU32), TypeVec(4, TypeU32)], - TypeU32, - t.params, - cases - ); + await run(t, builtin('dot'), [Type.vec4u, Type.vec4u], Type.u32, t.params, cases); }); g.test('abstract_float') @@ -181,14 +132,7 @@ g.test('f32_vec2') const cases = await d.get( t.params.inputSource === 'const' ? 'f32_vec2_const' : 'f32_vec2_non_const' ); - await run( - t, - builtin('dot'), - [TypeVec(2, TypeF32), TypeVec(2, TypeF32)], - TypeF32, - t.params, - cases - ); + await run(t, builtin('dot'), [Type.vec2f, Type.vec2f], Type.f32, t.params, cases); }); g.test('f32_vec3') @@ -199,14 +143,7 @@ g.test('f32_vec3') const cases = await d.get( t.params.inputSource === 'const' ? 'f32_vec3_const' : 'f32_vec3_non_const' ); - await run( - t, - builtin('dot'), - [TypeVec(3, TypeF32), TypeVec(3, TypeF32)], - TypeF32, - t.params, - cases - ); + await run(t, builtin('dot'), [Type.vec3f, Type.vec3f], Type.f32, t.params, cases); }); g.test('f32_vec4') @@ -217,14 +154,7 @@ g.test('f32_vec4') const cases = await d.get( t.params.inputSource === 'const' ? 'f32_vec4_const' : 'f32_vec4_non_const' ); - await run( - t, - builtin('dot'), - [TypeVec(4, TypeF32), TypeVec(4, TypeF32)], - TypeF32, - t.params, - cases - ); + await run(t, builtin('dot'), [Type.vec4f, Type.vec4f], Type.f32, t.params, cases); }); g.test('f16_vec2') @@ -238,14 +168,7 @@ g.test('f16_vec2') const cases = await d.get( t.params.inputSource === 'const' ? 'f16_vec2_const' : 'f16_vec2_non_const' ); - await run( - t, - builtin('dot'), - [TypeVec(2, TypeF16), TypeVec(2, TypeF16)], - TypeF16, - t.params, - cases - ); + await run(t, builtin('dot'), [Type.vec2h, Type.vec2h], Type.f16, t.params, cases); }); g.test('f16_vec3') @@ -259,14 +182,7 @@ g.test('f16_vec3') const cases = await d.get( t.params.inputSource === 'const' ? 'f16_vec3_const' : 'f16_vec3_non_const' ); - await run( - t, - builtin('dot'), - [TypeVec(3, TypeF16), TypeVec(3, TypeF16)], - TypeF16, - t.params, - cases - ); + await run(t, builtin('dot'), [Type.vec3h, Type.vec3h], Type.f16, t.params, cases); }); g.test('f16_vec4') @@ -280,12 +196,5 @@ g.test('f16_vec4') const cases = await d.get( t.params.inputSource === 'const' ? 'f16_vec4_const' : 'f16_vec4_non_const' ); - await run( - t, - builtin('dot'), - [TypeVec(4, TypeF16), TypeVec(4, TypeF16)], - TypeF16, - t.params, - cases - ); + await run(t, builtin('dot'), [Type.vec4h, Type.vec4h], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/dot4I8Packed.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/dot4I8Packed.spec.ts index dee5290281a8..de537c473e64 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/dot4I8Packed.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/dot4I8Packed.spec.ts @@ -9,7 +9,7 @@ the multiply, and then the add operations are done in WGSL i32 with wrapping beh import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeI32, TypeU32, i32, u32 } from '../../../../../util/conversion.js'; +import { Type, i32, u32 } from '../../../../../util/conversion.js'; import { Case } from '../../case.js'; import { allInputSources, Config, run } from '../../expression.js'; @@ -70,5 +70,5 @@ g.test('basic') return [makeCase(...(v as [number, number]))]; }); - await run(t, builtin('dot4I8Packed'), [TypeU32, TypeU32], TypeI32, cfg, cases); + await run(t, builtin('dot4I8Packed'), [Type.u32, Type.u32], Type.i32, cfg, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/dot4U8Packed.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/dot4U8Packed.spec.ts index f0dd6fc5081b..a12a3d012302 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/dot4U8Packed.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/dot4U8Packed.spec.ts @@ -8,7 +8,7 @@ unsigned integer dot product of these two vectors. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeU32, u32 } from '../../../../../util/conversion.js'; +import { Type, u32 } from '../../../../../util/conversion.js'; import { Case } from '../../case.js'; import { allInputSources, Config, run } from '../../expression.js'; @@ -55,5 +55,5 @@ g.test('basic') return [makeCase(...(v as [number, number]))]; }); - await run(t, builtin('dot4U8Packed'), [TypeU32, TypeU32], TypeU32, cfg, cases); + await run(t, builtin('dot4U8Packed'), [Type.u32, Type.u32], Type.u32, cfg, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/exp.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/exp.spec.ts index ad381df01690..09759ea190ef 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/exp.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/exp.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'exp' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn exp(e1: T ) -> T Returns the natural exponentiation of e1 (e.g. e^e1). Component-wise when T is a vector. @@ -9,7 +9,7 @@ Returns the natural exponentiation of e1 (e.g. e^e1). Component-wise when T is a import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF16, TypeF32 } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -33,7 +33,7 @@ g.test('f32') ) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f32_const' : 'f32_non_const'); - await run(t, builtin('exp'), [TypeF32], TypeF32, t.params, cases); + await run(t, builtin('exp'), [Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -47,5 +47,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f16_const' : 'f16_non_const'); - await run(t, builtin('exp'), [TypeF16], TypeF16, t.params, cases); + await run(t, builtin('exp'), [Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/exp2.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/exp2.spec.ts index cf0e3c3cbe81..f6b00c47ecca 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/exp2.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/exp2.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'exp2' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn exp2(e: T ) -> T Returns 2 raised to the power e (e.g. 2^e). Component-wise when T is a vector. @@ -9,7 +9,7 @@ Returns 2 raised to the power e (e.g. 2^e). Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF16, TypeF32 } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -33,7 +33,7 @@ g.test('f32') ) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f32_const' : 'f32_non_const'); - await run(t, builtin('exp2'), [TypeF32], TypeF32, t.params, cases); + await run(t, builtin('exp2'), [Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -47,5 +47,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f16_const' : 'f16_non_const'); - await run(t, builtin('exp2'), [TypeF16], TypeF16, t.params, cases); + await run(t, builtin('exp2'), [Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/extractBits.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/extractBits.spec.ts index d535bf5d746a..ef04b661bddf 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/extractBits.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/extractBits.spec.ts @@ -33,17 +33,7 @@ Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { - i32Bits, - TypeI32, - u32, - TypeU32, - u32Bits, - vec2, - vec3, - vec4, - TypeVec, -} from '../../../../../util/conversion.js'; +import { i32Bits, Type, u32, u32Bits, vec2, vec3, vec4 } from '../../../../../util/conversion.js'; import { allInputSources, Config, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -57,7 +47,7 @@ g.test('u32') .fn(async t => { const cfg: Config = t.params; - const T = t.params.width === 1 ? TypeU32 : TypeVec(t.params.width, TypeU32); + const T = t.params.width === 1 ? Type.u32 : Type.vec(t.params.width, Type.u32); const V = (x: number, y?: number, z?: number, w?: number) => { y = y === undefined ? x : y; @@ -193,7 +183,7 @@ g.test('u32') ); } - await run(t, builtin('extractBits'), [T, TypeU32, TypeU32], T, cfg, cases); + await run(t, builtin('extractBits'), [T, Type.u32, Type.u32], T, cfg, cases); }); g.test('i32') @@ -203,7 +193,7 @@ g.test('i32') .fn(async t => { const cfg: Config = t.params; - const T = t.params.width === 1 ? TypeI32 : TypeVec(t.params.width, TypeI32); + const T = t.params.width === 1 ? Type.i32 : Type.vec(t.params.width, Type.i32); const V = (x: number, y?: number, z?: number, w?: number) => { y = y === undefined ? x : y; @@ -333,5 +323,5 @@ g.test('i32') ); } - await run(t, builtin('extractBits'), [T, TypeU32, TypeU32], T, cfg, cases); + await run(t, builtin('extractBits'), [T, Type.u32, Type.u32], T, cfg, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/faceForward.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/faceForward.spec.ts index c21541ab8839..fae851439fc9 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/faceForward.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/faceForward.spec.ts @@ -1,14 +1,14 @@ export const description = ` Execution tests for the 'faceForward' builtin function -T is vecN, vecN, or vecN +T is vecN, vecN, or vecN @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 { TypeF16, TypeF32, TypeVec } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -33,8 +33,8 @@ g.test('f32_vec2') await run( t, builtin('faceForward'), - [TypeVec(2, TypeF32), TypeVec(2, TypeF32), TypeVec(2, TypeF32)], - TypeVec(2, TypeF32), + [Type.vec2f, Type.vec2f, Type.vec2f], + Type.vec2f, t.params, cases ); @@ -51,8 +51,8 @@ g.test('f32_vec3') await run( t, builtin('faceForward'), - [TypeVec(3, TypeF32), TypeVec(3, TypeF32), TypeVec(3, TypeF32)], - TypeVec(3, TypeF32), + [Type.vec3f, Type.vec3f, Type.vec3f], + Type.vec3f, t.params, cases ); @@ -69,8 +69,8 @@ g.test('f32_vec4') await run( t, builtin('faceForward'), - [TypeVec(4, TypeF32), TypeVec(4, TypeF32), TypeVec(4, TypeF32)], - TypeVec(4, TypeF32), + [Type.vec4f, Type.vec4f, Type.vec4f], + Type.vec4f, t.params, cases ); @@ -90,8 +90,8 @@ g.test('f16_vec2') await run( t, builtin('faceForward'), - [TypeVec(2, TypeF16), TypeVec(2, TypeF16), TypeVec(2, TypeF16)], - TypeVec(2, TypeF16), + [Type.vec2h, Type.vec2h, Type.vec2h], + Type.vec2h, t.params, cases ); @@ -111,8 +111,8 @@ g.test('f16_vec3') await run( t, builtin('faceForward'), - [TypeVec(3, TypeF16), TypeVec(3, TypeF16), TypeVec(3, TypeF16)], - TypeVec(3, TypeF16), + [Type.vec3h, Type.vec3h, Type.vec3h], + Type.vec3h, t.params, cases ); @@ -132,8 +132,8 @@ g.test('f16_vec4') await run( t, builtin('faceForward'), - [TypeVec(4, TypeF16), TypeVec(4, TypeF16), TypeVec(4, TypeF16)], - TypeVec(4, TypeF16), + [Type.vec4h, Type.vec4h, Type.vec4h], + Type.vec4h, t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/call/builtin/firstLeadingBit.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/firstLeadingBit.spec.ts index 26216563cd04..9248b1e2bf5c 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/firstLeadingBit.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/firstLeadingBit.spec.ts @@ -16,7 +16,7 @@ Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { i32, i32Bits, TypeI32, u32, TypeU32, u32Bits } from '../../../../../util/conversion.js'; +import { i32, i32Bits, Type, u32, u32Bits } from '../../../../../util/conversion.js'; import { allInputSources, Config, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -31,7 +31,7 @@ g.test('u32') ) .fn(async t => { const cfg: Config = t.params; - await run(t, builtin('firstLeadingBit'), [TypeU32], TypeU32, cfg, [ + await run(t, builtin('firstLeadingBit'), [Type.u32], Type.u32, cfg, [ // Zero { input: u32Bits(0b00000000000000000000000000000000), expected: u32(-1) }, @@ -146,7 +146,7 @@ g.test('i32') ) .fn(async t => { const cfg: Config = t.params; - await run(t, builtin('firstLeadingBit'), [TypeI32], TypeI32, cfg, [ + await run(t, builtin('firstLeadingBit'), [Type.i32], Type.i32, cfg, [ // Zero { input: i32Bits(0b00000000000000000000000000000000), expected: i32(-1) }, diff --git a/src/webgpu/shader/execution/expression/call/builtin/firstTrailingBit.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/firstTrailingBit.spec.ts index 5c65f59d2813..a8dd27ee87b2 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/firstTrailingBit.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/firstTrailingBit.spec.ts @@ -12,7 +12,7 @@ Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { i32, i32Bits, TypeI32, u32, TypeU32, u32Bits } from '../../../../../util/conversion.js'; +import { i32, i32Bits, Type, u32, u32Bits } from '../../../../../util/conversion.js'; import { allInputSources, Config, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -27,7 +27,7 @@ g.test('u32') ) .fn(async t => { const cfg: Config = t.params; - await run(t, builtin('firstTrailingBit'), [TypeU32], TypeU32, cfg, [ + await run(t, builtin('firstTrailingBit'), [Type.u32], Type.u32, cfg, [ // Zero { input: u32Bits(0b00000000000000000000000000000000), expected: u32(-1) }, @@ -142,7 +142,7 @@ g.test('i32') ) .fn(async t => { const cfg: Config = t.params; - await run(t, builtin('firstTrailingBit'), [TypeI32], TypeI32, cfg, [ + await run(t, builtin('firstTrailingBit'), [Type.i32], Type.i32, cfg, [ // Zero { input: i32Bits(0b00000000000000000000000000000000), expected: i32(-1) }, diff --git a/src/webgpu/shader/execution/expression/call/builtin/floor.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/floor.spec.ts index 63b0a138a045..26cffe5d10da 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/floor.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/floor.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'floor' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn floor(e: T ) -> T Returns the floor of e. Component-wise when T is a vector. @@ -9,7 +9,7 @@ Returns the floor of e. Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeAbstractFloat, TypeF16, TypeF32 } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, onlyConstInputSource, run } from '../../expression.js'; import { abstractFloatBuiltin, builtin } from './builtin.js'; @@ -30,8 +30,8 @@ g.test('abstract_float') await run( t, abstractFloatBuiltin('floor'), - [TypeAbstractFloat], - TypeAbstractFloat, + [Type.abstractFloat], + Type.abstractFloat, t.params, cases ); @@ -45,7 +45,7 @@ g.test('f32') ) .fn(async t => { const cases = await d.get('f32'); - await run(t, builtin('floor'), [TypeF32], TypeF32, t.params, cases); + await run(t, builtin('floor'), [Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -59,5 +59,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get('f16'); - await run(t, builtin('floor'), [TypeF16], TypeF16, t.params, cases); + await run(t, builtin('floor'), [Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/fma.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/fma.spec.ts index 2488603d8077..620792d42007 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/fma.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/fma.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'fma' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn fma(e1: T ,e2: T ,e3: T ) -> T Returns e1 * e2 + e3. Component-wise when T is a vector. @@ -9,7 +9,7 @@ Returns e1 * e2 + e3. Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeAbstractFloat, TypeF16, TypeF32 } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, onlyConstInputSource, run } from '../../expression.js'; import { abstractFloatBuiltin, builtin } from './builtin.js'; @@ -30,8 +30,8 @@ g.test('abstract_float') await run( t, abstractFloatBuiltin('fma'), - [TypeAbstractFloat, TypeAbstractFloat, TypeAbstractFloat], - TypeAbstractFloat, + [Type.abstractFloat, Type.abstractFloat, Type.abstractFloat], + Type.abstractFloat, t.params, cases ); @@ -45,7 +45,7 @@ g.test('f32') ) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f32_const' : 'f32_non_const'); - await run(t, builtin('fma'), [TypeF32, TypeF32, TypeF32], TypeF32, t.params, cases); + await run(t, builtin('fma'), [Type.f32, Type.f32, Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -59,5 +59,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f16_const' : 'f16_non_const'); - await run(t, builtin('fma'), [TypeF16, TypeF16, TypeF16], TypeF16, t.params, cases); + await run(t, builtin('fma'), [Type.f16, Type.f16, Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/fract.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/fract.spec.ts index df9e1845273e..d840122b3978 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/fract.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/fract.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'fract' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn fract(e: T ) -> T Returns the fractional part of e, computed as e - floor(e). @@ -10,7 +10,7 @@ Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF16, TypeF32 } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -34,7 +34,7 @@ g.test('f32') ) .fn(async t => { const cases = await d.get('f32'); - await run(t, builtin('fract'), [TypeF32], TypeF32, t.params, cases); + await run(t, builtin('fract'), [Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -48,5 +48,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get('f16'); - await run(t, builtin('fract'), [TypeF16], TypeF16, t.params, cases); + await run(t, builtin('fract'), [Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/frexp.cache.ts b/src/webgpu/shader/execution/expression/call/builtin/frexp.cache.ts index 7c107eb729a7..05f8de7f8936 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/frexp.cache.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/frexp.cache.ts @@ -1,5 +1,5 @@ import { skipUndefined } from '../../../../../util/compare.js'; -import { Scalar, Vector, i32, toVector } from '../../../../../util/conversion.js'; +import { ScalarValue, VectorValue, i32, toVector } from '../../../../../util/conversion.js'; import { FP } from '../../../../../util/floating_point.js'; import { frexp } from '../../../../../util/math.js'; import { Case } from '../../case.js'; @@ -8,8 +8,8 @@ import { makeCaseCache } from '../../case_cache.js'; /* @returns a fract Case for a given scalar or vector input */ function makeCaseFract(v: number | readonly number[], trait: 'f32' | 'f16'): Case { const fp = FP[trait]; - let toInput: (n: readonly number[]) => Scalar | Vector; - let toOutput: (n: readonly number[]) => Scalar | Vector; + let toInput: (n: readonly number[]) => ScalarValue | VectorValue; + let toOutput: (n: readonly number[]) => ScalarValue | VectorValue; if (v instanceof Array) { // Input is vector toInput = (n: readonly number[]) => toVector(n, fp.scalarBuilder); @@ -36,8 +36,8 @@ function makeCaseFract(v: number | readonly number[], trait: 'f32' | 'f16'): Cas /* @returns an exp Case for a given scalar or vector input */ function makeCaseExp(v: number | readonly number[], trait: 'f32' | 'f16'): Case { const fp = FP[trait]; - let toInput: (n: readonly number[]) => Scalar | Vector; - let toOutput: (n: readonly number[]) => Scalar | Vector; + let toInput: (n: readonly number[]) => ScalarValue | VectorValue; + let toOutput: (n: readonly number[]) => ScalarValue | VectorValue; if (v instanceof Array) { // Input is vector toInput = (n: readonly number[]) => toVector(n, fp.scalarBuilder); diff --git a/src/webgpu/shader/execution/expression/call/builtin/frexp.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/frexp.spec.ts index 663e345f499a..ee506decd9d0 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/frexp.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/frexp.spec.ts @@ -15,7 +15,7 @@ The magnitude of the significand is in the range of [0.5, 1.0) or 0. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF16, TypeF32, TypeI32, TypeVec } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { ShaderBuilder, allInputSources, basicExpressionBuilder, run } from '../../expression.js'; import { d } from './frexp.cache.js'; @@ -46,7 +46,7 @@ struct __frexp_result_f32 { .params(u => u.combine('inputSource', allInputSources)) .fn(async t => { const cases = await d.get('f32_fract'); - await run(t, fractBuilder(), [TypeF32], TypeF32, t.params, cases); + await run(t, fractBuilder(), [Type.f32], Type.f32, t.params, cases); }); g.test('f32_exp') @@ -64,7 +64,7 @@ struct __frexp_result_f32 { .params(u => u.combine('inputSource', allInputSources)) .fn(async t => { const cases = await d.get('f32_exp'); - await run(t, expBuilder(), [TypeF32], TypeI32, t.params, cases); + await run(t, expBuilder(), [Type.f32], Type.i32, t.params, cases); }); g.test('f32_vec2_fract') @@ -82,7 +82,7 @@ struct __frexp_result_vec2_f32 { .params(u => u.combine('inputSource', allInputSources)) .fn(async t => { const cases = await d.get('f32_vec2_fract'); - await run(t, fractBuilder(), [TypeVec(2, TypeF32)], TypeVec(2, TypeF32), t.params, cases); + await run(t, fractBuilder(), [Type.vec2f], Type.vec2f, t.params, cases); }); g.test('f32_vec2_exp') @@ -100,7 +100,7 @@ struct __frexp_result_vec2_f32 { .params(u => u.combine('inputSource', allInputSources)) .fn(async t => { const cases = await d.get('f32_vec2_exp'); - await run(t, expBuilder(), [TypeVec(2, TypeF32)], TypeVec(2, TypeI32), t.params, cases); + await run(t, expBuilder(), [Type.vec2f], Type.vec2i, t.params, cases); }); g.test('f32_vec3_fract') @@ -118,7 +118,7 @@ struct __frexp_result_vec3_f32 { .params(u => u.combine('inputSource', allInputSources)) .fn(async t => { const cases = await d.get('f32_vec3_fract'); - await run(t, fractBuilder(), [TypeVec(3, TypeF32)], TypeVec(3, TypeF32), t.params, cases); + await run(t, fractBuilder(), [Type.vec3f], Type.vec3f, t.params, cases); }); g.test('f32_vec3_exp') @@ -136,7 +136,7 @@ struct __frexp_result_vec3_f32 { .params(u => u.combine('inputSource', allInputSources)) .fn(async t => { const cases = await d.get('f32_vec3_exp'); - await run(t, expBuilder(), [TypeVec(3, TypeF32)], TypeVec(3, TypeI32), t.params, cases); + await run(t, expBuilder(), [Type.vec3f], Type.vec3i, t.params, cases); }); g.test('f32_vec4_fract') @@ -154,7 +154,7 @@ struct __frexp_result_vec4_f32 { .params(u => u.combine('inputSource', allInputSources)) .fn(async t => { const cases = await d.get('f32_vec4_fract'); - await run(t, fractBuilder(), [TypeVec(4, TypeF32)], TypeVec(4, TypeF32), t.params, cases); + await run(t, fractBuilder(), [Type.vec4f], Type.vec4f, t.params, cases); }); g.test('f32_vec4_exp') @@ -172,7 +172,7 @@ struct __frexp_result_vec4_f32 { .params(u => u.combine('inputSource', allInputSources)) .fn(async t => { const cases = await d.get('f32_vec4_exp'); - await run(t, expBuilder(), [TypeVec(4, TypeF32)], TypeVec(4, TypeI32), t.params, cases); + await run(t, expBuilder(), [Type.vec4f], Type.vec4i, t.params, cases); }); g.test('f16_fract') @@ -193,7 +193,7 @@ struct __frexp_result_f16 { }) .fn(async t => { const cases = await d.get('f16_fract'); - await run(t, fractBuilder(), [TypeF16], TypeF16, t.params, cases); + await run(t, fractBuilder(), [Type.f16], Type.f16, t.params, cases); }); g.test('f16_exp') @@ -214,7 +214,7 @@ struct __frexp_result_f16 { }) .fn(async t => { const cases = await d.get('f16_exp'); - await run(t, expBuilder(), [TypeF16], TypeI32, t.params, cases); + await run(t, expBuilder(), [Type.f16], Type.i32, t.params, cases); }); g.test('f16_vec2_fract') @@ -235,7 +235,7 @@ struct __frexp_result_vec2_f16 { }) .fn(async t => { const cases = await d.get('f16_vec2_fract'); - await run(t, fractBuilder(), [TypeVec(2, TypeF16)], TypeVec(2, TypeF16), t.params, cases); + await run(t, fractBuilder(), [Type.vec2h], Type.vec2h, t.params, cases); }); g.test('f16_vec2_exp') @@ -256,7 +256,7 @@ struct __frexp_result_vec2_f16 { }) .fn(async t => { const cases = await d.get('f16_vec2_exp'); - await run(t, expBuilder(), [TypeVec(2, TypeF16)], TypeVec(2, TypeI32), t.params, cases); + await run(t, expBuilder(), [Type.vec2h], Type.vec2i, t.params, cases); }); g.test('f16_vec3_fract') @@ -277,7 +277,7 @@ struct __frexp_result_vec3_f16 { }) .fn(async t => { const cases = await d.get('f16_vec3_fract'); - await run(t, fractBuilder(), [TypeVec(3, TypeF16)], TypeVec(3, TypeF16), t.params, cases); + await run(t, fractBuilder(), [Type.vec3h], Type.vec3h, t.params, cases); }); g.test('f16_vec3_exp') @@ -298,7 +298,7 @@ struct __frexp_result_vec3_f16 { }) .fn(async t => { const cases = await d.get('f16_vec3_exp'); - await run(t, expBuilder(), [TypeVec(3, TypeF16)], TypeVec(3, TypeI32), t.params, cases); + await run(t, expBuilder(), [Type.vec3h], Type.vec3i, t.params, cases); }); g.test('f16_vec4_fract') @@ -319,7 +319,7 @@ struct __frexp_result_vec4_f16 { }) .fn(async t => { const cases = await d.get('f16_vec4_fract'); - await run(t, fractBuilder(), [TypeVec(4, TypeF16)], TypeVec(4, TypeF16), t.params, cases); + await run(t, fractBuilder(), [Type.vec4h], Type.vec4h, t.params, cases); }); g.test('f16_vec4_exp') @@ -340,5 +340,5 @@ struct __frexp_result_vec4_f16 { }) .fn(async t => { const cases = await d.get('f16_vec4_exp'); - await run(t, expBuilder(), [TypeVec(4, TypeF16)], TypeVec(4, TypeI32), t.params, cases); + await run(t, expBuilder(), [Type.vec4h], Type.vec4i, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/insertBits.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/insertBits.spec.ts index 1068e76252c2..b3eb65781d59 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/insertBits.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/insertBits.spec.ts @@ -18,17 +18,7 @@ Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { - i32Bits, - TypeI32, - u32, - TypeU32, - u32Bits, - vec2, - vec3, - vec4, - TypeVec, -} from '../../../../../util/conversion.js'; +import { i32Bits, Type, u32, u32Bits, vec2, vec3, vec4 } from '../../../../../util/conversion.js'; import { allInputSources, Config, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -46,8 +36,8 @@ g.test('integer') ) .fn(async t => { const cfg: Config = t.params; - const scalarType = t.params.signed ? TypeI32 : TypeU32; - const T = t.params.width === 1 ? scalarType : TypeVec(t.params.width, scalarType); + const scalarType = t.params.signed ? Type.i32 : Type.u32; + const T = t.params.width === 1 ? scalarType : Type.vec(t.params.width, scalarType); const V = (x: number, y?: number, z?: number, w?: number) => { y = y === undefined ? x : y; @@ -382,5 +372,5 @@ g.test('integer') ); } - await run(t, builtin('insertBits'), [T, T, TypeU32, TypeU32], T, cfg, cases); + await run(t, builtin('insertBits'), [T, T, Type.u32, Type.u32], T, cfg, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/inversesqrt.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/inversesqrt.spec.ts index fb5248ec8ad6..c27c56d4b5dd 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/inversesqrt.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/inversesqrt.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'inverseSqrt' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn inverseSqrt(e: T ) -> T Returns the reciprocal of sqrt(e). Component-wise when T is a vector. @@ -9,7 +9,7 @@ Returns the reciprocal of sqrt(e). Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF16, TypeF32 } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -33,7 +33,7 @@ g.test('f32') ) .fn(async t => { const cases = await d.get('f32'); - await run(t, builtin('inverseSqrt'), [TypeF32], TypeF32, t.params, cases); + await run(t, builtin('inverseSqrt'), [Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -47,5 +47,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get('f16'); - await run(t, builtin('inverseSqrt'), [TypeF16], TypeF16, t.params, cases); + await run(t, builtin('inverseSqrt'), [Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/ldexp.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/ldexp.spec.ts index e2eba8232d43..b06a3ef55086 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/ldexp.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/ldexp.spec.ts @@ -1,10 +1,10 @@ export const description = ` Execution tests for the 'ldexp' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN -K is AbstractInt, i32 +K is Type.abstractInt, i32 I is K or vecN, where I is a scalar if T is a scalar, or a vector when T is a vector @@ -14,7 +14,7 @@ Returns e1 * 2^e2. Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF16, TypeF32, TypeI32 } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -41,7 +41,7 @@ g.test('f32') ) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f32_const' : 'f32_non_const'); - await run(t, builtin('ldexp'), [TypeF32, TypeI32], TypeF32, t.params, cases); + await run(t, builtin('ldexp'), [Type.f32, Type.i32], Type.f32, t.params, cases); }); g.test('f16') @@ -55,5 +55,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f16_const' : 'f16_non_const'); - await run(t, builtin('ldexp'), [TypeF16, TypeI32], TypeF16, t.params, cases); + await run(t, builtin('ldexp'), [Type.f16, Type.i32], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/length.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/length.spec.ts index e91d5dcdafe5..690bc6152b37 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/length.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/length.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'length' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn length(e: T ) -> f32 Returns the length of e (e.g. abs(e) if T is a scalar, or sqrt(e[0]^2 + e[1]^2 + ...) if T is a vector). @@ -9,7 +9,7 @@ Returns the length of e (e.g. abs(e) if T is a scalar, or sqrt(e[0]^2 + e[1]^2 + import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF16, TypeF32, TypeVec } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -31,7 +31,7 @@ g.test('f32') .params(u => u.combine('inputSource', allInputSources)) .fn(async t => { const cases = await d.get('f32'); - await run(t, builtin('length'), [TypeF32], TypeF32, t.params, cases); + await run(t, builtin('length'), [Type.f32], Type.f32, t.params, cases); }); g.test('f32_vec2') @@ -42,7 +42,7 @@ g.test('f32_vec2') const cases = await d.get( t.params.inputSource === 'const' ? 'f32_vec2_const' : 'f32_vec2_non_const' ); - await run(t, builtin('length'), [TypeVec(2, TypeF32)], TypeF32, t.params, cases); + await run(t, builtin('length'), [Type.vec2f], Type.f32, t.params, cases); }); g.test('f32_vec3') @@ -53,7 +53,7 @@ g.test('f32_vec3') const cases = await d.get( t.params.inputSource === 'const' ? 'f32_vec3_const' : 'f32_vec3_non_const' ); - await run(t, builtin('length'), [TypeVec(3, TypeF32)], TypeF32, t.params, cases); + await run(t, builtin('length'), [Type.vec3f], Type.f32, t.params, cases); }); g.test('f32_vec4') @@ -64,7 +64,7 @@ g.test('f32_vec4') const cases = await d.get( t.params.inputSource === 'const' ? 'f32_vec4_const' : 'f32_vec4_non_const' ); - await run(t, builtin('length'), [TypeVec(4, TypeF32)], TypeF32, t.params, cases); + await run(t, builtin('length'), [Type.vec4f], Type.f32, t.params, cases); }); g.test('f16') @@ -76,7 +76,7 @@ g.test('f16') }) .fn(async t => { const cases = await d.get('f16'); - await run(t, builtin('length'), [TypeF16], TypeF16, t.params, cases); + await run(t, builtin('length'), [Type.f16], Type.f16, t.params, cases); }); g.test('f16_vec2') @@ -90,7 +90,7 @@ g.test('f16_vec2') const cases = await d.get( t.params.inputSource === 'const' ? 'f16_vec2_const' : 'f16_vec2_non_const' ); - await run(t, builtin('length'), [TypeVec(2, TypeF16)], TypeF16, t.params, cases); + await run(t, builtin('length'), [Type.vec2h], Type.f16, t.params, cases); }); g.test('f16_vec3') @@ -104,7 +104,7 @@ g.test('f16_vec3') const cases = await d.get( t.params.inputSource === 'const' ? 'f16_vec3_const' : 'f16_vec3_non_const' ); - await run(t, builtin('length'), [TypeVec(3, TypeF16)], TypeF16, t.params, cases); + await run(t, builtin('length'), [Type.vec3h], Type.f16, t.params, cases); }); g.test('f16_vec4') @@ -118,5 +118,5 @@ g.test('f16_vec4') const cases = await d.get( t.params.inputSource === 'const' ? 'f16_vec4_const' : 'f16_vec4_non_const' ); - await run(t, builtin('length'), [TypeVec(4, TypeF16)], TypeF16, t.params, cases); + await run(t, builtin('length'), [Type.vec4h], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/log.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/log.spec.ts index 387705320ff9..1d9814679002 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/log.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/log.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'log' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn log(e: T ) -> T Returns the natural logarithm of e. Component-wise when T is a vector. @@ -9,7 +9,7 @@ Returns the natural logarithm of e. Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF16, TypeF32 } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -39,7 +39,7 @@ TODO(#792): Decide what the ground-truth is for these tests. [1] ) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f32_const' : 'f32_non_const'); - await run(t, builtin('log'), [TypeF32], TypeF32, t.params, cases); + await run(t, builtin('log'), [Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -53,5 +53,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f16_const' : 'f16_non_const'); - await run(t, builtin('log'), [TypeF16], TypeF16, t.params, cases); + await run(t, builtin('log'), [Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/log2.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/log2.spec.ts index 86a38a60246a..497c66676cc3 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/log2.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/log2.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'log2' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn log2(e: T ) -> T Returns the base-2 logarithm of e. Component-wise when T is a vector. @@ -9,7 +9,7 @@ Returns the base-2 logarithm of e. Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF16, TypeF32 } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -39,7 +39,7 @@ TODO(#792): Decide what the ground-truth is for these tests. [1] ) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f32_const' : 'f32_non_const'); - await run(t, builtin('log2'), [TypeF32], TypeF32, t.params, cases); + await run(t, builtin('log2'), [Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -53,5 +53,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f16_const' : 'f16_non_const'); - await run(t, builtin('log2'), [TypeF16], TypeF16, t.params, cases); + await run(t, builtin('log2'), [Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/max.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/max.spec.ts index 63e3fda3f2b6..ee7cb0d674f5 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/max.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/max.spec.ts @@ -1,12 +1,12 @@ export const description = ` Execution tests for the 'max' builtin function -S is AbstractInt, i32, or u32 +S is abstract-int, i32, or u32 T is S or vecN @const fn max(e1: T ,e2: T) -> T Returns e2 if e1 is less than e2, and e1 otherwise. Component-wise when T is a vector. -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is vecN @const fn max(e1: T ,e2: T) -> T Returns e2 if e1 is less than e2, and e1 otherwise. @@ -18,17 +18,7 @@ Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { - TypeAbstractFloat, - TypeF16, - TypeF32, - TypeI32, - TypeU32, - i32, - u32, - abstractInt, - TypeAbstractInt, -} from '../../../../../util/conversion.js'; +import { Type, i32, u32, abstractInt } from '../../../../../util/conversion.js'; import { maxBigInt } from '../../../../../util/math.js'; import { Case } from '../../case.js'; import { allInputSources, onlyConstInputSource, run } from '../../expression.js'; @@ -66,8 +56,8 @@ g.test('abstract_int') await run( t, abstractIntBuiltin('max'), - [TypeAbstractInt, TypeAbstractInt], - TypeAbstractInt, + [Type.abstractInt, Type.abstractInt], + Type.abstractInt, t.params, cases ); @@ -87,7 +77,7 @@ g.test('u32') const test_values: number[] = [0, 1, 2, 0x70000000, 0x80000000, 0xffffffff]; const cases = generateTestCases(test_values, makeCase); - await run(t, builtin('max'), [TypeU32, TypeU32], TypeU32, t.params, cases); + await run(t, builtin('max'), [Type.u32, Type.u32], Type.u32, t.params, cases); }); g.test('i32') @@ -104,7 +94,7 @@ g.test('i32') const test_values: number[] = [-0x70000000, -2, -1, 0, 1, 2, 0x70000000]; const cases = generateTestCases(test_values, makeCase); - await run(t, builtin('max'), [TypeI32, TypeI32], TypeI32, t.params, cases); + await run(t, builtin('max'), [Type.i32, Type.i32], Type.i32, t.params, cases); }); g.test('abstract_float') @@ -120,8 +110,8 @@ g.test('abstract_float') await run( t, abstractFloatBuiltin('max'), - [TypeAbstractFloat, TypeAbstractFloat], - TypeAbstractFloat, + [Type.abstractFloat, Type.abstractFloat], + Type.abstractFloat, t.params, cases ); @@ -135,7 +125,7 @@ g.test('f32') ) .fn(async t => { const cases = await d.get('f32'); - await run(t, builtin('max'), [TypeF32, TypeF32], TypeF32, t.params, cases); + await run(t, builtin('max'), [Type.f32, Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -149,5 +139,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get('f16'); - await run(t, builtin('max'), [TypeF16, TypeF16], TypeF16, t.params, cases); + await run(t, builtin('max'), [Type.f16, Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/min.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/min.spec.ts index 30f411196047..ac636413997d 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/min.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/min.spec.ts @@ -1,12 +1,12 @@ export const description = ` Execution tests for the 'min' builtin function -S is AbstractInt, i32, or u32 +S is abstract-int, i32, or u32 T is S or vecN @const fn min(e1: T ,e2: T) -> T Returns e1 if e1 is less than e2, and e2 otherwise. Component-wise when T is a vector. -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn min(e1: T ,e2: T) -> T Returns e2 if e2 is less than e1, and e1 otherwise. @@ -17,17 +17,7 @@ Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { - TypeAbstractFloat, - TypeF16, - TypeF32, - TypeI32, - TypeU32, - i32, - u32, - abstractInt, - TypeAbstractInt, -} from '../../../../../util/conversion.js'; +import { Type, i32, u32, abstractInt } from '../../../../../util/conversion.js'; import { minBigInt } from '../../../../../util/math.js'; import { Case } from '../../case.js'; import { allInputSources, onlyConstInputSource, run } from '../../expression.js'; @@ -65,8 +55,8 @@ g.test('abstract_int') await run( t, abstractIntBuiltin('min'), - [TypeAbstractInt, TypeAbstractInt], - TypeAbstractInt, + [Type.abstractInt, Type.abstractInt], + Type.abstractInt, t.params, cases ); @@ -86,7 +76,7 @@ g.test('u32') const test_values: number[] = [0, 1, 2, 0x70000000, 0x80000000, 0xffffffff]; const cases = generateTestCases(test_values, makeCase); - await run(t, builtin('min'), [TypeU32, TypeU32], TypeU32, t.params, cases); + await run(t, builtin('min'), [Type.u32, Type.u32], Type.u32, t.params, cases); }); g.test('i32') @@ -103,7 +93,7 @@ g.test('i32') const test_values: number[] = [-0x70000000, -2, -1, 0, 1, 2, 0x70000000]; const cases = generateTestCases(test_values, makeCase); - await run(t, builtin('min'), [TypeI32, TypeI32], TypeI32, t.params, cases); + await run(t, builtin('min'), [Type.i32, Type.i32], Type.i32, t.params, cases); }); g.test('abstract_float') @@ -119,8 +109,8 @@ g.test('abstract_float') await run( t, abstractFloatBuiltin('min'), - [TypeAbstractFloat, TypeAbstractFloat], - TypeAbstractFloat, + [Type.abstractFloat, Type.abstractFloat], + Type.abstractFloat, t.params, cases ); @@ -134,7 +124,7 @@ g.test('f32') ) .fn(async t => { const cases = await d.get('f32'); - await run(t, builtin('min'), [TypeF32, TypeF32], TypeF32, t.params, cases); + await run(t, builtin('min'), [Type.f32, Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -148,5 +138,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get('f16'); - await run(t, builtin('min'), [TypeF16, TypeF16], TypeF16, t.params, cases); + await run(t, builtin('min'), [Type.f16, Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/mix.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/mix.spec.ts index d502c639620b..0005ab5c0eeb 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/mix.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/mix.spec.ts @@ -1,12 +1,12 @@ export const description = ` Execution tests for the 'mix' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn mix(e1: T, e2: T, e3: T) -> T Returns the linear blend of e1 and e2 (e.g. e1*(1-e3)+e2*e3). Component-wise when T is a vector. -T is AbstractFloat, f32, or f16 +T is abstract-float, f32, or f16 T2 is vecN @const fn mix(e1: T2, e2: T2, e3: T) -> T2 Returns the component-wise linear blend of e1 and e2, using scalar blending factor e3 for each component. @@ -16,7 +16,7 @@ Same as mix(e1,e2,T2(e3)). import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeAbstractFloat, TypeF16, TypeF32, TypeVec } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, onlyConstInputSource, run } from '../../expression.js'; import { abstractFloatBuiltin, builtin } from './builtin.js'; @@ -37,8 +37,8 @@ g.test('abstract_float_matching') await run( t, abstractFloatBuiltin('mix'), - [TypeAbstractFloat, TypeAbstractFloat, TypeAbstractFloat], - TypeAbstractFloat, + [Type.abstractFloat, Type.abstractFloat, Type.abstractFloat], + Type.abstractFloat, t.params, cases ); @@ -53,8 +53,8 @@ g.test('abstract_float_nonmatching_vec2') await run( t, abstractFloatBuiltin('mix'), - [TypeVec(2, TypeAbstractFloat), TypeVec(2, TypeAbstractFloat), TypeAbstractFloat], - TypeVec(2, TypeAbstractFloat), + [Type.vec(2, Type.abstractFloat), Type.vec(2, Type.abstractFloat), Type.abstractFloat], + Type.vec(2, Type.abstractFloat), t.params, cases ); @@ -69,8 +69,8 @@ g.test('abstract_float_nonmatching_vec3') await run( t, abstractFloatBuiltin('mix'), - [TypeVec(3, TypeAbstractFloat), TypeVec(3, TypeAbstractFloat), TypeAbstractFloat], - TypeVec(3, TypeAbstractFloat), + [Type.vec(3, Type.abstractFloat), Type.vec(3, Type.abstractFloat), Type.abstractFloat], + Type.vec(3, Type.abstractFloat), t.params, cases ); @@ -85,8 +85,8 @@ g.test('abstract_float_nonmatching_vec4') await run( t, abstractFloatBuiltin('mix'), - [TypeVec(4, TypeAbstractFloat), TypeVec(4, TypeAbstractFloat), TypeAbstractFloat], - TypeVec(4, TypeAbstractFloat), + [Type.vec(4, Type.abstractFloat), Type.vec(4, Type.abstractFloat), Type.abstractFloat], + Type.vec(4, Type.abstractFloat), t.params, cases ); @@ -100,7 +100,7 @@ g.test('f32_matching') ) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f32_const' : 'f32_non_const'); - await run(t, builtin('mix'), [TypeF32, TypeF32, TypeF32], TypeF32, t.params, cases); + await run(t, builtin('mix'), [Type.f32, Type.f32, Type.f32], Type.f32, t.params, cases); }); g.test('f32_nonmatching_vec2') @@ -111,14 +111,7 @@ g.test('f32_nonmatching_vec2') const cases = await d.get( t.params.inputSource === 'const' ? 'f32_vec2_scalar_const' : 'f32_vec2_scalar_non_const' ); - await run( - t, - builtin('mix'), - [TypeVec(2, TypeF32), TypeVec(2, TypeF32), TypeF32], - TypeVec(2, TypeF32), - t.params, - cases - ); + await run(t, builtin('mix'), [Type.vec2f, Type.vec2f, Type.f32], Type.vec2f, t.params, cases); }); g.test('f32_nonmatching_vec3') @@ -129,14 +122,7 @@ g.test('f32_nonmatching_vec3') const cases = await d.get( t.params.inputSource === 'const' ? 'f32_vec3_scalar_const' : 'f32_vec3_scalar_non_const' ); - await run( - t, - builtin('mix'), - [TypeVec(3, TypeF32), TypeVec(3, TypeF32), TypeF32], - TypeVec(3, TypeF32), - t.params, - cases - ); + await run(t, builtin('mix'), [Type.vec3f, Type.vec3f, Type.f32], Type.vec3f, t.params, cases); }); g.test('f32_nonmatching_vec4') @@ -147,14 +133,7 @@ g.test('f32_nonmatching_vec4') const cases = await d.get( t.params.inputSource === 'const' ? 'f32_vec4_scalar_const' : 'f32_vec4_scalar_non_const' ); - await run( - t, - builtin('mix'), - [TypeVec(4, TypeF32), TypeVec(4, TypeF32), TypeF32], - TypeVec(4, TypeF32), - t.params, - cases - ); + await run(t, builtin('mix'), [Type.vec4f, Type.vec4f, Type.f32], Type.vec4f, t.params, cases); }); g.test('f16_matching') @@ -168,7 +147,7 @@ g.test('f16_matching') }) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f16_const' : 'f16_non_const'); - await run(t, builtin('mix'), [TypeF16, TypeF16, TypeF16], TypeF16, t.params, cases); + await run(t, builtin('mix'), [Type.f16, Type.f16, Type.f16], Type.f16, t.params, cases); }); g.test('f16_nonmatching_vec2') @@ -182,14 +161,7 @@ g.test('f16_nonmatching_vec2') const cases = await d.get( t.params.inputSource === 'const' ? 'f16_vec2_scalar_const' : 'f16_vec2_scalar_non_const' ); - await run( - t, - builtin('mix'), - [TypeVec(2, TypeF16), TypeVec(2, TypeF16), TypeF16], - TypeVec(2, TypeF16), - t.params, - cases - ); + await run(t, builtin('mix'), [Type.vec2h, Type.vec2h, Type.f16], Type.vec2h, t.params, cases); }); g.test('f16_nonmatching_vec3') @@ -203,14 +175,7 @@ g.test('f16_nonmatching_vec3') const cases = await d.get( t.params.inputSource === 'const' ? 'f16_vec3_scalar_const' : 'f16_vec3_scalar_non_const' ); - await run( - t, - builtin('mix'), - [TypeVec(3, TypeF16), TypeVec(3, TypeF16), TypeF16], - TypeVec(3, TypeF16), - t.params, - cases - ); + await run(t, builtin('mix'), [Type.vec3h, Type.vec3h, Type.f16], Type.vec3h, t.params, cases); }); g.test('f16_nonmatching_vec4') @@ -224,12 +189,5 @@ g.test('f16_nonmatching_vec4') const cases = await d.get( t.params.inputSource === 'const' ? 'f16_vec4_scalar_const' : 'f16_vec4_scalar_non_const' ); - await run( - t, - builtin('mix'), - [TypeVec(4, TypeF16), TypeVec(4, TypeF16), TypeF16], - TypeVec(4, TypeF16), - t.params, - cases - ); + await run(t, builtin('mix'), [Type.vec4h, Type.vec4h, Type.f16], Type.vec4h, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/modf.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/modf.spec.ts index 3e12d4f8696d..6c988008f825 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/modf.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/modf.spec.ts @@ -1,13 +1,13 @@ export const description = ` Execution tests for the 'modf' builtin function -T is f32 or f16 or AbstractFloat +T is f32 or f16 or Type.abstractFloat @const fn modf(e:T) -> result_struct Splits |e| into fractional and whole number parts. The whole part is (|e| % 1.0), and the fractional part is |e| minus the whole part. Returns the result_struct for the given type. -S is f32 or f16 or AbstractFloat +S is f32 or f16 or Type.abstractFloat T is vecN @const fn modf(e:T) -> result_struct Splits the components of |e| into fractional and whole number parts. @@ -18,7 +18,7 @@ Returns the result_struct for the given type. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeAbstractFloat, TypeF16, TypeF32, TypeVec } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { abstractFloatShaderBuilder, allInputSources, @@ -67,7 +67,7 @@ struct __modf_result_f32 { .params(u => u.combine('inputSource', allInputSources)) .fn(async t => { const cases = await d.get('f32_fract'); - await run(t, fractBuilder(), [TypeF32], TypeF32, t.params, cases); + await run(t, fractBuilder(), [Type.f32], Type.f32, t.params, cases); }); g.test('f32_whole') @@ -85,7 +85,7 @@ struct __modf_result_f32 { .params(u => u.combine('inputSource', allInputSources)) .fn(async t => { const cases = await d.get('f32_whole'); - await run(t, wholeBuilder(), [TypeF32], TypeF32, t.params, cases); + await run(t, wholeBuilder(), [Type.f32], Type.f32, t.params, cases); }); g.test('f32_vec2_fract') @@ -103,7 +103,7 @@ struct __modf_result_vec2_f32 { .params(u => u.combine('inputSource', allInputSources)) .fn(async t => { const cases = await d.get('f32_vec2_fract'); - await run(t, fractBuilder(), [TypeVec(2, TypeF32)], TypeVec(2, TypeF32), t.params, cases); + await run(t, fractBuilder(), [Type.vec2f], Type.vec2f, t.params, cases); }); g.test('f32_vec2_whole') @@ -121,7 +121,7 @@ struct __modf_result_vec2_f32 { .params(u => u.combine('inputSource', allInputSources)) .fn(async t => { const cases = await d.get('f32_vec2_whole'); - await run(t, wholeBuilder(), [TypeVec(2, TypeF32)], TypeVec(2, TypeF32), t.params, cases); + await run(t, wholeBuilder(), [Type.vec2f], Type.vec2f, t.params, cases); }); g.test('f32_vec3_fract') @@ -139,7 +139,7 @@ struct __modf_result_vec3_f32 { .params(u => u.combine('inputSource', allInputSources)) .fn(async t => { const cases = await d.get('f32_vec3_fract'); - await run(t, fractBuilder(), [TypeVec(3, TypeF32)], TypeVec(3, TypeF32), t.params, cases); + await run(t, fractBuilder(), [Type.vec3f], Type.vec3f, t.params, cases); }); g.test('f32_vec3_whole') @@ -157,7 +157,7 @@ struct __modf_result_vec3_f32 { .params(u => u.combine('inputSource', allInputSources)) .fn(async t => { const cases = await d.get('f32_vec3_whole'); - await run(t, wholeBuilder(), [TypeVec(3, TypeF32)], TypeVec(3, TypeF32), t.params, cases); + await run(t, wholeBuilder(), [Type.vec3f], Type.vec3f, t.params, cases); }); g.test('f32_vec4_fract') @@ -175,7 +175,7 @@ struct __modf_result_vec4_f32 { .params(u => u.combine('inputSource', allInputSources)) .fn(async t => { const cases = await d.get('f32_vec4_fract'); - await run(t, fractBuilder(), [TypeVec(4, TypeF32)], TypeVec(4, TypeF32), t.params, cases); + await run(t, fractBuilder(), [Type.vec4f], Type.vec4f, t.params, cases); }); g.test('f32_vec4_whole') @@ -193,7 +193,7 @@ struct __modf_result_vec4_f32 { .params(u => u.combine('inputSource', allInputSources)) .fn(async t => { const cases = await d.get('f32_vec4_whole'); - await run(t, wholeBuilder(), [TypeVec(4, TypeF32)], TypeVec(4, TypeF32), t.params, cases); + await run(t, wholeBuilder(), [Type.vec4f], Type.vec4f, t.params, cases); }); g.test('f16_fract') @@ -214,7 +214,7 @@ struct __modf_result_f16 { }) .fn(async t => { const cases = await d.get('f16_fract'); - await run(t, fractBuilder(), [TypeF16], TypeF16, t.params, cases); + await run(t, fractBuilder(), [Type.f16], Type.f16, t.params, cases); }); g.test('f16_whole') @@ -235,7 +235,7 @@ struct __modf_result_f16 { }) .fn(async t => { const cases = await d.get('f16_whole'); - await run(t, wholeBuilder(), [TypeF16], TypeF16, t.params, cases); + await run(t, wholeBuilder(), [Type.f16], Type.f16, t.params, cases); }); g.test('f16_vec2_fract') @@ -256,7 +256,7 @@ struct __modf_result_vec2_f16 { }) .fn(async t => { const cases = await d.get('f16_vec2_fract'); - await run(t, fractBuilder(), [TypeVec(2, TypeF16)], TypeVec(2, TypeF16), t.params, cases); + await run(t, fractBuilder(), [Type.vec2h], Type.vec2h, t.params, cases); }); g.test('f16_vec2_whole') @@ -277,7 +277,7 @@ struct __modf_result_vec2_f16 { }) .fn(async t => { const cases = await d.get('f16_vec2_whole'); - await run(t, wholeBuilder(), [TypeVec(2, TypeF16)], TypeVec(2, TypeF16), t.params, cases); + await run(t, wholeBuilder(), [Type.vec2h], Type.vec2h, t.params, cases); }); g.test('f16_vec3_fract') @@ -298,7 +298,7 @@ struct __modf_result_vec3_f16 { }) .fn(async t => { const cases = await d.get('f16_vec3_fract'); - await run(t, fractBuilder(), [TypeVec(3, TypeF16)], TypeVec(3, TypeF16), t.params, cases); + await run(t, fractBuilder(), [Type.vec3h], Type.vec3h, t.params, cases); }); g.test('f16_vec3_whole') @@ -319,7 +319,7 @@ struct __modf_result_vec3_f16 { }) .fn(async t => { const cases = await d.get('f16_vec3_whole'); - await run(t, wholeBuilder(), [TypeVec(3, TypeF16)], TypeVec(3, TypeF16), t.params, cases); + await run(t, wholeBuilder(), [Type.vec3h], Type.vec3h, t.params, cases); }); g.test('f16_vec4_fract') @@ -340,7 +340,7 @@ struct __modf_result_vec4_f16 { }) .fn(async t => { const cases = await d.get('f16_vec4_fract'); - await run(t, fractBuilder(), [TypeVec(4, TypeF16)], TypeVec(4, TypeF16), t.params, cases); + await run(t, fractBuilder(), [Type.vec4h], Type.vec4h, t.params, cases); }); g.test('f16_vec4_whole') @@ -361,43 +361,43 @@ struct __modf_result_vec4_f16 { }) .fn(async t => { const cases = await d.get('f16_vec4_whole'); - await run(t, wholeBuilder(), [TypeVec(4, TypeF16)], TypeVec(4, TypeF16), t.params, cases); + await run(t, wholeBuilder(), [Type.vec4h], Type.vec4h, t.params, cases); }); g.test('abstract_fract') .specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions') .desc( ` -T is AbstractFloat +T is abstract-float struct __modf_result_abstract { - fract : AbstractFloat, // fractional part - whole : AbstractFloat // whole part + fract : Type.abstractFloat, // fractional part + whole : Type.abstractFloat // whole part } ` ) .params(u => u.combine('inputSource', onlyConstInputSource)) .fn(async t => { const cases = await d.get('abstract_fract'); - await run(t, abstractFractBuilder(), [TypeAbstractFloat], TypeAbstractFloat, t.params, cases); + await run(t, abstractFractBuilder(), [Type.abstractFloat], Type.abstractFloat, t.params, cases); }); g.test('abstract_whole') .specURL('https://www.w3.org/TR/WGSL/#float-builtin-functions') .desc( ` -T is AbstractFloat +T is abstract-float struct __modf_result_abstract { - fract : AbstractFloat, // fractional part - whole : AbstractFloat // whole part + fract : Type.abstractFloat, // fractional part + whole : Type.abstractFloat // whole part } ` ) .params(u => u.combine('inputSource', onlyConstInputSource)) .fn(async t => { const cases = await d.get('abstract_whole'); - await run(t, abstractWholeBuilder(), [TypeAbstractFloat], TypeAbstractFloat, t.params, cases); + await run(t, abstractWholeBuilder(), [Type.abstractFloat], Type.abstractFloat, t.params, cases); }); g.test('abstract_vec2_fract') @@ -418,8 +418,8 @@ struct __modf_result_vec2_abstract { await run( t, abstractFractBuilder(), - [TypeVec(2, TypeAbstractFloat)], - TypeVec(2, TypeAbstractFloat), + [Type.vec(2, Type.abstractFloat)], + Type.vec(2, Type.abstractFloat), t.params, cases ); @@ -443,8 +443,8 @@ struct __modf_result_vec2_abstract { await run( t, abstractWholeBuilder(), - [TypeVec(2, TypeAbstractFloat)], - TypeVec(2, TypeAbstractFloat), + [Type.vec(2, Type.abstractFloat)], + Type.vec(2, Type.abstractFloat), t.params, cases ); @@ -468,8 +468,8 @@ struct __modf_result_vec3_abstract { await run( t, abstractFractBuilder(), - [TypeVec(3, TypeAbstractFloat)], - TypeVec(3, TypeAbstractFloat), + [Type.vec(3, Type.abstractFloat)], + Type.vec(3, Type.abstractFloat), t.params, cases ); @@ -493,8 +493,8 @@ struct __modf_result_vec3_abstract { await run( t, abstractWholeBuilder(), - [TypeVec(3, TypeAbstractFloat)], - TypeVec(3, TypeAbstractFloat), + [Type.vec(3, Type.abstractFloat)], + Type.vec(3, Type.abstractFloat), t.params, cases ); @@ -518,8 +518,8 @@ struct __modf_result_vec4_abstract { await run( t, abstractFractBuilder(), - [TypeVec(4, TypeAbstractFloat)], - TypeVec(4, TypeAbstractFloat), + [Type.vec(4, Type.abstractFloat)], + Type.vec(4, Type.abstractFloat), t.params, cases ); @@ -543,8 +543,8 @@ struct __modf_result_vec4_abstract { await run( t, abstractWholeBuilder(), - [TypeVec(4, TypeAbstractFloat)], - TypeVec(4, TypeAbstractFloat), + [Type.vec(4, Type.abstractFloat)], + Type.vec(4, Type.abstractFloat), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/call/builtin/normalize.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/normalize.spec.ts index 4820f5884d69..7aca252464da 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/normalize.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/normalize.spec.ts @@ -1,14 +1,14 @@ export const description = ` Execution tests for the 'normalize' builtin function -T is AbstractFloat, f32, or f16 +T is abstract-float, f32, or f16 @const fn normalize(e: vecN ) -> vecN Returns a unit vector in the same direction as e. `; import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF16, TypeF32, TypeVec } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -32,7 +32,7 @@ g.test('f32_vec2') const cases = await d.get( t.params.inputSource === 'const' ? 'f32_vec2_const' : 'f32_vec2_non_const' ); - await run(t, builtin('normalize'), [TypeVec(2, TypeF32)], TypeVec(2, TypeF32), t.params, cases); + await run(t, builtin('normalize'), [Type.vec2f], Type.vec2f, t.params, cases); }); g.test('f32_vec3') @@ -43,7 +43,7 @@ g.test('f32_vec3') const cases = await d.get( t.params.inputSource === 'const' ? 'f32_vec3_const' : 'f32_vec3_non_const' ); - await run(t, builtin('normalize'), [TypeVec(3, TypeF32)], TypeVec(3, TypeF32), t.params, cases); + await run(t, builtin('normalize'), [Type.vec3f], Type.vec3f, t.params, cases); }); g.test('f32_vec4') @@ -54,7 +54,7 @@ g.test('f32_vec4') const cases = await d.get( t.params.inputSource === 'const' ? 'f32_vec4_const' : 'f32_vec4_non_const' ); - await run(t, builtin('normalize'), [TypeVec(4, TypeF32)], TypeVec(4, TypeF32), t.params, cases); + await run(t, builtin('normalize'), [Type.vec4f], Type.vec4f, t.params, cases); }); g.test('f16_vec2') @@ -68,7 +68,7 @@ g.test('f16_vec2') const cases = await d.get( t.params.inputSource === 'const' ? 'f16_vec2_const' : 'f16_vec2_non_const' ); - await run(t, builtin('normalize'), [TypeVec(2, TypeF16)], TypeVec(2, TypeF16), t.params, cases); + await run(t, builtin('normalize'), [Type.vec2h], Type.vec2h, t.params, cases); }); g.test('f16_vec3') @@ -82,7 +82,7 @@ g.test('f16_vec3') const cases = await d.get( t.params.inputSource === 'const' ? 'f16_vec3_const' : 'f16_vec3_non_const' ); - await run(t, builtin('normalize'), [TypeVec(3, TypeF16)], TypeVec(3, TypeF16), t.params, cases); + await run(t, builtin('normalize'), [Type.vec3h], Type.vec3h, t.params, cases); }); g.test('f16_vec4') @@ -96,5 +96,5 @@ g.test('f16_vec4') const cases = await d.get( t.params.inputSource === 'const' ? 'f16_vec4_const' : 'f16_vec4_non_const' ); - await run(t, builtin('normalize'), [TypeVec(4, TypeF16)], TypeVec(4, TypeF16), t.params, cases); + await run(t, builtin('normalize'), [Type.vec4h], Type.vec4h, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/pack2x16float.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/pack2x16float.spec.ts index efa4041259eb..5ba69934279f 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/pack2x16float.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/pack2x16float.spec.ts @@ -6,7 +6,7 @@ which is then placed in bits 16 × i through 16 × i + 15 of the result. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF32, TypeU32, TypeVec } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -24,5 +24,5 @@ g.test('pack') .params(u => u.combine('inputSource', allInputSources)) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f32_const' : 'f32_non_const'); - await run(t, builtin('pack2x16float'), [TypeVec(2, TypeF32)], TypeU32, t.params, cases); + await run(t, builtin('pack2x16float'), [Type.vec2f], Type.u32, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/pack2x16snorm.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/pack2x16snorm.spec.ts index 6479fe7ce070..1bcca2f73fe2 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/pack2x16snorm.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/pack2x16snorm.spec.ts @@ -8,15 +8,7 @@ bits 16 × i through 16 × i + 15 of the result. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; import { kValue } from '../../../../../util/constants.js'; -import { - f32, - pack2x16snorm, - TypeF32, - TypeU32, - TypeVec, - u32, - vec2, -} from '../../../../../util/conversion.js'; +import { f32, pack2x16snorm, u32, vec2, Type } from '../../../../../util/conversion.js'; import { quantizeToF32, vectorF32Range } from '../../../../../util/math.js'; import { Case } from '../../case.js'; import { allInputSources, run } from '../../expression.js'; @@ -52,5 +44,5 @@ g.test('pack') ]; }); - await run(t, builtin('pack2x16snorm'), [TypeVec(2, TypeF32)], TypeU32, t.params, cases); + await run(t, builtin('pack2x16snorm'), [Type.vec2f], Type.u32, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/pack2x16unorm.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/pack2x16unorm.spec.ts index 303c555c1daf..334d1064824c 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/pack2x16unorm.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/pack2x16unorm.spec.ts @@ -8,15 +8,7 @@ bits 16 × i through 16 × i + 15 of the result. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; import { kValue } from '../../../../../util/constants.js'; -import { - f32, - pack2x16unorm, - TypeF32, - TypeU32, - TypeVec, - u32, - vec2, -} from '../../../../../util/conversion.js'; +import { f32, pack2x16unorm, u32, vec2, Type } from '../../../../../util/conversion.js'; import { quantizeToF32, vectorF32Range } from '../../../../../util/math.js'; import { Case } from '../../case.js'; import { allInputSources, run } from '../../expression.js'; @@ -52,5 +44,5 @@ g.test('pack') ]; }); - await run(t, builtin('pack2x16unorm'), [TypeVec(2, TypeF32)], TypeU32, t.params, cases); + await run(t, builtin('pack2x16unorm'), [Type.vec2f], Type.u32, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/pack4x8snorm.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/pack4x8snorm.spec.ts index b1c2607c940f..fbe362ea45e8 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/pack4x8snorm.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/pack4x8snorm.spec.ts @@ -8,16 +8,7 @@ bits 8 × i through 8 × i + 7 of the result. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; import { kValue } from '../../../../../util/constants.js'; -import { - f32, - pack4x8snorm, - Scalar, - TypeF32, - TypeU32, - TypeVec, - u32, - vec4, -} from '../../../../../util/conversion.js'; +import { f32, pack4x8snorm, ScalarValue, u32, vec4, Type } from '../../../../../util/conversion.js'; import { quantizeToF32, vectorF32Range } from '../../../../../util/math.js'; import { Case } from '../../case.js'; import { allInputSources, run } from '../../expression.js'; @@ -36,7 +27,12 @@ g.test('pack') .params(u => u.combine('inputSource', allInputSources)) .fn(async t => { const makeCase = (vals: [number, number, number, number]): Case => { - const vals_f32 = new Array(4) as [Scalar, Scalar, Scalar, Scalar]; + const vals_f32 = new Array(4) as [ + ScalarValue, + ScalarValue, + ScalarValue, + ScalarValue, + ]; for (const idx in vals) { vals[idx] = quantizeToF32(vals[idx]); vals_f32[idx] = f32(vals[idx]); @@ -57,5 +53,5 @@ g.test('pack') ]; }); - await run(t, builtin('pack4x8snorm'), [TypeVec(4, TypeF32)], TypeU32, t.params, cases); + await run(t, builtin('pack4x8snorm'), [Type.vec4f], Type.u32, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/pack4x8unorm.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/pack4x8unorm.spec.ts index fa67e8f4ae3d..c7d62e722b24 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/pack4x8unorm.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/pack4x8unorm.spec.ts @@ -8,16 +8,7 @@ bits 8 × i through 8 × i + 7 of the result. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; import { kValue } from '../../../../../util/constants.js'; -import { - f32, - pack4x8unorm, - Scalar, - TypeF32, - TypeU32, - TypeVec, - u32, - vec4, -} from '../../../../../util/conversion.js'; +import { f32, pack4x8unorm, ScalarValue, u32, vec4, Type } from '../../../../../util/conversion.js'; import { quantizeToF32, vectorF32Range } from '../../../../../util/math.js'; import { Case } from '../../case.js'; import { allInputSources, run } from '../../expression.js'; @@ -36,7 +27,12 @@ g.test('pack') .params(u => u.combine('inputSource', allInputSources)) .fn(async t => { const makeCase = (vals: [number, number, number, number]): Case => { - const vals_f32 = new Array(4) as [Scalar, Scalar, Scalar, Scalar]; + const vals_f32 = new Array(4) as [ + ScalarValue, + ScalarValue, + ScalarValue, + ScalarValue, + ]; for (const idx in vals) { vals[idx] = quantizeToF32(vals[idx]); vals_f32[idx] = f32(vals[idx]); @@ -57,5 +53,5 @@ g.test('pack') ]; }); - await run(t, builtin('pack4x8unorm'), [TypeVec(4, TypeF32)], TypeU32, t.params, cases); + await run(t, builtin('pack4x8unorm'), [Type.vec4f], Type.u32, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/pack4xI8.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/pack4xI8.spec.ts index 8caae09eba7c..94aa67f0ae85 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/pack4xI8.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/pack4xI8.spec.ts @@ -8,7 +8,7 @@ Component e[i] of the input is mapped to bits (8 * i) through (8 * (i + 7)) of t import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeI32, TypeU32, TypeVec, u32, toVector, i32 } from '../../../../../util/conversion.js'; +import { u32, toVector, i32, Type } from '../../../../../util/conversion.js'; import { Case } from '../../case.js'; import { allInputSources, Config, run } from '../../expression.js'; @@ -65,5 +65,5 @@ g.test('basic') return [makeCase(v)]; }); - await run(t, builtin('pack4xI8'), [TypeVec(4, TypeI32)], TypeU32, cfg, cases); + await run(t, builtin('pack4xI8'), [Type.vec4i], Type.u32, cfg, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/pack4xI8Clamp.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/pack4xI8Clamp.spec.ts index 0ab63d89beef..4968ed1e04de 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/pack4xI8Clamp.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/pack4xI8Clamp.spec.ts @@ -9,7 +9,7 @@ result. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeI32, TypeU32, TypeVec, u32, toVector, i32 } from '../../../../../util/conversion.js'; +import { u32, toVector, i32, Type } from '../../../../../util/conversion.js'; import { clamp } from '../../../../../util/math.js'; import { Case } from '../../case.js'; import { allInputSources, Config, run } from '../../expression.js'; @@ -69,5 +69,5 @@ g.test('basic') return [makeCase(v)]; }); - await run(t, builtin('pack4xI8Clamp'), [TypeVec(4, TypeI32)], TypeU32, cfg, cases); + await run(t, builtin('pack4xI8Clamp'), [Type.vec4i], Type.u32, cfg, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/pack4xU8.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/pack4xU8.spec.ts index 0d4d2223f05d..9d08e88d4432 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/pack4xU8.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/pack4xU8.spec.ts @@ -8,7 +8,7 @@ Component e[i] of the input is mapped to bits (8 * i) through (8 * (i + 7)) of t import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeU32, TypeVec, u32, toVector } from '../../../../../util/conversion.js'; +import { u32, toVector, Type } from '../../../../../util/conversion.js'; import { Case } from '../../case.js'; import { allInputSources, Config, run } from '../../expression.js'; @@ -50,5 +50,5 @@ g.test('basic') return [makeCase(v)]; }); - await run(t, builtin('pack4xU8'), [TypeVec(4, TypeU32)], TypeU32, cfg, cases); + await run(t, builtin('pack4xU8'), [Type.vec4u], Type.u32, cfg, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/pack4xU8Clamp.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/pack4xU8Clamp.spec.ts index 0f70cb6f8c87..ffecf9b8779c 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/pack4xU8Clamp.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/pack4xU8Clamp.spec.ts @@ -9,7 +9,7 @@ result. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeU32, TypeVec, u32, toVector } from '../../../../../util/conversion.js'; +import { u32, toVector, Type } from '../../../../../util/conversion.js'; import { clamp } from '../../../../../util/math.js'; import { Case } from '../../case.js'; import { allInputSources, Config, run } from '../../expression.js'; @@ -53,5 +53,5 @@ g.test('basic') return [makeCase(v)]; }); - await run(t, builtin('pack4xU8Clamp'), [TypeVec(4, TypeU32)], TypeU32, cfg, cases); + await run(t, builtin('pack4xU8Clamp'), [Type.vec4u], Type.u32, cfg, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/pow.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/pow.spec.ts index deea077e7a31..476c591a358e 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/pow.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/pow.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'pow' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn pow(e1: T ,e2: T ) -> T Returns e1 raised to the power e2. Component-wise when T is a vector. @@ -9,7 +9,7 @@ Returns e1 raised to the power e2. Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF16, TypeF32 } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -33,7 +33,7 @@ g.test('f32') ) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f32_const' : 'f32_non_const'); - await run(t, builtin('pow'), [TypeF32, TypeF32], TypeF32, t.params, cases); + await run(t, builtin('pow'), [Type.f32, Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -47,5 +47,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f16_const' : 'f16_non_const'); - await run(t, builtin('pow'), [TypeF16, TypeF16], TypeF16, t.params, cases); + await run(t, builtin('pow'), [Type.f16, Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/quantizeToF16.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/quantizeToF16.spec.ts index ee34ddd17479..0aa9669e93b3 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/quantizeToF16.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/quantizeToF16.spec.ts @@ -10,7 +10,7 @@ Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF32 } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -26,5 +26,5 @@ g.test('f32') ) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f32_const' : 'f32_non_const'); - await run(t, builtin('quantizeToF16'), [TypeF32], TypeF32, t.params, cases); + await run(t, builtin('quantizeToF16'), [Type.f32], Type.f32, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/radians.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/radians.spec.ts index afc7da6d8cdb..a405807ec044 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/radians.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/radians.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'radians' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn radians(e1: T ) -> T Converts degrees to radians, approximating e1 * π / 180. @@ -10,7 +10,7 @@ Component-wise when T is a vector import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeAbstractFloat, TypeF16, TypeF32 } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, onlyConstInputSource, run } from '../../expression.js'; import { abstractFloatBuiltin, builtin } from './builtin.js'; @@ -31,8 +31,8 @@ g.test('abstract_float') await run( t, abstractFloatBuiltin('radians'), - [TypeAbstractFloat], - TypeAbstractFloat, + [Type.abstractFloat], + Type.abstractFloat, t.params, cases ); @@ -46,7 +46,7 @@ g.test('f32') ) .fn(async t => { const cases = await d.get('f32'); - await run(t, builtin('radians'), [TypeF32], TypeF32, t.params, cases); + await run(t, builtin('radians'), [Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -60,5 +60,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get('f16'); - await run(t, builtin('radians'), [TypeF16], TypeF16, t.params, cases); + await run(t, builtin('radians'), [Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/reflect.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/reflect.spec.ts index 0908bf04be5c..9c1a25f22a60 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/reflect.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/reflect.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'reflect' builtin function -T is vecN, vecN, or vecN +T is vecN, vecN, or vecN @const fn reflect(e1: T, e2: T ) -> T For the incident vector e1 and surface orientation e2, returns the reflection direction e1-2*dot(e2,e1)*e2. @@ -9,7 +9,7 @@ direction e1-2*dot(e2,e1)*e2. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF16, TypeF32, TypeVec } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -31,14 +31,7 @@ g.test('f32_vec2') const cases = await d.get( t.params.inputSource === 'const' ? 'f32_vec2_const' : 'f32_vec2_non_const' ); - await run( - t, - builtin('reflect'), - [TypeVec(2, TypeF32), TypeVec(2, TypeF32)], - TypeVec(2, TypeF32), - t.params, - cases - ); + await run(t, builtin('reflect'), [Type.vec2f, Type.vec2f], Type.vec2f, t.params, cases); }); g.test('f32_vec3') @@ -49,14 +42,7 @@ g.test('f32_vec3') const cases = await d.get( t.params.inputSource === 'const' ? 'f32_vec3_const' : 'f32_vec3_non_const' ); - await run( - t, - builtin('reflect'), - [TypeVec(3, TypeF32), TypeVec(3, TypeF32)], - TypeVec(3, TypeF32), - t.params, - cases - ); + await run(t, builtin('reflect'), [Type.vec3f, Type.vec3f], Type.vec3f, t.params, cases); }); g.test('f32_vec4') @@ -67,14 +53,7 @@ g.test('f32_vec4') const cases = await d.get( t.params.inputSource === 'const' ? 'f32_vec4_const' : 'f32_vec4_non_const' ); - await run( - t, - builtin('reflect'), - [TypeVec(4, TypeF32), TypeVec(4, TypeF32)], - TypeVec(4, TypeF32), - t.params, - cases - ); + await run(t, builtin('reflect'), [Type.vec4f, Type.vec4f], Type.vec4f, t.params, cases); }); g.test('f16_vec2') @@ -88,14 +67,7 @@ g.test('f16_vec2') const cases = await d.get( t.params.inputSource === 'const' ? 'f16_vec2_const' : 'f16_vec2_non_const' ); - await run( - t, - builtin('reflect'), - [TypeVec(2, TypeF16), TypeVec(2, TypeF16)], - TypeVec(2, TypeF16), - t.params, - cases - ); + await run(t, builtin('reflect'), [Type.vec2h, Type.vec2h], Type.vec2h, t.params, cases); }); g.test('f16_vec3') @@ -109,14 +81,7 @@ g.test('f16_vec3') const cases = await d.get( t.params.inputSource === 'const' ? 'f16_vec3_const' : 'f16_vec3_non_const' ); - await run( - t, - builtin('reflect'), - [TypeVec(3, TypeF16), TypeVec(3, TypeF16)], - TypeVec(3, TypeF16), - t.params, - cases - ); + await run(t, builtin('reflect'), [Type.vec3h, Type.vec3h], Type.vec3h, t.params, cases); }); g.test('f16_vec4') @@ -130,12 +95,5 @@ g.test('f16_vec4') const cases = await d.get( t.params.inputSource === 'const' ? 'f16_vec4_const' : 'f16_vec4_non_const' ); - await run( - t, - builtin('reflect'), - [TypeVec(4, TypeF16), TypeVec(4, TypeF16)], - TypeVec(4, TypeF16), - t.params, - cases - ); + await run(t, builtin('reflect'), [Type.vec4h, Type.vec4h], Type.vec4h, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/refract.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/refract.spec.ts index 67eb8ac94658..466c9be7d922 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/refract.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/refract.spec.ts @@ -2,7 +2,7 @@ export const description = ` Execution tests for the 'refract' builtin function T is vecN -I is AbstractFloat, f32, or f16 +I is abstract-float, f32, or f16 @const fn refract(e1: T ,e2: T ,e3: I ) -> T For the incident vector e1 and surface normal e2, and the ratio of indices of refraction e3, let k = 1.0 -e3*e3* (1.0 - dot(e2,e1) * dot(e2,e1)). @@ -12,7 +12,7 @@ vector e3*e1- (e3* dot(e2,e1) + sqrt(k)) *e2. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF16, TypeF32, TypeVec } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -37,8 +37,8 @@ g.test('f32_vec2') await run( t, builtin('refract'), - [TypeVec(2, TypeF32), TypeVec(2, TypeF32), TypeF32], - TypeVec(2, TypeF32), + [Type.vec2f, Type.vec2f, Type.f32], + Type.vec2f, t.params, cases ); @@ -55,8 +55,8 @@ g.test('f32_vec3') await run( t, builtin('refract'), - [TypeVec(3, TypeF32), TypeVec(3, TypeF32), TypeF32], - TypeVec(3, TypeF32), + [Type.vec3f, Type.vec3f, Type.f32], + Type.vec3f, t.params, cases ); @@ -73,8 +73,8 @@ g.test('f32_vec4') await run( t, builtin('refract'), - [TypeVec(4, TypeF32), TypeVec(4, TypeF32), TypeF32], - TypeVec(4, TypeF32), + [Type.vec4f, Type.vec4f, Type.f32], + Type.vec4f, t.params, cases ); @@ -94,8 +94,8 @@ g.test('f16_vec2') await run( t, builtin('refract'), - [TypeVec(2, TypeF16), TypeVec(2, TypeF16), TypeF16], - TypeVec(2, TypeF16), + [Type.vec2h, Type.vec2h, Type.f16], + Type.vec2h, t.params, cases ); @@ -115,8 +115,8 @@ g.test('f16_vec3') await run( t, builtin('refract'), - [TypeVec(3, TypeF16), TypeVec(3, TypeF16), TypeF16], - TypeVec(3, TypeF16), + [Type.vec3h, Type.vec3h, Type.f16], + Type.vec3h, t.params, cases ); @@ -136,8 +136,8 @@ g.test('f16_vec4') await run( t, builtin('refract'), - [TypeVec(4, TypeF16), TypeVec(4, TypeF16), TypeF16], - TypeVec(4, TypeF16), + [Type.vec4h, Type.vec4h, Type.f16], + Type.vec4h, t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/call/builtin/reverseBits.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/reverseBits.spec.ts index 6acb35982216..e235e62a5284 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/reverseBits.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/reverseBits.spec.ts @@ -10,7 +10,7 @@ Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeU32, u32Bits, TypeI32, i32Bits } from '../../../../../util/conversion.js'; +import { u32Bits, i32Bits, Type } from '../../../../../util/conversion.js'; import { allInputSources, Config, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -26,7 +26,7 @@ g.test('u32') .fn(async t => { const cfg: Config = t.params; // prettier-ignore - await run(t, builtin('reverseBits'), [TypeU32], TypeU32, cfg, [ + await run(t, builtin('reverseBits'), [Type.u32], Type.u32, cfg, [ // Zero { input: u32Bits(0b00000000000000000000000000000000), expected: u32Bits(0b00000000000000000000000000000000) }, @@ -142,7 +142,7 @@ g.test('i32') .fn(async t => { const cfg: Config = t.params; // prettier-ignore - await run(t, builtin('reverseBits'), [TypeI32], TypeI32, cfg, [ + await run(t, builtin('reverseBits'), [Type.i32], Type.i32, cfg, [ // Zero { input: i32Bits(0b00000000000000000000000000000000), expected: i32Bits(0b00000000000000000000000000000000) }, diff --git a/src/webgpu/shader/execution/expression/call/builtin/round.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/round.spec.ts index 8d215b952d59..eeaf41b38185 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/round.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/round.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'round' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn round(e: T) -> T Result is the integer k nearest to e, as a floating point value. @@ -12,7 +12,7 @@ Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeAbstractFloat, TypeF16, TypeF32 } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, onlyConstInputSource, run } from '../../expression.js'; import { abstractFloatBuiltin, builtin } from './builtin.js'; @@ -33,8 +33,8 @@ g.test('abstract_float') await run( t, abstractFloatBuiltin('round'), - [TypeAbstractFloat], - TypeAbstractFloat, + [Type.abstractFloat], + Type.abstractFloat, t.params, cases ); @@ -48,7 +48,7 @@ g.test('f32') ) .fn(async t => { const cases = await d.get('f32'); - await run(t, builtin('round'), [TypeF32], TypeF32, t.params, cases); + await run(t, builtin('round'), [Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -62,5 +62,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get('f16'); - await run(t, builtin('round'), [TypeF16], TypeF16, t.params, cases); + await run(t, builtin('round'), [Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/saturate.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/saturate.spec.ts index 216ffb734578..79c61e4eec6c 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/saturate.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/saturate.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'saturate' builtin function -S is AbstractFloat, f32, or f16 +S is abstract-float, f32, or f16 T is S or vecN @const fn saturate(e: T) -> T Returns clamp(e, 0.0, 1.0). Component-wise when T is a vector. @@ -9,7 +9,7 @@ Returns clamp(e, 0.0, 1.0). Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeAbstractFloat, TypeF16, TypeF32 } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, onlyConstInputSource, run } from '../../expression.js'; import { abstractFloatBuiltin, builtin } from './builtin.js'; @@ -30,8 +30,8 @@ g.test('abstract_float') await run( t, abstractFloatBuiltin('saturate'), - [TypeAbstractFloat], - TypeAbstractFloat, + [Type.abstractFloat], + Type.abstractFloat, t.params, cases ); @@ -44,7 +44,7 @@ g.test('f32') ) .fn(async t => { const cases = await d.get('f32'); - await run(t, builtin('saturate'), [TypeF32], TypeF32, t.params, cases); + await run(t, builtin('saturate'), [Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -58,5 +58,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get('f16'); - await run(t, builtin('saturate'), [TypeF16], TypeF16, t.params, cases); + await run(t, builtin('saturate'), [Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/select.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/select.spec.ts index aa5ee45e84e2..63accbc2d466 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/select.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/select.spec.ts @@ -14,12 +14,6 @@ import { makeTestGroup } from '../../../../../../common/framework/test_group.js' import { GPUTest } from '../../../../../gpu_test.js'; import { VectorType, - TypeVec, - TypeBool, - TypeF32, - TypeF16, - TypeI32, - TypeU32, f32, f16, i32, @@ -31,10 +25,9 @@ import { vec3, vec4, abstractFloat, - TypeAbstractFloat, - TypeAbstractInt, abstractInt, - Scalar, + ScalarValue, + Type, } from '../../../../../util/conversion.js'; import { Case } from '../../case.js'; import { run, allInputSources } from '../../expression.js'; @@ -51,41 +44,41 @@ type scalarKind = 'b' | 'af' | 'f' | 'h' | 'ai' | 'i' | 'u'; const dataType = { b: { - type: TypeBool, + type: Type.bool, scalar_builder: makeBool, shader_builder: builtin('select'), }, af: { - type: TypeAbstractFloat, + type: Type.abstractFloat, scalar_builder: abstractFloat, shader_builder: abstractFloatBuiltin('select'), }, f: { - type: TypeF32, + type: Type.f32, scalar_builder: f32, shader_builder: builtin('select'), }, h: { - type: TypeF16, + type: Type.f16, scalar_builder: f16, shader_builder: builtin('select'), }, ai: { - type: TypeAbstractInt, + type: Type.abstractInt, // Only ints are used in the tests below, so the conversion to bigint will // be safe. If a non-int is passed in this will Error. - scalar_builder: (v: number): Scalar => { + scalar_builder: (v: number): ScalarValue => { return abstractInt(BigInt(v)); }, shader_builder: abstractIntBuiltin('select'), }, i: { - type: TypeI32, + type: Type.i32, scalar_builder: i32, shader_builder: builtin('select'), }, u: { - type: TypeU32, + type: Type.u32, scalar_builder: u32, shader_builder: builtin('select'), }, @@ -136,21 +129,21 @@ g.test('scalar') ], }, vec2: { - type: TypeVec(2, componentType), + type: Type.vec(2, componentType), cases: [ { input: [v2a, v2b, False], expected: v2a }, { input: [v2a, v2b, True], expected: v2b }, ], }, vec3: { - type: TypeVec(3, componentType), + type: Type.vec(3, componentType), cases: [ { input: [v3a, v3b, False], expected: v3a }, { input: [v3a, v3b, True], expected: v3b }, ], }, vec4: { - type: TypeVec(4, componentType), + type: Type.vec(4, componentType), cases: [ { input: [v4a, v4b, False], expected: v4a }, { input: [v4a, v4b, True], expected: v4b }, @@ -162,7 +155,7 @@ g.test('scalar') await run( t, dataType[t.params.component as scalarKind].shader_builder, - [overload.type, overload.type, TypeBool], + [overload.type, overload.type, Type.bool], overload.type, t.params, overload.cases @@ -205,8 +198,8 @@ g.test('vector') const a = vec2(scalars[0], scalars[1]); const b = vec2(scalars[4], scalars[5]); tests = { - dataType: TypeVec(2, componentType), - boolType: TypeVec(2, TypeBool), + dataType: Type.vec(2, componentType), + boolType: Type.vec(2, Type.bool), cases: [ { input: [a, b, vec2(F, F)], expected: vec2(a.x, a.y) }, { input: [a, b, vec2(F, T)], expected: vec2(a.x, b.y) }, @@ -220,8 +213,8 @@ g.test('vector') const a = vec3(scalars[0], scalars[1], scalars[2]); const b = vec3(scalars[4], scalars[5], scalars[6]); tests = { - dataType: TypeVec(3, componentType), - boolType: TypeVec(3, TypeBool), + dataType: Type.vec(3, componentType), + boolType: Type.vec(3, Type.bool), cases: [ { input: [a, b, vec3(F, F, F)], expected: vec3(a.x, a.y, a.z) }, { input: [a, b, vec3(F, F, T)], expected: vec3(a.x, a.y, b.z) }, @@ -239,8 +232,8 @@ g.test('vector') const a = vec4(scalars[0], scalars[1], scalars[2], scalars[3]); const b = vec4(scalars[4], scalars[5], scalars[6], scalars[7]); tests = { - dataType: TypeVec(4, componentType), - boolType: TypeVec(4, TypeBool), + dataType: Type.vec(4, componentType), + boolType: Type.vec(4, Type.bool), cases: [ { input: [a, b, vec4(F, F, F, F)], expected: vec4(a.x, a.y, a.z, a.w) }, { input: [a, b, vec4(F, F, F, T)], expected: vec4(a.x, a.y, a.z, b.w) }, diff --git a/src/webgpu/shader/execution/expression/call/builtin/sign.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/sign.spec.ts index 7872377dc42c..f7d2e3ccfd5a 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/sign.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/sign.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'sign' builtin function -S is AbstractFloat, AbstractInt, i32, f32, f16 +S is abstract-float, Type.abstractInt, i32, f32, f16 T is S or vecN @const fn sign(e: T ) -> T Returns the sign of e. Component-wise when T is a vector. @@ -9,13 +9,7 @@ Returns the sign of e. Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { - TypeAbstractFloat, - TypeAbstractInt, - TypeF16, - TypeF32, - TypeI32, -} from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, onlyConstInputSource, run } from '../../expression.js'; import { abstractFloatBuiltin, abstractIntBuiltin, builtin } from './builtin.js'; @@ -36,8 +30,8 @@ g.test('abstract_float') await run( t, abstractFloatBuiltin('sign'), - [TypeAbstractFloat], - TypeAbstractFloat, + [Type.abstractFloat], + Type.abstractFloat, t.params, cases ); @@ -53,7 +47,7 @@ g.test('abstract_int') ) .fn(async t => { const cases = await d.get('abstract_int'); - await run(t, abstractIntBuiltin('sign'), [TypeAbstractInt], TypeAbstractInt, t.params, cases); + await run(t, abstractIntBuiltin('sign'), [Type.abstractInt], Type.abstractInt, t.params, cases); }); g.test('i32') @@ -64,7 +58,7 @@ g.test('i32') ) .fn(async t => { const cases = await d.get('i32'); - await run(t, builtin('sign'), [TypeI32], TypeI32, t.params, cases); + await run(t, builtin('sign'), [Type.i32], Type.i32, t.params, cases); }); g.test('f32') @@ -75,7 +69,7 @@ g.test('f32') ) .fn(async t => { const cases = await d.get('f32'); - await run(t, builtin('sign'), [TypeF32], TypeF32, t.params, cases); + await run(t, builtin('sign'), [Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -89,5 +83,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get('f16'); - await run(t, builtin('sign'), [TypeF16], TypeF16, t.params, cases); + await run(t, builtin('sign'), [Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/sin.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/sin.spec.ts index e9420fc0880d..4d649b4db5eb 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/sin.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/sin.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'sin' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn sin(e: T ) -> T Returns the sine of e. Component-wise when T is a vector. @@ -9,7 +9,7 @@ Returns the sine of e. Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF16, TypeF32 } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -39,7 +39,7 @@ TODO(#792): Decide what the ground-truth is for these tests. [1] ) .fn(async t => { const cases = await d.get('f32'); - await run(t, builtin('sin'), [TypeF32], TypeF32, t.params, cases); + await run(t, builtin('sin'), [Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -53,5 +53,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get('f16'); - await run(t, builtin('sin'), [TypeF16], TypeF16, t.params, cases); + await run(t, builtin('sin'), [Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/sinh.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/sinh.spec.ts index 0070befa47fc..f59616d9af12 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/sinh.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/sinh.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'sinh' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn sinh(e: T ) -> T Returns the hyperbolic sine of e. Component-wise when T is a vector. @@ -9,7 +9,7 @@ Returns the hyperbolic sine of e. Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF16, TypeF32 } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -33,7 +33,7 @@ g.test('f32') ) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f32_const' : 'f32_non_const'); - await run(t, builtin('sinh'), [TypeF32], TypeF32, t.params, cases); + await run(t, builtin('sinh'), [Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -47,5 +47,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f16_const' : 'f16_non_const'); - await run(t, builtin('sinh'), [TypeF16], TypeF16, t.params, cases); + await run(t, builtin('sinh'), [Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/smoothstep.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/smoothstep.spec.ts index a32c112b8a94..1404061d02f7 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/smoothstep.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/smoothstep.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'smoothstep' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn smoothstep(low: T , high: T , x: T ) -> T Returns the smooth Hermite interpolation between 0 and 1. @@ -11,7 +11,7 @@ For scalar T, the result is t * t * (3.0 - 2.0 * t), where t = clamp((x - low) / import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF16, TypeF32 } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -35,7 +35,7 @@ g.test('f32') ) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f32_const' : 'f32_non_const'); - await run(t, builtin('smoothstep'), [TypeF32, TypeF32, TypeF32], TypeF32, t.params, cases); + await run(t, builtin('smoothstep'), [Type.f32, Type.f32, Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -49,5 +49,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f16_const' : 'f16_non_const'); - await run(t, builtin('smoothstep'), [TypeF16, TypeF16, TypeF16], TypeF16, t.params, cases); + await run(t, builtin('smoothstep'), [Type.f16, Type.f16, Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/sqrt.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/sqrt.spec.ts index cfd379fea660..ee4197d70f7d 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/sqrt.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/sqrt.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'sqrt' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn sqrt(e: T ) -> T Returns the square root of e. Component-wise when T is a vector. @@ -9,7 +9,7 @@ Returns the square root of e. Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF16, TypeF32 } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -33,7 +33,7 @@ g.test('f32') ) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f32_const' : 'f32_non_const'); - await run(t, builtin('sqrt'), [TypeF32], TypeF32, t.params, cases); + await run(t, builtin('sqrt'), [Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -47,5 +47,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f16_const' : 'f16_non_const'); - await run(t, builtin('sqrt'), [TypeF16], TypeF16, t.params, cases); + await run(t, builtin('sqrt'), [Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/step.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/step.spec.ts index c55a48812e9c..caf75e6f623a 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/step.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/step.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'step' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn step(edge: T ,x: T ) -> T Returns 1.0 if edge ≤ x, and 0.0 otherwise. Component-wise when T is a vector. @@ -9,7 +9,7 @@ Returns 1.0 if edge ≤ x, and 0.0 otherwise. Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF16, TypeF32 } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -33,7 +33,7 @@ g.test('f32') ) .fn(async t => { const cases = await d.get('f32'); - await run(t, builtin('step'), [TypeF32, TypeF32], TypeF32, t.params, cases); + await run(t, builtin('step'), [Type.f32, Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -47,5 +47,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get('f16'); - await run(t, builtin('step'), [TypeF16, TypeF16], TypeF16, t.params, cases); + await run(t, builtin('step'), [Type.f16, Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/tan.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/tan.spec.ts index f86b3c959a16..4ddef19fe168 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/tan.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/tan.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'tan' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn tan(e: T ) -> T Returns the tangent of e. Component-wise when T is a vector. @@ -9,7 +9,7 @@ Returns the tangent of e. Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF16, TypeF32 } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -33,7 +33,7 @@ g.test('f32') ) .fn(async t => { const cases = await d.get('f32'); - await run(t, builtin('tan'), [TypeF32], TypeF32, t.params, cases); + await run(t, builtin('tan'), [Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -47,5 +47,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get('f16'); - await run(t, builtin('tan'), [TypeF16], TypeF16, t.params, cases); + await run(t, builtin('tan'), [Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/tanh.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/tanh.spec.ts index 496c7bcf1b11..19f4ff55318b 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/tanh.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/tanh.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'tanh' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn tanh(e: T ) -> T Returns the hyperbolic tangent of e. Component-wise when T is a vector. @@ -9,7 +9,7 @@ Returns the hyperbolic tangent of e. Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF16, TypeF32 } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -33,7 +33,7 @@ g.test('f32') ) .fn(async t => { const cases = await d.get('f32'); - await run(t, builtin('tanh'), [TypeF32], TypeF32, t.params, cases); + await run(t, builtin('tanh'), [Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -47,5 +47,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get('f16'); - await run(t, builtin('tanh'), [TypeF16], TypeF16, t.params, cases); + await run(t, builtin('tanh'), [Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/transpose.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/transpose.spec.ts index 90fa226a01e3..7a96906cfa71 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/transpose.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/transpose.spec.ts @@ -1,14 +1,14 @@ export const description = ` Execution tests for the 'transpose' builtin function -T is AbstractFloat, f32, or f16 +T is abstract-float, f32, or f16 @const transpose(e: matRxC ) -> matCxR Returns the transpose of e. `; import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeAbstractFloat, TypeF16, TypeF32, TypeMat } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, onlyConstInputSource, run } from '../../expression.js'; import { abstractFloatBuiltin, builtin } from './builtin.js'; @@ -32,8 +32,8 @@ g.test('abstract_float') await run( t, abstractFloatBuiltin('transpose'), - [TypeMat(cols, rows, TypeAbstractFloat)], - TypeMat(rows, cols, TypeAbstractFloat), + [Type.mat(cols, rows, Type.abstractFloat)], + Type.mat(rows, cols, Type.abstractFloat), t.params, cases ); @@ -59,8 +59,8 @@ g.test('f32') await run( t, builtin('transpose'), - [TypeMat(cols, rows, TypeF32)], - TypeMat(rows, cols, TypeF32), + [Type.mat(cols, rows, Type.f32)], + Type.mat(rows, cols, Type.f32), t.params, cases ); @@ -89,8 +89,8 @@ g.test('f16') await run( t, builtin('transpose'), - [TypeMat(cols, rows, TypeF16)], - TypeMat(rows, cols, TypeF16), + [Type.mat(cols, rows, Type.f16)], + Type.mat(rows, cols, Type.f16), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/call/builtin/trunc.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/trunc.spec.ts index 022248ae5b97..9d05709fc686 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/trunc.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/trunc.spec.ts @@ -1,7 +1,7 @@ export const description = ` Execution tests for the 'trunc' builtin function -S is AbstractFloat, f32, f16 +S is abstract-float, f32, f16 T is S or vecN @const fn trunc(e: T ) -> T Returns the nearest whole number whose absolute value is less than or equal to e. @@ -10,7 +10,7 @@ Component-wise when T is a vector. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeAbstractFloat, TypeF16, TypeF32 } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, onlyConstInputSource, run } from '../../expression.js'; import { abstractFloatBuiltin, builtin } from './builtin.js'; @@ -31,8 +31,8 @@ g.test('abstract_float') await run( t, abstractFloatBuiltin('trunc'), - [TypeAbstractFloat], - TypeAbstractFloat, + [Type.abstractFloat], + Type.abstractFloat, t.params, cases ); @@ -46,7 +46,7 @@ g.test('f32') ) .fn(async t => { const cases = await d.get('f32'); - await run(t, builtin('trunc'), [TypeF32], TypeF32, t.params, cases); + await run(t, builtin('trunc'), [Type.f32], Type.f32, t.params, cases); }); g.test('f16') @@ -60,5 +60,5 @@ g.test('f16') }) .fn(async t => { const cases = await d.get('f16'); - await run(t, builtin('trunc'), [TypeF16], TypeF16, t.params, cases); + await run(t, builtin('trunc'), [Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/unpack2x16float.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/unpack2x16float.spec.ts index da1819f8ef6e..e145afca50be 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/unpack2x16float.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/unpack2x16float.spec.ts @@ -7,7 +7,7 @@ interpretation of bits 16×i through 16×i+15 of e as an IEEE-754 binary16 value import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF32, TypeU32, TypeVec } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -25,5 +25,5 @@ g.test('unpack') .params(u => u.combine('inputSource', allInputSources)) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'u32_const' : 'u32_non_const'); - await run(t, builtin('unpack2x16float'), [TypeU32], TypeVec(2, TypeF32), t.params, cases); + await run(t, builtin('unpack2x16float'), [Type.u32], Type.vec2f, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/unpack2x16snorm.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/unpack2x16snorm.spec.ts index a88702bcce70..059a5664f9e4 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/unpack2x16snorm.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/unpack2x16snorm.spec.ts @@ -7,7 +7,7 @@ of bits 16×i through 16×i+15 of e as a twos-complement signed integer. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF32, TypeU32, TypeVec } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -25,5 +25,5 @@ g.test('unpack') .params(u => u.combine('inputSource', allInputSources)) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'u32_const' : 'u32_non_const'); - await run(t, builtin('unpack2x16snorm'), [TypeU32], TypeVec(2, TypeF32), t.params, cases); + await run(t, builtin('unpack2x16snorm'), [Type.u32], Type.vec2f, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/unpack2x16unorm.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/unpack2x16unorm.spec.ts index 325e0a9735b5..971f384023ef 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/unpack2x16unorm.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/unpack2x16unorm.spec.ts @@ -7,7 +7,7 @@ Component i of the result is v ÷ 65535, where v is the interpretation of bits import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF32, TypeU32, TypeVec } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -25,5 +25,5 @@ g.test('unpack') .params(u => u.combine('inputSource', allInputSources)) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'u32_const' : 'u32_non_const'); - await run(t, builtin('unpack2x16unorm'), [TypeU32], TypeVec(2, TypeF32), t.params, cases); + await run(t, builtin('unpack2x16unorm'), [Type.u32], Type.vec2f, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/unpack4x8snorm.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/unpack4x8snorm.spec.ts index 3b48cca4539f..d6e533621b14 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/unpack4x8snorm.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/unpack4x8snorm.spec.ts @@ -7,7 +7,7 @@ bits 8×i through 8×i+7 of e as a twos-complement signed integer. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF32, TypeU32, TypeVec } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -25,5 +25,5 @@ g.test('unpack') .params(u => u.combine('inputSource', allInputSources)) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'u32_const' : 'u32_non_const'); - await run(t, builtin('unpack4x8snorm'), [TypeU32], TypeVec(4, TypeF32), t.params, cases); + await run(t, builtin('unpack4x8snorm'), [Type.u32], Type.vec4f, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/unpack4x8unorm.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/unpack4x8unorm.spec.ts index 3e57f2592ee5..026043da1a97 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/unpack4x8unorm.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/unpack4x8unorm.spec.ts @@ -7,7 +7,7 @@ through 8×i+7 of e as an unsigned integer. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeF32, TypeU32, TypeVec } from '../../../../../util/conversion.js'; +import { Type } from '../../../../../util/conversion.js'; import { allInputSources, run } from '../../expression.js'; import { builtin } from './builtin.js'; @@ -25,5 +25,5 @@ g.test('unpack') .params(u => u.combine('inputSource', allInputSources)) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'u32_const' : 'u32_non_const'); - await run(t, builtin('unpack4x8unorm'), [TypeU32], TypeVec(4, TypeF32), t.params, cases); + await run(t, builtin('unpack4x8unorm'), [Type.u32], Type.vec4f, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/unpack4xI8.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/unpack4xI8.spec.ts index 6253ad7bebca..4f7e4ed3a70d 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/unpack4xI8.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/unpack4xI8.spec.ts @@ -8,7 +8,7 @@ with sign extension. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeI32, TypeU32, TypeVec, u32, toVector, i32 } from '../../../../../util/conversion.js'; +import { u32, toVector, i32, Type } from '../../../../../util/conversion.js'; import { Case } from '../../case.js'; import { allInputSources, Config, run } from '../../expression.js'; @@ -52,5 +52,5 @@ g.test('basic') return [makeCase(v)]; }); - await run(t, builtin('unpack4xI8'), [TypeU32], TypeVec(4, TypeI32), cfg, cases); + await run(t, builtin('unpack4xI8'), [Type.u32], Type.vec4i, cfg, cases); }); diff --git a/src/webgpu/shader/execution/expression/call/builtin/unpack4xU8.spec.ts b/src/webgpu/shader/execution/expression/call/builtin/unpack4xU8.spec.ts index 3c13f32fecc6..09849030eb10 100644 --- a/src/webgpu/shader/execution/expression/call/builtin/unpack4xU8.spec.ts +++ b/src/webgpu/shader/execution/expression/call/builtin/unpack4xU8.spec.ts @@ -8,7 +8,7 @@ with zero extension. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../../gpu_test.js'; -import { TypeU32, TypeVec, u32, toVector } from '../../../../../util/conversion.js'; +import { u32, toVector, Type } from '../../../../../util/conversion.js'; import { Case } from '../../case.js'; import { allInputSources, Config, run } from '../../expression.js'; @@ -44,5 +44,5 @@ g.test('basic') return [makeCase(v)]; }); - await run(t, builtin('unpack4xU8'), [TypeU32], TypeVec(4, TypeU32), cfg, cases); + await run(t, builtin('unpack4xU8'), [Type.u32], Type.vec4u, cfg, cases); }); diff --git a/src/webgpu/shader/execution/expression/case.ts b/src/webgpu/shader/execution/expression/case.ts index 436f0a6964ad..d837b1c32fb4 100644 --- a/src/webgpu/shader/execution/expression/case.ts +++ b/src/webgpu/shader/execution/expression/case.ts @@ -1,7 +1,14 @@ import { crc32 } from '../../../../common/util/crc32.js'; import { ROArrayArray } from '../../../../common/util/types.js'; import { assert } from '../../../../common/util/util.js'; -import { abstractInt, i32, ScalarBuilder, u32, Value, Vector } from '../../../util/conversion.js'; +import { + abstractInt, + i32, + ScalarBuilder, + u32, + Value, + VectorValue, +} from '../../../util/conversion.js'; import { cartesianProduct, QuantizeFunc, @@ -62,7 +69,9 @@ export function selectNCases(dis: string, n: number, cases: Case[]): Case[] { return cases; } const dis_crc32 = crc32(dis); - return cases.filter(c => n * (0xffff_ffff / count) > (crc32(c.input.toString()) ^ dis_crc32)); + return cases.filter( + c => Math.trunc((n / count) * 0xffff_ffff) > (crc32(c.input.toString()) ^ dis_crc32) >>> 0 + ); } /** @@ -103,8 +112,8 @@ function makeScalarVectorBinaryToVectorCase( return undefined; } return { - input: [scalarize(scalar), new Vector(vector.map(scalarize))], - expected: new Vector(result.filter(notUndefined).map(scalarize)), + input: [scalarize(scalar), new VectorValue(vector.map(scalarize))], + expected: new VectorValue(result.filter(notUndefined).map(scalarize)), }; } @@ -154,8 +163,8 @@ function makeVectorScalarBinaryToVectorCase( return undefined; } return { - input: [new Vector(vector.map(scalarize)), scalarize(scalar)], - expected: new Vector(result.filter(notUndefined).map(scalarize)), + input: [new VectorValue(vector.map(scalarize)), scalarize(scalar)], + expected: new VectorValue(result.filter(notUndefined).map(scalarize)), }; } @@ -357,8 +366,8 @@ function makeVectorVectorToScalarCase( return { input: [ - new Vector(param0_quantized.map(scalarize)), - new Vector(param1_quantized.map(scalarize)), + new VectorValue(param0_quantized.map(scalarize)), + new VectorValue(param1_quantized.map(scalarize)), ], expected: scalarize(result), }; diff --git a/src/webgpu/shader/execution/expression/case_cache.ts b/src/webgpu/shader/execution/expression/case_cache.ts index 1991c78217e9..345183c5d506 100644 --- a/src/webgpu/shader/execution/expression/case_cache.ts +++ b/src/webgpu/shader/execution/expression/case_cache.ts @@ -3,11 +3,11 @@ import { unreachable } from '../../../../common/util/util.js'; import BinaryStream from '../../../util/binary_stream.js'; import { deserializeComparator, serializeComparator } from '../../../util/compare.js'; import { - Matrix, - Scalar, + MatrixValue, Value, - Vector, + VectorValue, deserializeValue, + isScalarValue, serializeValue, } from '../../../util/conversion.js'; import { @@ -31,7 +31,7 @@ enum SerializedExpectationKind { /** serializeExpectation() serializes an Expectation to a BinaryStream */ export function serializeExpectation(s: BinaryStream, e: Expectation) { - if (e instanceof Scalar || e instanceof Vector || e instanceof Matrix) { + if (isScalarValue(e) || e instanceof VectorValue || e instanceof MatrixValue) { s.writeU8(SerializedExpectationKind.Value); serializeValue(s, e); return; diff --git a/src/webgpu/shader/execution/expression/expectation.ts b/src/webgpu/shader/execution/expression/expectation.ts index 8078673f2569..d43ab5279116 100644 --- a/src/webgpu/shader/execution/expression/expectation.ts +++ b/src/webgpu/shader/execution/expression/expectation.ts @@ -1,6 +1,6 @@ import { ROArrayArray } from '../../../../common/util/types.js'; import { Comparator, compare } from '../../../util/compare.js'; -import { Matrix, Scalar, Value, Vector } from '../../../util/conversion.js'; +import { MatrixValue, Value, VectorValue, isScalarValue } from '../../../util/conversion.js'; import { FPInterval } from '../../../util/floating_point.js'; export type Expectation = @@ -14,9 +14,9 @@ export type Expectation = export function isComparator(e: Expectation): e is Comparator { return !( e instanceof FPInterval || - e instanceof Scalar || - e instanceof Vector || - e instanceof Matrix || + isScalarValue(e) || + e instanceof VectorValue || + e instanceof MatrixValue || e instanceof Array ); } diff --git a/src/webgpu/shader/execution/expression/expression.ts b/src/webgpu/shader/execution/expression/expression.ts index c622e6c5fdde..e86d068c6daa 100644 --- a/src/webgpu/shader/execution/expression/expression.ts +++ b/src/webgpu/shader/execution/expression/expression.ts @@ -5,17 +5,18 @@ import { Comparator, ComparatorImpl } from '../../../util/compare.js'; import { kValue } from '../../../util/constants.js'; import { MatrixType, - Scalar, + ScalarValue, ScalarType, Type, - TypeU32, - TypeVec, - Value, - Vector, VectorType, + Value, + VectorValue, isAbstractType, scalarTypeOf, + ArrayType, + elementTypeOf, } from '../../../util/conversion.js'; +import { align } from '../../../util/math.js'; import { Case } from './case.js'; import { toComparator } from './expectation.js'; @@ -49,103 +50,120 @@ export type Config = { vectorize?: number; }; -// Helper for returning the stride for a given Type -function valueStride(ty: Type): number { - // AbstractFloats and AbstractInts are passed out of the shader via structs of - // 2x u32s and unpacking containers as arrays - if (scalarTypeOf(ty).kind === 'abstract-float' || scalarTypeOf(ty).kind === 'abstract-int') { - if (ty instanceof ScalarType) { - return 16; - } - if (ty instanceof VectorType) { - if (ty.width === 2) { - return 16; - } - // vec3s have padding to make them the same size as vec4s - return 32; - } - if (ty instanceof MatrixType) { - switch (ty.cols) { - case 2: - switch (ty.rows) { - case 2: - return 32; - case 3: - return 64; - case 4: - return 64; - } - break; - case 3: - switch (ty.rows) { - case 2: - return 48; - case 3: - return 96; - case 4: - return 96; - } - break; - case 4: - switch (ty.rows) { - case 2: - return 64; - case 3: - return 128; - case 4: - return 128; - } - break; - } +/** + * @returns the size and alignment in bytes of the type 'ty', taking into + * consideration storage alignment constraints and abstract numerics, which are + * encoded as a struct of holding two u32s. + */ +function sizeAndAlignmentOf(ty: Type, source: InputSource): { size: number; alignment: number } { + if (ty instanceof ScalarType) { + if (ty.kind === 'abstract-float' || ty.kind === 'abstract-int') { + // AbstractFloats and AbstractInts are passed out of the shader via structs of + // 2x u32s and unpacking containers as arrays + return { size: 8, alignment: 8 }; } - unreachable(`AbstractFloats have not yet been implemented for ${ty.toString()}`); + return { size: ty.size, alignment: ty.alignment }; + } + + if (ty instanceof VectorType) { + const out = sizeAndAlignmentOf(ty.elementType, source); + const n = ty.width === 3 ? 4 : ty.width; + out.size *= n; + out.alignment *= n; + return out; } if (ty instanceof MatrixType) { - switch (ty.cols) { - case 2: - switch (ty.rows) { - case 2: - return 16; - case 3: - return 32; - case 4: - return 32; - } - break; - case 3: - switch (ty.rows) { - case 2: - return 32; - case 3: - return 64; - case 4: - return 64; - } - break; - case 4: - switch (ty.rows) { - case 2: - return 32; - case 3: - return 64; - case 4: - return 64; - } - break; + const out = sizeAndAlignmentOf(ty.elementType, source); + const n = ty.rows === 3 ? 4 : ty.rows; + out.size *= n * ty.cols; + out.alignment *= n; + return out; + } + + if (ty instanceof ArrayType) { + const out = sizeAndAlignmentOf(ty.elementType, source); + if (source === 'uniform') { + out.alignment = align(out.alignment, 16); } - unreachable( - `Attempted to get stride length for a matrix with dimensions (${ty.cols}x${ty.rows}), which isn't currently handled` - ); + out.size *= ty.count; + return out; + } + + unreachable(`unhandled type: ${ty}`); +} + +/** + * @returns the stride in bytes of the type 'ty', taking into consideration abstract numerics, + * which are encoded as a struct of 2 x u32. + */ +function strideOf(ty: Type, source: InputSource): number { + const sizeAndAlign = sizeAndAlignmentOf(ty, source); + return align(sizeAndAlign.size, sizeAndAlign.alignment); +} + +/** + * Calls 'callback' with the layout information of each structure member with the types 'members'. + * @returns the byte size, stride and alignment of the structure. + */ +function structLayout( + members: Type[], + source: InputSource, + callback?: (m: { + index: number; + type: Type; + size: number; + alignment: number; + offset: number; + }) => void +): { size: number; stride: number; alignment: number } { + let offset = 0; + let alignment = 1; + for (let i = 0; i < members.length; i++) { + const member = members[i]; + const sizeAndAlign = sizeAndAlignmentOf(member, source); + offset = align(offset, sizeAndAlign.alignment); + if (callback) { + callback({ + index: i, + type: member, + size: sizeAndAlign.size, + alignment: sizeAndAlign.alignment, + offset, + }); + } + offset += sizeAndAlign.size; + alignment = Math.max(alignment, sizeAndAlign.alignment); } - // Handles scalars and vectors - return 16; + if (source === 'uniform') { + alignment = align(alignment, 16); + } + + const size = offset; + const stride = align(size, alignment); + return { size, stride, alignment }; +} + +/** @returns the stride in bytes between two consecutive structures with the given members */ +function structStride(members: Type[], source: InputSource): number { + return structLayout(members, source).stride; } -// Helper for summing up all the stride values for an array of Types -function valueStrides(tys: Type[]): number { - return tys.map(valueStride).reduce((sum, c) => sum + c); +/** @returns the WGSL to describe the structure members in 'members' */ +function wgslMembers(members: Type[], source: InputSource, memberName: (i: number) => string) { + const lines: string[] = []; + const layout = structLayout(members, source, m => { + lines.push(` @size(${m.size}) ${memberName(lines.length)} : ${m.type},`); + }); + const padding = layout.stride - layout.size; + if (padding > 0) { + // Pad with a 'f16' if the padding requires an odd multiple of 2 bytes. + // This is required as 'i32' has an alignment and size of 4 bytes. + const ty = (padding & 2) !== 0 ? 'f16' : 'i32'; + lines.push(` @size(${padding}) padding : ${ty},`); + } + return lines.join('\n'); } // Helper for returning the WGSL storage type for the given Type. @@ -158,11 +176,11 @@ function storageType(ty: Type): Type { `Custom handling is implemented for 'abstract-float' values` ); if (ty.kind === 'bool') { - return TypeU32; + return Type.u32; } } if (ty instanceof VectorType) { - return TypeVec(ty.width, storageType(ty.elementType) as ScalarType); + return Type.vec(ty.width, storageType(ty.elementType) as ScalarType); } return ty; } @@ -296,12 +314,13 @@ export async function run( // 2k appears to be a sweet-spot when benchmarking. return Math.floor( Math.min(1024 * 2, t.device.limits.maxUniformBufferBindingSize) / - valueStrides(parameterTypes) + structStride(parameterTypes, cfg.inputSource) ); case 'storage_r': case 'storage_rw': return Math.floor( - t.device.limits.maxStorageBufferBindingSize / valueStrides(parameterTypes) + t.device.limits.maxStorageBufferBindingSize / + structStride(parameterTypes, cfg.inputSource) ); } })(); @@ -380,7 +399,8 @@ async function submitBatch( pipelineCache: PipelineCache ): Promise<() => void> { // Construct a buffer to hold the results of the expression tests - const outputBufferSize = cases.length * valueStride(resultType); + const outputStride = structStride([resultType], 'storage_rw'); + const outputBufferSize = align(cases.length * outputStride, 4); const outputBuffer = t.device.createBuffer({ size: outputBufferSize, usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST | GPUBufferUsage.STORAGE, @@ -415,7 +435,7 @@ async function submitBatch( // Read the outputs from the output buffer const outputs = new Array(cases.length); for (let i = 0; i < cases.length; i++) { - outputs[i] = resultType.read(outputData, i * valueStride(resultType)); + outputs[i] = resultType.read(outputData, i * outputStride); } // The list of expectation failures @@ -484,7 +504,7 @@ function wgslOutputs(resultType: Type, count: number): string { ) { output_struct = ` struct Output { - @size(${valueStride(resultType)}) value : ${storageType(resultType)} + @size(${strideOf(resultType, 'storage_rw')}) value : ${storageType(resultType)} };`; } else { if (resultType instanceof ScalarType) { @@ -494,7 +514,7 @@ struct Output { }; struct Output { - @size(${valueStride(resultType)}) value: AF, + @size(${strideOf(resultType, 'storage_rw')}) value: AF, };`; } if (resultType instanceof VectorType) { @@ -505,7 +525,7 @@ struct Output { }; struct Output { - @size(${valueStride(resultType)}) value: array, + @size(${strideOf(resultType, 'storage_rw')}) value: array, };`; } @@ -518,7 +538,7 @@ struct Output { }; struct Output { - @size(${valueStride(resultType)}) value: array, ${cols}>, + @size(${strideOf(resultType, 'storage_rw')}) value: array, ${cols}>, };`; } @@ -602,7 +622,7 @@ function basicExpressionShaderBody( // Constant eval ////////////////////////////////////////////////////////////////////////// let body = ''; - if (parameterTypes.some(isAbstractType)) { + if (parameterTypes.some(ty => isAbstractType(elementTypeOf(ty)))) { // Directly assign the expression to the output, to avoid an // intermediate store, which will concretize the value early body = cases @@ -656,10 +676,8 @@ ${body} return ` struct Input { -${parameterTypes - .map((ty, i) => ` @size(${valueStride(ty)}) param${i} : ${storageType(ty)},`) - .join('\n')} -}; +${wgslMembers(parameterTypes.map(storageType), inputSource, i => `param${i}`)} +} ${wgslOutputs(resultType, cases.length)} @@ -791,8 +809,7 @@ ${wgslHeader(parameterTypes, resultType)} ${wgslOutputs(resultType, cases.length)} struct Input { - @size(${valueStride(lhsType)}) lhs : ${storageType(lhsType)}, - @size(${valueStride(rhsType)}) rhs : ${storageType(rhsType)}, +${wgslMembers([lhsType, rhsType].map(storageType), inputSource, i => ['lhs', 'rhs'][i])} } ${wgslInputVar(inputSource, cases.length)} @@ -1128,27 +1145,23 @@ async function buildPipeline( // Input values come from a uniform or storage buffer // size in bytes of the input buffer - const inputSize = cases.length * valueStrides(parameterTypes); + const caseStride = structStride(parameterTypes, inputSource); + const inputSize = align(cases.length * caseStride, 4); // Holds all the parameter values for all cases const inputData = new Uint8Array(inputSize); // Pack all the input parameter values into the inputData buffer - { - const caseStride = valueStrides(parameterTypes); - for (let caseIdx = 0; caseIdx < cases.length; caseIdx++) { - const caseBase = caseIdx * caseStride; - let offset = caseBase; - for (let paramIdx = 0; paramIdx < parameterTypes.length; paramIdx++) { - const params = cases[caseIdx].input; - if (params instanceof Array) { - params[paramIdx].copyTo(inputData, offset); - } else { - params.copyTo(inputData, offset); - } - offset += valueStride(parameterTypes[paramIdx]); + for (let caseIdx = 0; caseIdx < cases.length; caseIdx++) { + const offset = caseIdx * caseStride; + structLayout(parameterTypes, inputSource, m => { + const arg = cases[caseIdx].input; + if (arg instanceof Array) { + arg[m.index].copyTo(inputData, offset + m.offset); + } else { + arg.copyTo(inputData, offset + m.offset); } - } + }); } // build the compute pipeline, if the shader hasn't been compiled already. @@ -1213,22 +1226,22 @@ function packScalarsToVector( } const packedCases: Array = []; - const packedParameterTypes = parameterTypes.map(p => TypeVec(vectorWidth, p as ScalarType)); - const packedResultType = new VectorType(vectorWidth, resultType); + const packedParameterTypes = parameterTypes.map(p => Type.vec(vectorWidth, p as ScalarType)); + const packedResultType = Type.vec(vectorWidth, resultType); const clampCaseIdx = (idx: number) => Math.min(idx, cases.length - 1); let caseIdx = 0; while (caseIdx < cases.length) { // Construct the vectorized inputs from the scalar cases - const packedInputs = new Array(parameterTypes.length); + const packedInputs = new Array(parameterTypes.length); for (let paramIdx = 0; paramIdx < parameterTypes.length; paramIdx++) { - const inputElements = new Array(vectorWidth); + const inputElements = new Array(vectorWidth); for (let i = 0; i < vectorWidth; i++) { const input = cases[clampCaseIdx(caseIdx + i)].input; - inputElements[i] = (input instanceof Array ? input[paramIdx] : input) as Scalar; + inputElements[i] = (input instanceof Array ? input[paramIdx] : input) as ScalarValue; } - packedInputs[paramIdx] = new Vector(inputElements); + packedInputs[paramIdx] = new VectorValue(inputElements); } // Gather the comparators for the packed cases @@ -1242,7 +1255,7 @@ function packScalarsToVector( const gElements = new Array(vectorWidth); const eElements = new Array(vectorWidth); for (let i = 0; i < vectorWidth; i++) { - const d = cmp_impls[i]((got as Vector).elements[i]); + const d = cmp_impls[i]((got as VectorValue).elements[i]); matched = matched && d.matched; gElements[i] = d.got; eElements[i] = d.expected; diff --git a/src/webgpu/shader/execution/expression/unary/af_arithmetic.spec.ts b/src/webgpu/shader/execution/expression/unary/af_arithmetic.spec.ts index 005ddc6448ea..686d4b7c4ac2 100644 --- a/src/webgpu/shader/execution/expression/unary/af_arithmetic.spec.ts +++ b/src/webgpu/shader/execution/expression/unary/af_arithmetic.spec.ts @@ -1,10 +1,10 @@ export const description = ` -Execution Tests for AbstractFloat arithmetic unary expression operations +Execution Tests for Type.abstractFloat arithmetic unary expression operations `; import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeAbstractFloat } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { onlyConstInputSource, run } from '../expression.js'; import { d } from './af_arithmetic.cache.js'; @@ -30,8 +30,8 @@ Accuracy: Correctly rounded await run( t, abstractFloatUnary('-'), - [TypeAbstractFloat], - TypeAbstractFloat, + [Type.abstractFloat], + Type.abstractFloat, t.params, cases, 1 diff --git a/src/webgpu/shader/execution/expression/unary/af_assignment.spec.ts b/src/webgpu/shader/execution/expression/unary/af_assignment.spec.ts index 76e96fe80354..001c47e117bd 100644 --- a/src/webgpu/shader/execution/expression/unary/af_assignment.spec.ts +++ b/src/webgpu/shader/execution/expression/unary/af_assignment.spec.ts @@ -4,7 +4,7 @@ Execution Tests for assignment of AbstractFloats import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeAbstractFloat, TypeF16, TypeF32 } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { ShaderBuilder, abstractFloatShaderBuilder, @@ -35,7 +35,15 @@ testing that extracting abstract floats works .params(u => u.combine('inputSource', onlyConstInputSource)) .fn(async t => { const cases = await d.get('abstract'); - await run(t, abstract_assignment(), [TypeAbstractFloat], TypeAbstractFloat, t.params, cases, 1); + await run( + t, + abstract_assignment(), + [Type.abstractFloat], + Type.abstractFloat, + t.params, + cases, + 1 + ); }); g.test('f32') @@ -48,7 +56,7 @@ concretizing to f32 .params(u => u.combine('inputSource', onlyConstInputSource)) .fn(async t => { const cases = await d.get('f32'); - await run(t, concrete_assignment(), [TypeAbstractFloat], TypeF32, t.params, cases); + await run(t, concrete_assignment(), [Type.abstractFloat], Type.f32, t.params, cases); }); g.test('f16') @@ -64,5 +72,5 @@ concretizing to f16 .params(u => u.combine('inputSource', onlyConstInputSource)) .fn(async t => { const cases = await d.get('f16'); - await run(t, concrete_assignment(), [TypeAbstractFloat], TypeF16, t.params, cases); + await run(t, concrete_assignment(), [Type.abstractFloat], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/unary/ai_arithmetic.spec.ts b/src/webgpu/shader/execution/expression/unary/ai_arithmetic.spec.ts index bc50be4a7b62..625a38b2d5af 100644 --- a/src/webgpu/shader/execution/expression/unary/ai_arithmetic.spec.ts +++ b/src/webgpu/shader/execution/expression/unary/ai_arithmetic.spec.ts @@ -4,7 +4,7 @@ Execution Tests for the abstract integer arithmetic unary expression operations import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeAbstractInt } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { onlyConstInputSource, run } from '../expression.js'; import { d } from './ai_arithmetic.cache.js'; @@ -26,5 +26,5 @@ Expression: -x ) .fn(async t => { const cases = await d.get('negation'); - await run(t, abstractIntUnary('-'), [TypeAbstractInt], TypeAbstractInt, t.params, cases); + await run(t, abstractIntUnary('-'), [Type.abstractInt], Type.abstractInt, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/unary/ai_assignment.spec.ts b/src/webgpu/shader/execution/expression/unary/ai_assignment.spec.ts index f7915df97adc..fe1ba2d9fc12 100644 --- a/src/webgpu/shader/execution/expression/unary/ai_assignment.spec.ts +++ b/src/webgpu/shader/execution/expression/unary/ai_assignment.spec.ts @@ -4,7 +4,7 @@ Execution Tests for assignment of AbstractInts import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeAbstractInt, TypeI32, TypeU32 } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { ShaderBuilder, abstractIntShaderBuilder, @@ -35,7 +35,7 @@ testing that extracting abstract ints works .params(u => u.combine('inputSource', onlyConstInputSource)) .fn(async t => { const cases = await d.get('abstract'); - await run(t, abstract_assignment(), [TypeAbstractInt], TypeAbstractInt, t.params, cases, 1); + await run(t, abstract_assignment(), [Type.abstractInt], Type.abstractInt, t.params, cases, 1); }); g.test('i32') @@ -48,7 +48,7 @@ concretizing to i32 .params(u => u.combine('inputSource', onlyConstInputSource)) .fn(async t => { const cases = await d.get('i32'); - await run(t, concrete_assignment(), [TypeAbstractInt], TypeI32, t.params, cases); + await run(t, concrete_assignment(), [Type.abstractInt], Type.i32, t.params, cases); }); g.test('u32') @@ -61,5 +61,5 @@ concretizing to u32 .params(u => u.combine('inputSource', onlyConstInputSource)) .fn(async t => { const cases = await d.get('u32'); - await run(t, concrete_assignment(), [TypeAbstractInt], TypeU32, t.params, cases); + await run(t, concrete_assignment(), [Type.abstractInt], Type.u32, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/unary/ai_complement.spec.ts b/src/webgpu/shader/execution/expression/unary/ai_complement.spec.ts index 919321e207ce..507ae219cb29 100644 --- a/src/webgpu/shader/execution/expression/unary/ai_complement.spec.ts +++ b/src/webgpu/shader/execution/expression/unary/ai_complement.spec.ts @@ -1,10 +1,10 @@ export const description = ` -Execution Tests for the AbstractInt bitwise complement operation +Execution Tests for the Type.abstractInt bitwise complement operation `; import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { abstractInt, TypeAbstractInt } from '../../../../util/conversion.js'; +import { abstractInt, Type } from '../../../../util/conversion.js'; import { fullI64Range } from '../../../../util/math.js'; import { onlyConstInputSource, run } from '../expression.js'; @@ -28,5 +28,5 @@ Expression: ~x const cases = fullI64Range().map(e => { return { input: abstractInt(e), expected: abstractInt(~e) }; }); - await run(t, abstractIntUnary('~'), [TypeAbstractInt], TypeAbstractInt, t.params, cases); + await run(t, abstractIntUnary('~'), [Type.abstractInt], Type.abstractInt, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/unary/bool_conversion.cache.ts b/src/webgpu/shader/execution/expression/unary/bool_conversion.cache.ts index f64ec1cd4180..5b16c49c421b 100644 --- a/src/webgpu/shader/execution/expression/unary/bool_conversion.cache.ts +++ b/src/webgpu/shader/execution/expression/unary/bool_conversion.cache.ts @@ -1,5 +1,5 @@ import { anyOf } from '../../../../util/compare.js'; -import { Scalar, bool, f16, f32, i32, u32 } from '../../../../util/conversion.js'; +import { ScalarValue, bool, f16, f32, i32, u32 } from '../../../../util/conversion.js'; import { fullI32Range, fullU32Range, @@ -29,7 +29,7 @@ export const d = makeCaseCache('unary/bool_conversion', { }, f32: () => { return scalarF32Range().map(f => { - const expected: Scalar[] = []; + const expected: ScalarValue[] = []; if (f !== 0) { expected.push(bool(true)); } @@ -41,7 +41,7 @@ export const d = makeCaseCache('unary/bool_conversion', { }, f16: () => { return scalarF16Range().map(f => { - const expected: Scalar[] = []; + const expected: ScalarValue[] = []; if (f !== 0) { expected.push(bool(true)); } diff --git a/src/webgpu/shader/execution/expression/unary/bool_conversion.spec.ts b/src/webgpu/shader/execution/expression/unary/bool_conversion.spec.ts index 5f5bb31397a3..55d01d3eda1f 100644 --- a/src/webgpu/shader/execution/expression/unary/bool_conversion.spec.ts +++ b/src/webgpu/shader/execution/expression/unary/bool_conversion.spec.ts @@ -4,7 +4,7 @@ Execution Tests for the boolean conversion operations import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeBool, TypeF16, TypeF32, TypeI32, TypeU32 } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { ShaderBuilder, allInputSources, run } from '../expression.js'; import { d } from './bool_conversion.cache.js'; @@ -31,7 +31,14 @@ Identity operation ) .fn(async t => { const cases = await d.get('bool'); - await run(t, vectorizeToExpression(t.params.vectorize), [TypeBool], TypeBool, t.params, cases); + await run( + t, + vectorizeToExpression(t.params.vectorize), + [Type.bool], + Type.bool, + t.params, + cases + ); }); g.test('u32') @@ -49,7 +56,7 @@ The result is false if e is 0, and true otherwise. ) .fn(async t => { const cases = await d.get('u32'); - await run(t, vectorizeToExpression(t.params.vectorize), [TypeU32], TypeBool, t.params, cases); + await run(t, vectorizeToExpression(t.params.vectorize), [Type.u32], Type.bool, t.params, cases); }); g.test('i32') @@ -67,7 +74,7 @@ The result is false if e is 0, and true otherwise. ) .fn(async t => { const cases = await d.get('i32'); - await run(t, vectorizeToExpression(t.params.vectorize), [TypeI32], TypeBool, t.params, cases); + await run(t, vectorizeToExpression(t.params.vectorize), [Type.i32], Type.bool, t.params, cases); }); g.test('f32') @@ -85,7 +92,7 @@ The result is false if e is 0.0 or -0.0, and true otherwise. ) .fn(async t => { const cases = await d.get('f32'); - await run(t, vectorizeToExpression(t.params.vectorize), [TypeF32], TypeBool, t.params, cases); + await run(t, vectorizeToExpression(t.params.vectorize), [Type.f32], Type.bool, t.params, cases); }); g.test('f16') @@ -106,5 +113,5 @@ The result is false if e is 0.0 or -0.0, and true otherwise. }) .fn(async t => { const cases = await d.get('f16'); - await run(t, vectorizeToExpression(t.params.vectorize), [TypeF16], TypeBool, t.params, cases); + await run(t, vectorizeToExpression(t.params.vectorize), [Type.f16], Type.bool, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/unary/bool_logical.spec.ts b/src/webgpu/shader/execution/expression/unary/bool_logical.spec.ts index 01eaaab43a51..58d4b9fc0fc3 100644 --- a/src/webgpu/shader/execution/expression/unary/bool_logical.spec.ts +++ b/src/webgpu/shader/execution/expression/unary/bool_logical.spec.ts @@ -4,7 +4,7 @@ Execution Tests for the boolean unary logical expression operations import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { bool, TypeBool } from '../../../../util/conversion.js'; +import { bool, Type } from '../../../../util/conversion.js'; import { allInputSources, run } from '../expression.js'; import { unary } from './unary.js'; @@ -29,5 +29,5 @@ Logical negation. The result is true when e is false and false when e is true. C { input: bool(false), expected: bool(true) }, ]; - await run(t, unary('!'), [TypeBool], TypeBool, t.params, cases); + await run(t, unary('!'), [Type.bool], Type.bool, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/unary/f16_arithmetic.spec.ts b/src/webgpu/shader/execution/expression/unary/f16_arithmetic.spec.ts index 60e16e645221..813bbf7a64e6 100644 --- a/src/webgpu/shader/execution/expression/unary/f16_arithmetic.spec.ts +++ b/src/webgpu/shader/execution/expression/unary/f16_arithmetic.spec.ts @@ -4,7 +4,7 @@ Execution Tests for the f16 arithmetic unary expression operations import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeF16 } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { allInputSources, run } from '../expression.js'; import { d } from './f16_arithmetic.cache.js'; @@ -28,5 +28,5 @@ Accuracy: Correctly rounded }) .fn(async t => { const cases = await d.get('negation'); - await run(t, unary('-'), [TypeF16], TypeF16, t.params, cases); + await run(t, unary('-'), [Type.f16], Type.f16, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/unary/f16_conversion.spec.ts b/src/webgpu/shader/execution/expression/unary/f16_conversion.spec.ts index a8da8ff3bd7f..765b36d54cc6 100644 --- a/src/webgpu/shader/execution/expression/unary/f16_conversion.spec.ts +++ b/src/webgpu/shader/execution/expression/unary/f16_conversion.spec.ts @@ -4,14 +4,7 @@ Execution Tests for the f32 conversion operations import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { - TypeBool, - TypeF16, - TypeF32, - TypeI32, - TypeMat, - TypeU32, -} from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { ShaderBuilder, allInputSources, run } from '../expression.js'; import { d } from './f16_conversion.cache.js'; @@ -46,7 +39,7 @@ The result is 1.0 if e is true and 0.0 otherwise }) .fn(async t => { const cases = await d.get('bool'); - await run(t, vectorizeToExpression(t.params.vectorize), [TypeBool], TypeF16, t.params, cases); + await run(t, vectorizeToExpression(t.params.vectorize), [Type.bool], Type.f16, t.params, cases); }); g.test('u32') @@ -66,7 +59,7 @@ Converted to f16, +/-Inf if out of range }) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'u32_const' : 'u32_non_const'); - await run(t, vectorizeToExpression(t.params.vectorize), [TypeU32], TypeF16, t.params, cases); + await run(t, vectorizeToExpression(t.params.vectorize), [Type.u32], Type.f16, t.params, cases); }); g.test('i32') @@ -86,7 +79,7 @@ Converted to f16, +/-Inf if out of range }) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'i32_const' : 'i32_non_const'); - await run(t, vectorizeToExpression(t.params.vectorize), [TypeI32], TypeF16, t.params, cases); + await run(t, vectorizeToExpression(t.params.vectorize), [Type.i32], Type.f16, t.params, cases); }); g.test('f32') @@ -106,7 +99,7 @@ Correctly rounded to f16 }) .fn(async t => { const cases = await d.get(t.params.inputSource === 'const' ? 'f32_const' : 'f32_non_const'); - await run(t, vectorizeToExpression(t.params.vectorize), [TypeF32], TypeF16, t.params, cases); + await run(t, vectorizeToExpression(t.params.vectorize), [Type.f32], Type.f16, t.params, cases); }); g.test('f32_mat') @@ -132,8 +125,8 @@ g.test('f32_mat') await run( t, matrixExperession(cols, rows), - [TypeMat(cols, rows, TypeF32)], - TypeMat(cols, rows, TypeF16), + [Type.mat(cols, rows, Type.f32)], + Type.mat(cols, rows, Type.f16), t.params, cases ); @@ -156,7 +149,7 @@ g.test('f16') }) .fn(async t => { const cases = await d.get('f16'); - await run(t, vectorizeToExpression(t.params.vectorize), [TypeF16], TypeF16, t.params, cases); + await run(t, vectorizeToExpression(t.params.vectorize), [Type.f16], Type.f16, t.params, cases); }); g.test('f16_mat') @@ -182,8 +175,8 @@ g.test('f16_mat') await run( t, matrixExperession(cols, rows), - [TypeMat(cols, rows, TypeF16)], - TypeMat(cols, rows, TypeF16), + [Type.mat(cols, rows, Type.f16)], + Type.mat(cols, rows, Type.f16), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/unary/f32_arithmetic.spec.ts b/src/webgpu/shader/execution/expression/unary/f32_arithmetic.spec.ts index c60e2c3d51b0..3bb48705e854 100644 --- a/src/webgpu/shader/execution/expression/unary/f32_arithmetic.spec.ts +++ b/src/webgpu/shader/execution/expression/unary/f32_arithmetic.spec.ts @@ -4,7 +4,7 @@ Execution Tests for the f32 arithmetic unary expression operations import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeF32 } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { allInputSources, run } from '../expression.js'; import { d } from './f32_arithmetic.cache.js'; @@ -25,5 +25,5 @@ Accuracy: Correctly rounded ) .fn(async t => { const cases = await d.get('negation'); - await run(t, unary('-'), [TypeF32], TypeF32, t.params, cases); + await run(t, unary('-'), [Type.f32], Type.f32, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/unary/f32_conversion.spec.ts b/src/webgpu/shader/execution/expression/unary/f32_conversion.spec.ts index 3e2fbd540ace..464fdee44e79 100644 --- a/src/webgpu/shader/execution/expression/unary/f32_conversion.spec.ts +++ b/src/webgpu/shader/execution/expression/unary/f32_conversion.spec.ts @@ -4,14 +4,7 @@ Execution Tests for the f32 conversion operations import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { - TypeBool, - TypeF16, - TypeF32, - TypeI32, - TypeMat, - TypeU32, -} from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { ShaderBuilder, allInputSources, run } from '../expression.js'; import { d } from './f32_conversion.cache.js'; @@ -43,7 +36,7 @@ The result is 1.0 if e is true and 0.0 otherwise ) .fn(async t => { const cases = await d.get('bool'); - await run(t, vectorizeToExpression(t.params.vectorize), [TypeBool], TypeF32, t.params, cases); + await run(t, vectorizeToExpression(t.params.vectorize), [Type.bool], Type.f32, t.params, cases); }); g.test('u32') @@ -60,7 +53,7 @@ Converted to f32 ) .fn(async t => { const cases = await d.get('u32'); - await run(t, vectorizeToExpression(t.params.vectorize), [TypeU32], TypeF32, t.params, cases); + await run(t, vectorizeToExpression(t.params.vectorize), [Type.u32], Type.f32, t.params, cases); }); g.test('i32') @@ -77,7 +70,7 @@ Converted to f32 ) .fn(async t => { const cases = await d.get('i32'); - await run(t, vectorizeToExpression(t.params.vectorize), [TypeI32], TypeF32, t.params, cases); + await run(t, vectorizeToExpression(t.params.vectorize), [Type.i32], Type.f32, t.params, cases); }); g.test('f32') @@ -94,7 +87,7 @@ Identity operation ) .fn(async t => { const cases = await d.get('f32'); - await run(t, vectorizeToExpression(t.params.vectorize), [TypeF32], TypeF32, t.params, cases); + await run(t, vectorizeToExpression(t.params.vectorize), [Type.f32], Type.f32, t.params, cases); }); g.test('f32_mat') @@ -117,8 +110,8 @@ g.test('f32_mat') await run( t, matrixExperession(cols, rows), - [TypeMat(cols, rows, TypeF32)], - TypeMat(cols, rows, TypeF32), + [Type.mat(cols, rows, Type.f32)], + Type.mat(cols, rows, Type.f32), t.params, cases ); @@ -141,7 +134,7 @@ g.test('f16') }) .fn(async t => { const cases = await d.get('f16'); - await run(t, vectorizeToExpression(t.params.vectorize), [TypeF16], TypeF32, t.params, cases); + await run(t, vectorizeToExpression(t.params.vectorize), [Type.f16], Type.f32, t.params, cases); }); g.test('f16_mat') @@ -167,8 +160,8 @@ g.test('f16_mat') await run( t, matrixExperession(cols, rows), - [TypeMat(cols, rows, TypeF16)], - TypeMat(cols, rows, TypeF32), + [Type.mat(cols, rows, Type.f16)], + Type.mat(cols, rows, Type.f32), t.params, cases ); diff --git a/src/webgpu/shader/execution/expression/unary/i32_arithmetic.spec.ts b/src/webgpu/shader/execution/expression/unary/i32_arithmetic.spec.ts index a6fe77ada165..a7d16a96cd88 100644 --- a/src/webgpu/shader/execution/expression/unary/i32_arithmetic.spec.ts +++ b/src/webgpu/shader/execution/expression/unary/i32_arithmetic.spec.ts @@ -4,7 +4,7 @@ Execution Tests for the i32 arithmetic unary expression operations import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeI32 } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { allInputSources, run } from '../expression.js'; import { d } from './i32_arithmetic.cache.js'; @@ -24,5 +24,5 @@ Expression: -x ) .fn(async t => { const cases = await d.get('negation'); - await run(t, unary('-'), [TypeI32], TypeI32, t.params, cases); + await run(t, unary('-'), [Type.i32], Type.i32, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/unary/i32_complement.spec.ts b/src/webgpu/shader/execution/expression/unary/i32_complement.spec.ts index dc0ca8b8d066..01e5728d70d1 100644 --- a/src/webgpu/shader/execution/expression/unary/i32_complement.spec.ts +++ b/src/webgpu/shader/execution/expression/unary/i32_complement.spec.ts @@ -4,7 +4,7 @@ Execution Tests for the i32 bitwise complement operation import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { i32, TypeI32 } from '../../../../util/conversion.js'; +import { i32, Type } from '../../../../util/conversion.js'; import { fullI32Range } from '../../../../util/math.js'; import { allInputSources, run } from '../expression.js'; @@ -26,5 +26,5 @@ Expression: ~x const cases = fullI32Range().map(e => { return { input: i32(e), expected: i32(~e) }; }); - await run(t, unary('~'), [TypeI32], TypeI32, t.params, cases); + await run(t, unary('~'), [Type.i32], Type.i32, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/unary/i32_conversion.spec.ts b/src/webgpu/shader/execution/expression/unary/i32_conversion.spec.ts index 4ad3c4e7424f..606253b59e5c 100644 --- a/src/webgpu/shader/execution/expression/unary/i32_conversion.spec.ts +++ b/src/webgpu/shader/execution/expression/unary/i32_conversion.spec.ts @@ -4,7 +4,7 @@ Execution Tests for the i32 conversion operations import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeBool, TypeF16, TypeF32, TypeI32, TypeU32 } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { ShaderBuilder, allInputSources, run } from '../expression.js'; import { d } from './i32_conversion.cache.js'; @@ -31,7 +31,7 @@ The result is 1u if e is true and 0u otherwise ) .fn(async t => { const cases = await d.get('bool'); - await run(t, vectorizeToExpression(t.params.vectorize), [TypeBool], TypeI32, t.params, cases); + await run(t, vectorizeToExpression(t.params.vectorize), [Type.bool], Type.i32, t.params, cases); }); g.test('u32') @@ -48,7 +48,7 @@ Reinterpretation of bits ) .fn(async t => { const cases = await d.get('u32'); - await run(t, vectorizeToExpression(t.params.vectorize), [TypeU32], TypeI32, t.params, cases); + await run(t, vectorizeToExpression(t.params.vectorize), [Type.u32], Type.i32, t.params, cases); }); g.test('i32') @@ -65,7 +65,7 @@ Identity operation ) .fn(async t => { const cases = await d.get('i32'); - await run(t, vectorizeToExpression(t.params.vectorize), [TypeI32], TypeI32, t.params, cases); + await run(t, vectorizeToExpression(t.params.vectorize), [Type.i32], Type.i32, t.params, cases); }); g.test('f32') @@ -82,7 +82,7 @@ e is converted to i32, rounding towards zero ) .fn(async t => { const cases = await d.get('f32'); - await run(t, vectorizeToExpression(t.params.vectorize), [TypeF32], TypeI32, t.params, cases); + await run(t, vectorizeToExpression(t.params.vectorize), [Type.f32], Type.i32, t.params, cases); }); g.test('f16') @@ -102,5 +102,5 @@ e is converted to u32, rounding towards zero }) .fn(async t => { const cases = await d.get('f16'); - await run(t, vectorizeToExpression(t.params.vectorize), [TypeF16], TypeI32, t.params, cases); + await run(t, vectorizeToExpression(t.params.vectorize), [Type.f16], Type.i32, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/unary/u32_complement.spec.ts b/src/webgpu/shader/execution/expression/unary/u32_complement.spec.ts index 6052ac008f0e..74251a32c62b 100644 --- a/src/webgpu/shader/execution/expression/unary/u32_complement.spec.ts +++ b/src/webgpu/shader/execution/expression/unary/u32_complement.spec.ts @@ -4,7 +4,7 @@ Execution Tests for the u32 bitwise complement operation import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeU32, u32 } from '../../../../util/conversion.js'; +import { Type, u32 } from '../../../../util/conversion.js'; import { fullU32Range } from '../../../../util/math.js'; import { allInputSources, run } from '../expression.js'; @@ -26,5 +26,5 @@ Expression: ~x const cases = fullU32Range().map(e => { return { input: u32(e), expected: u32(~e) }; }); - await run(t, unary('~'), [TypeU32], TypeU32, t.params, cases); + await run(t, unary('~'), [Type.u32], Type.u32, t.params, cases); }); diff --git a/src/webgpu/shader/execution/expression/unary/u32_conversion.spec.ts b/src/webgpu/shader/execution/expression/unary/u32_conversion.spec.ts index d684824362cf..330f713dca5e 100644 --- a/src/webgpu/shader/execution/expression/unary/u32_conversion.spec.ts +++ b/src/webgpu/shader/execution/expression/unary/u32_conversion.spec.ts @@ -4,7 +4,7 @@ Execution Tests for the u32 conversion operations import { makeTestGroup } from '../../../../../common/framework/test_group.js'; import { GPUTest } from '../../../../gpu_test.js'; -import { TypeBool, TypeF16, TypeF32, TypeI32, TypeU32 } from '../../../../util/conversion.js'; +import { Type } from '../../../../util/conversion.js'; import { ShaderBuilder, allInputSources, run } from '../expression.js'; import { d } from './u32_conversion.cache.js'; @@ -31,7 +31,7 @@ The result is 1u if e is true and 0u otherwise ) .fn(async t => { const cases = await d.get('bool'); - await run(t, vectorizeToExpression(t.params.vectorize), [TypeBool], TypeU32, t.params, cases); + await run(t, vectorizeToExpression(t.params.vectorize), [Type.bool], Type.u32, t.params, cases); }); g.test('u32') @@ -48,7 +48,7 @@ Identity operation ) .fn(async t => { const cases = await d.get('u32'); - await run(t, vectorizeToExpression(t.params.vectorize), [TypeU32], TypeU32, t.params, cases); + await run(t, vectorizeToExpression(t.params.vectorize), [Type.u32], Type.u32, t.params, cases); }); g.test('i32') @@ -65,7 +65,7 @@ Reinterpretation of bits ) .fn(async t => { const cases = await d.get('i32'); - await run(t, vectorizeToExpression(t.params.vectorize), [TypeI32], TypeU32, t.params, cases); + await run(t, vectorizeToExpression(t.params.vectorize), [Type.i32], Type.u32, t.params, cases); }); g.test('f32') @@ -82,7 +82,7 @@ e is converted to u32, rounding towards zero ) .fn(async t => { const cases = await d.get('f32'); - await run(t, vectorizeToExpression(t.params.vectorize), [TypeF32], TypeU32, t.params, cases); + await run(t, vectorizeToExpression(t.params.vectorize), [Type.f32], Type.u32, t.params, cases); }); g.test('f16') @@ -102,14 +102,14 @@ e is converted to u32, rounding towards zero }) .fn(async t => { const cases = await d.get('f16'); - await run(t, vectorizeToExpression(t.params.vectorize), [TypeF16], TypeU32, t.params, cases); + await run(t, vectorizeToExpression(t.params.vectorize), [Type.f16], Type.u32, t.params, cases); }); g.test('abstract_int') .specURL('https://www.w3.org/TR/WGSL/#value-constructor-builtin-function') .desc( ` -u32(e), where e is an AbstractInt +u32(e), where e is an Type.abstractInt Identity operation if the e can be represented in u32, otherwise it produces a shader-creation error ` diff --git a/src/webgpu/shader/validation/expression/binary/and_or_xor.spec.ts b/src/webgpu/shader/validation/expression/binary/and_or_xor.spec.ts new file mode 100644 index 000000000000..ed0ce336c4f0 --- /dev/null +++ b/src/webgpu/shader/validation/expression/binary/and_or_xor.spec.ts @@ -0,0 +1,181 @@ +export const description = ` +Validation tests for logical and bitwise and/or/xor expressions. +`; + +import { makeTestGroup } from '../../../../../common/framework/test_group.js'; +import { keysOf, objectsToRecord } from '../../../../../common/util/data_tables.js'; +import { + kAllScalarsAndVectors, + ScalarType, + scalarTypeOf, + Type, + VectorType, +} from '../../../../util/conversion.js'; +import { ShaderValidationTest } from '../../shader_validation_test.js'; + +export const g = makeTestGroup(ShaderValidationTest); + +// A list of operators and a flag for whether they support boolean values or not. +const kOperators = { + and: { op: '&', supportsBool: true }, + or: { op: '|', supportsBool: true }, + xor: { op: '^', supportsBool: false }, +}; + +// A list of scalar and vector types. +const kScalarAndVectorTypes = objectsToRecord(kAllScalarsAndVectors); + +g.test('scalar_vector') + .desc( + ` + Validates that scalar and vector expressions are only accepted for bool or compatible integer types. + ` + ) + .params(u => + u + .combine('op', keysOf(kOperators)) + .combine('lhs', keysOf(kScalarAndVectorTypes)) + .combine( + 'rhs', + // Skip vec3 and vec4 on the RHS to keep the number of subcases down. + keysOf(kScalarAndVectorTypes).filter( + value => !(value.startsWith('vec3') || value.startsWith('vec4')) + ) + ) + .beginSubcases() + ) + .beforeAllSubcases(t => { + if ( + scalarTypeOf(kScalarAndVectorTypes[t.params.lhs]) === Type.f16 || + scalarTypeOf(kScalarAndVectorTypes[t.params.rhs]) === Type.f16 + ) { + t.selectDeviceOrSkipTestCase('shader-f16'); + } + }) + .fn(t => { + const op = kOperators[t.params.op]; + const lhs = kScalarAndVectorTypes[t.params.lhs]; + const rhs = kScalarAndVectorTypes[t.params.rhs]; + const lhsElement = scalarTypeOf(lhs); + const rhsElement = scalarTypeOf(rhs); + const hasF16 = lhsElement === Type.f16 || rhsElement === Type.f16; + const code = ` +${hasF16 ? 'enable f16;' : ''} +const lhs = ${lhs.create(0).wgsl()}; +const rhs = ${rhs.create(0).wgsl()}; +const foo = lhs ${op.op} rhs; +`; + + // Determine if the element types are compatible. + const kIntegerTypes = [Type.abstractInt, Type.i32, Type.u32]; + let elementIsCompatible = false; + if (lhsElement === Type.abstractInt) { + // Abstract integers are compatible with any other integer type. + elementIsCompatible = kIntegerTypes.includes(rhsElement); + } else if (rhsElement === Type.abstractInt) { + // Abstract integers are compatible with any other numeric type. + elementIsCompatible = kIntegerTypes.includes(lhsElement); + } else if (kIntegerTypes.includes(lhsElement)) { + // Concrete integers are only compatible with values with the exact same type. + elementIsCompatible = lhsElement === rhsElement; + } else if (lhsElement === Type.bool) { + // Booleans are only compatible with other booleans. + elementIsCompatible = rhsElement === Type.bool; + } + + // Determine if the full type is compatible. + let valid = false; + if (lhs instanceof ScalarType && rhs instanceof ScalarType) { + valid = elementIsCompatible; + } else if (lhs instanceof VectorType && rhs instanceof VectorType) { + // Vectors are only compatible with if the vector widths match. + valid = lhs.width === rhs.width && elementIsCompatible; + } + + if (lhsElement === Type.bool) { + valid &&= op.supportsBool; + } + + t.expectCompileResult(valid, code); + }); + +interface InvalidTypeConfig { + // An expression that produces a value of the target type. + expr: string; + // A function that converts an expression of the target type into a valid integer operand. + control: (x: string) => string; +} +const kInvalidTypes: Record = { + mat2x2f: { + expr: 'm', + control: e => `i32(${e}[0][0])`, + }, + + array: { + expr: 'arr', + control: e => `${e}[0]`, + }, + + ptr: { + expr: '(&u)', + control: e => `*${e}`, + }, + + atomic: { + expr: 'a', + control: e => `atomicLoad(&${e})`, + }, + + texture: { + expr: 't', + control: e => `i32(textureLoad(${e}, vec2(), 0).x)`, + }, + + sampler: { + expr: 's', + control: e => `i32(textureSampleLevel(t, ${e}, vec2(), 0).x)`, + }, + + struct: { + expr: 'str', + control: e => `${e}.u`, + }, +}; + +g.test('invalid_types') + .desc( + ` + Validates that expressions are never accepted for non-scalar and non-vector types. + ` + ) + .params(u => + u + .combine('op', keysOf(kOperators)) + .combine('type', keysOf(kInvalidTypes)) + .combine('control', [true, false]) + .beginSubcases() + ) + .fn(t => { + const op = kOperators[t.params.op]; + const type = kInvalidTypes[t.params.type]; + const expr = t.params.control ? type.control(type.expr) : type.expr; + const code = ` +@group(0) @binding(0) var t : texture_2d; +@group(0) @binding(1) var s : sampler; +@group(0) @binding(2) var a : atomic; + +struct S { u : u32 } + +var u : u32; +var m : mat2x2f; +var arr : array; +var str : S; + +@compute @workgroup_size(1) +fn main() { + let foo = ${expr} ${op.op} ${expr}; +} +`; + + t.expectCompileResult(t.params.control, code); + }); diff --git a/src/webgpu/shader/validation/expression/binary/comparison.spec.ts b/src/webgpu/shader/validation/expression/binary/comparison.spec.ts new file mode 100644 index 000000000000..6721460f41a6 --- /dev/null +++ b/src/webgpu/shader/validation/expression/binary/comparison.spec.ts @@ -0,0 +1,186 @@ +export const description = ` +Validation tests for comparison expressions. +`; + +import { makeTestGroup } from '../../../../../common/framework/test_group.js'; +import { keysOf, objectsToRecord } from '../../../../../common/util/data_tables.js'; +import { + isFloatType, + kAllScalarsAndVectors, + ScalarType, + scalarTypeOf, + Type, + VectorType, +} from '../../../../util/conversion.js'; +import { ShaderValidationTest } from '../../shader_validation_test.js'; + +export const g = makeTestGroup(ShaderValidationTest); + +// A list of scalar and vector types. +const kScalarAndVectorTypes = objectsToRecord(kAllScalarsAndVectors); + +// A list of comparison operators and a flag for whether they support boolean values or not. +const kComparisonOperators = { + eq: { op: '==', supportsBool: true }, + ne: { op: '!=', supportsBool: true }, + gt: { op: '>', supportsBool: false }, + ge: { op: '>=', supportsBool: false }, + lt: { op: '<', supportsBool: false }, + le: { op: '<=', supportsBool: false }, +}; + +g.test('scalar_vector') + .desc( + ` + Validates that scalar and vector comparison expressions are only accepted for compatible types. + ` + ) + .params(u => + u + .combine('op', keysOf(kComparisonOperators)) + .combine('lhs', keysOf(kScalarAndVectorTypes)) + .combine( + 'rhs', + // Skip vec3 and vec4 on the RHS to keep the number of subcases down. + keysOf(kScalarAndVectorTypes).filter( + value => !(value.startsWith('vec3') || value.startsWith('vec4')) + ) + ) + .beginSubcases() + ) + .beforeAllSubcases(t => { + if ( + scalarTypeOf(kScalarAndVectorTypes[t.params.lhs]) === Type.f16 || + scalarTypeOf(kScalarAndVectorTypes[t.params.rhs]) === Type.f16 + ) { + t.selectDeviceOrSkipTestCase('shader-f16'); + } + }) + .fn(t => { + const lhs = kScalarAndVectorTypes[t.params.lhs]; + const rhs = kScalarAndVectorTypes[t.params.rhs]; + const lhsElement = scalarTypeOf(lhs); + const rhsElement = scalarTypeOf(rhs); + const hasF16 = lhsElement === Type.f16 || rhsElement === Type.f16; + const code = ` +${hasF16 ? 'enable f16;' : ''} +const lhs = ${lhs.create(0).wgsl()}; +const rhs = ${rhs.create(0).wgsl()}; +const foo = lhs ${kComparisonOperators[t.params.op].op} rhs; +`; + + let valid = false; + + // Determine if the element types are comparable. + let elementIsCompatible = false; + if (lhsElement === Type.abstractInt) { + // Abstract integers are comparable to any other numeric type. + elementIsCompatible = rhsElement !== Type.bool; + } else if (rhsElement === Type.abstractInt) { + // Abstract integers are comparable to any other numeric type. + elementIsCompatible = lhsElement !== Type.bool; + } else if (lhsElement === Type.abstractFloat) { + // Abstract floats are comparable to any other float type. + elementIsCompatible = isFloatType(rhsElement); + } else if (rhsElement === Type.abstractFloat) { + // Abstract floats are comparable to any other float type. + elementIsCompatible = isFloatType(lhsElement); + } else { + // Non-abstract types are only comparable to values with the exact same type. + elementIsCompatible = lhsElement === rhsElement; + } + + // Determine if the full type is comparable. + if (lhs instanceof ScalarType && rhs instanceof ScalarType) { + valid = elementIsCompatible; + } else if (lhs instanceof VectorType && rhs instanceof VectorType) { + // Vectors are only comparable if the vector widths match. + valid = lhs.width === rhs.width && elementIsCompatible; + } + + if (lhsElement === Type.bool) { + valid &&= kComparisonOperators[t.params.op].supportsBool; + } + + t.expectCompileResult(valid, code); + }); + +interface InvalidTypeConfig { + // An expression that produces a value of the target type. + expr: string; + // A function that converts an expression of the target type into a valid comparison operand. + control: (x: string) => string; +} +const kInvalidTypes: Record = { + mat2x2f: { + expr: 'm', + control: e => `${e}[0]`, + }, + + array: { + expr: 'arr', + control: e => `${e}[0]`, + }, + + ptr: { + expr: '(&u)', + control: e => `*${e}`, + }, + + atomic: { + expr: 'a', + control: e => `atomicLoad(&${e})`, + }, + + texture: { + expr: 't', + control: e => `textureLoad(${e}, vec2(), 0)`, + }, + + sampler: { + expr: 's', + control: e => `textureSampleLevel(t, ${e}, vec2(), 0)`, + }, + + struct: { + expr: 'str', + control: e => `${e}.u`, + }, +}; + +g.test('invalid_types') + .desc( + ` + Validates that comparison expressions are never accepted for non-scalar and non-vector types. + ` + ) + .params(u => + u + .combine('op', keysOf(kComparisonOperators)) + .combine('type', keysOf(kInvalidTypes)) + .combine('control', [true, false]) + .beginSubcases() + ) + .fn(t => { + const type = kInvalidTypes[t.params.type]; + const expr = t.params.control ? type.control(type.expr) : type.expr; + const code = ` +@group(0) @binding(0) var t : texture_2d; +@group(0) @binding(1) var s : sampler; +@group(0) @binding(2) var a : atomic; + +struct S { u : u32 } + +var u : u32; +var m : mat2x2f; +var arr : array; +var str : S; + +@compute @workgroup_size(1) +fn main() { + let foo = ${expr} ${kComparisonOperators[t.params.op].op} ${expr}; +} +`; + + t.expectCompileResult(t.params.control, code); + }); diff --git a/src/webgpu/shader/validation/expression/call/builtin/abs.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/abs.spec.ts index 183fa296248f..2b0375d7835f 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/abs.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/abs.spec.ts @@ -5,7 +5,11 @@ Validation tests for the ${builtin}() builtin. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js'; -import { TypeF16, elementType, kAllScalarsAndVectors } from '../../../../../util/conversion.js'; +import { + Type, + kAllNumericScalarsAndVectors, + scalarTypeOf, +} from '../../../../../util/conversion.js'; import { ShaderValidationTest } from '../../../shader_validation_test.js'; import { @@ -17,7 +21,7 @@ import { export const g = makeTestGroup(ShaderValidationTest); -const kValuesTypes = objectsToRecord(kAllScalarsAndVectors); +const kValuesTypes = objectsToRecord(kAllNumericScalarsAndVectors); g.test('values') .desc( @@ -34,7 +38,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() never .expand('value', u => fullRangeForType(kValuesTypes[u.type])) ) .beforeAllSubcases(t => { - if (elementType(kValuesTypes[t.params.type]) === TypeF16) { + if (scalarTypeOf(kValuesTypes[t.params.type]) === Type.f16) { t.selectDeviceOrSkipTestCase('shader-f16'); } }) diff --git a/src/webgpu/shader/validation/expression/call/builtin/acos.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/acos.spec.ts index cabdf6b659d6..9b6438aaec65 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/acos.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/acos.spec.ts @@ -6,11 +6,10 @@ Validation tests for the ${builtin}() builtin. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js'; import { - TypeF16, - TypeF32, - elementType, + Type, kConcreteIntegerScalarsAndVectors, kConvertableToFloatScalarsAndVectors, + scalarTypeOf, } from '../../../../../util/conversion.js'; import { absBigInt } from '../../../../../util/math.js'; import { ShaderValidationTest } from '../../../shader_validation_test.js'; @@ -48,7 +47,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec ) ) .beforeAllSubcases(t => { - if (elementType(kValuesTypes[t.params.type]) === TypeF16) { + if (scalarTypeOf(kValuesTypes[t.params.type]) === Type.f16) { t.selectDeviceOrSkipTestCase('shader-f16'); } }) @@ -67,7 +66,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec }); // f32 is included here to confirm that validation is failing due to a type issue and not something else. -const kIntegerArgumentTypes = objectsToRecord([TypeF32, ...kConcreteIntegerScalarsAndVectors]); +const kIntegerArgumentTypes = objectsToRecord([Type.f32, ...kConcreteIntegerScalarsAndVectors]); g.test('integer_argument') .desc( @@ -81,7 +80,7 @@ Validates that scalar and vector integer arguments are rejected by ${builtin}() validateConstOrOverrideBuiltinEval( t, builtin, - /* expectedResult */ type === TypeF32, + /* expectedResult */ type === Type.f32, [type.create(0)], 'constant' ); diff --git a/src/webgpu/shader/validation/expression/call/builtin/acosh.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/acosh.spec.ts index 3526b45f32ad..c3644befc9ba 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/acosh.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/acosh.spec.ts @@ -6,13 +6,10 @@ Validation tests for the ${builtin}() builtin. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js'; import { - TypeF16, - TypeF32, - elementType, + Type, kConcreteIntegerScalarsAndVectors, - TypeAbstractInt, kConvertableToFloatScalarsAndVectors, - TypeAbstractFloat, + scalarTypeOf, } from '../../../../../util/conversion.js'; import { isRepresentable } from '../../../../../util/floating_point.js'; import { ShaderValidationTest } from '../../../shader_validation_test.js'; @@ -50,7 +47,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec ) ) .beforeAllSubcases(t => { - if (elementType(kValuesTypes[t.params.type]) === TypeF16) { + if (scalarTypeOf(kValuesTypes[t.params.type]) === Type.f16) { t.selectDeviceOrSkipTestCase('shader-f16'); } }) @@ -59,7 +56,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec const expectedResult = isRepresentable( Math.acosh(Number(t.params.value)), // AbstractInt is converted to AbstractFloat before calling into the builtin - elementType(type).kind === 'abstract-int' ? TypeAbstractFloat : elementType(type) + scalarTypeOf(type).kind === 'abstract-int' ? Type.abstractFloat : scalarTypeOf(type) ); validateConstOrOverrideBuiltinEval( t, @@ -84,8 +81,8 @@ Validates that scalar and vector integer arguments are rejected by ${builtin}() validateConstOrOverrideBuiltinEval( t, builtin, - /* expectedResult */ type === TypeF32, - [type.create(type === TypeAbstractInt ? 1n : 1)], + /* expectedResult */ type === Type.f32, + [type.create(type === Type.abstractInt ? 1n : 1)], 'constant' ); }); diff --git a/src/webgpu/shader/validation/expression/call/builtin/asin.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/asin.spec.ts index 3b7cdf8b8668..bff34f104dee 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/asin.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/asin.spec.ts @@ -6,11 +6,10 @@ Validation tests for the ${builtin}() builtin. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js'; import { - TypeF16, - TypeF32, - elementType, + Type, kConcreteIntegerScalarsAndVectors, kConvertableToFloatScalarsAndVectors, + scalarTypeOf, } from '../../../../../util/conversion.js'; import { absBigInt } from '../../../../../util/math.js'; import { ShaderValidationTest } from '../../../shader_validation_test.js'; @@ -48,7 +47,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec ) ) .beforeAllSubcases(t => { - if (elementType(kValuesTypes[t.params.type]) === TypeF16) { + if (scalarTypeOf(kValuesTypes[t.params.type]) === Type.f16) { t.selectDeviceOrSkipTestCase('shader-f16'); } }) @@ -66,7 +65,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec ); }); -const kIntegerArgumentTypes = objectsToRecord([TypeF32, ...kConcreteIntegerScalarsAndVectors]); +const kIntegerArgumentTypes = objectsToRecord([Type.f32, ...kConcreteIntegerScalarsAndVectors]); g.test('integer_argument') .desc( @@ -80,7 +79,7 @@ Validates that scalar and vector integer arguments are rejected by ${builtin}() validateConstOrOverrideBuiltinEval( t, builtin, - /* expectedResult */ type === TypeF32, + /* expectedResult */ type === Type.f32, [type.create(0)], 'constant' ); diff --git a/src/webgpu/shader/validation/expression/call/builtin/asinh.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/asinh.spec.ts index c205ea2d6ecb..cec4b73c6094 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/asinh.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/asinh.spec.ts @@ -6,12 +6,10 @@ Validation tests for the ${builtin}() builtin. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js'; import { - TypeF16, - TypeF32, - elementType, kConcreteIntegerScalarsAndVectors, kConvertableToFloatScalarsAndVectors, - TypeAbstractFloat, + scalarTypeOf, + Type, } from '../../../../../util/conversion.js'; import { isRepresentable } from '../../../../../util/floating_point.js'; import { linearRange, linearRangeBigInt } from '../../../../../util/math.js'; @@ -52,7 +50,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec ) ) .beforeAllSubcases(t => { - if (elementType(kValuesTypes[t.params.type]) === TypeF16) { + if (scalarTypeOf(kValuesTypes[t.params.type]) === Type.f16) { t.selectDeviceOrSkipTestCase('shader-f16'); } }) @@ -61,7 +59,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec const expectedResult = isRepresentable( Math.asinh(Number(t.params.value)), // AbstractInt is converted to AbstractFloat before calling into the builtin - elementType(type).kind === 'abstract-int' ? TypeAbstractFloat : elementType(type) + scalarTypeOf(type).kind === 'abstract-int' ? Type.abstractFloat : scalarTypeOf(type) ); validateConstOrOverrideBuiltinEval( t, @@ -72,7 +70,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec ); }); -const kIntegerArgumentTypes = objectsToRecord([TypeF32, ...kConcreteIntegerScalarsAndVectors]); +const kIntegerArgumentTypes = objectsToRecord([Type.f32, ...kConcreteIntegerScalarsAndVectors]); g.test('integer_argument') .desc( @@ -86,7 +84,7 @@ Validates that scalar and vector integer arguments are rejected by ${builtin}() validateConstOrOverrideBuiltinEval( t, builtin, - /* expectedResult */ type === TypeF32, + /* expectedResult */ type === Type.f32, [type.create(1)], 'constant' ); diff --git a/src/webgpu/shader/validation/expression/call/builtin/atan.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/atan.spec.ts index 3b7dad4c4059..76bafbbcca8a 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/atan.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/atan.spec.ts @@ -6,11 +6,10 @@ Validation tests for the ${builtin}() builtin. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js'; import { - TypeF16, - TypeF32, - elementType, + Type, kConcreteIntegerScalarsAndVectors, kConvertableToFloatScalarsAndVectors, + scalarTypeOf, } from '../../../../../util/conversion.js'; import { ShaderValidationTest } from '../../../shader_validation_test.js'; @@ -47,7 +46,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec ) ) .beforeAllSubcases(t => { - if (elementType(kValuesTypes[t.params.type]) === TypeF16) { + if (scalarTypeOf(kValuesTypes[t.params.type]) === Type.f16) { t.selectDeviceOrSkipTestCase('shader-f16'); } }) @@ -63,7 +62,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec ); }); -const kIntegerArgumentTypes = objectsToRecord([TypeF32, ...kConcreteIntegerScalarsAndVectors]); +const kIntegerArgumentTypes = objectsToRecord([Type.f32, ...kConcreteIntegerScalarsAndVectors]); g.test('integer_argument') .desc( @@ -77,7 +76,7 @@ Validates that scalar and vector integer arguments are rejected by ${builtin}() validateConstOrOverrideBuiltinEval( t, builtin, - /* expectedResult */ type === TypeF32, + /* expectedResult */ type === Type.f32, [type.create(0)], 'constant' ); diff --git a/src/webgpu/shader/validation/expression/call/builtin/atan2.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/atan2.spec.ts index 4c61b331e2ad..1a6776a018fa 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/atan2.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/atan2.spec.ts @@ -6,13 +6,11 @@ Validation tests for the ${builtin}() builtin. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js'; import { - TypeF16, - TypeF32, - Vector, - VectorType, - elementType, + VectorValue, kFloatScalarsAndVectors, kConcreteIntegerScalarsAndVectors, + scalarTypeOf, + Type, } from '../../../../../util/conversion.js'; import { isRepresentable } from '../../../../../util/floating_point.js'; import { ShaderValidationTest } from '../../../shader_validation_test.js'; @@ -56,7 +54,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec ) ) .beforeAllSubcases(t => { - if (elementType(kValuesTypes[t.params.type]) === TypeF16) { + if (scalarTypeOf(kValuesTypes[t.params.type]) === Type.f16) { t.selectDeviceOrSkipTestCase('shader-f16'); } }) @@ -64,7 +62,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec const type = kValuesTypes[t.params.type]; const expectedResult = isRepresentable( Math.abs(Math.atan2(Number(t.params.x), Number(t.params.y))), - elementType(type) + scalarTypeOf(type) ); validateConstOrOverrideBuiltinEval( t, @@ -75,7 +73,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec ); }); -const kIntegerArgumentTypes = objectsToRecord([TypeF32, ...kConcreteIntegerScalarsAndVectors]); +const kIntegerArgumentTypes = objectsToRecord([Type.f32, ...kConcreteIntegerScalarsAndVectors]); g.test('integer_argument_y') .desc( @@ -86,11 +84,11 @@ Validates that scalar and vector integer arguments are rejected by ${builtin}() .params(u => u.combine('type', keysOf(kIntegerArgumentTypes))) .fn(t => { const yTy = kIntegerArgumentTypes[t.params.type]; - const xTy = yTy instanceof Vector ? new VectorType(yTy.size, TypeF32) : TypeF32; + const xTy = yTy instanceof VectorValue ? Type.vec(yTy.size, Type.f32) : Type.f32; validateConstOrOverrideBuiltinEval( t, builtin, - /* expectedResult */ yTy === TypeF32, + /* expectedResult */ yTy === Type.f32, [yTy.create(1), xTy.create(1)], 'constant' ); @@ -105,11 +103,11 @@ Validates that scalar and vector integer arguments are rejected by ${builtin}() .params(u => u.combine('type', keysOf(kIntegerArgumentTypes))) .fn(t => { const xTy = kIntegerArgumentTypes[t.params.type]; - const yTy = xTy instanceof Vector ? new VectorType(xTy.size, TypeF32) : TypeF32; + const yTy = xTy instanceof VectorValue ? Type.vec(xTy.size, Type.f32) : Type.f32; validateConstOrOverrideBuiltinEval( t, builtin, - /* expectedResult */ xTy === TypeF32, + /* expectedResult */ xTy === Type.f32, [yTy.create(1), xTy.create(1)], 'constant' ); diff --git a/src/webgpu/shader/validation/expression/call/builtin/atanh.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/atanh.spec.ts index 1d31ed88db28..1a9184a7416c 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/atanh.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/atanh.spec.ts @@ -6,11 +6,10 @@ Validation tests for the ${builtin}() builtin. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js'; import { - TypeF16, - TypeF32, - elementType, + Type, kConcreteIntegerScalarsAndVectors, kConvertableToFloatScalarsAndVectors, + scalarTypeOf, } from '../../../../../util/conversion.js'; import { absBigInt } from '../../../../../util/math.js'; import { ShaderValidationTest } from '../../../shader_validation_test.js'; @@ -48,7 +47,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec ) ) .beforeAllSubcases(t => { - if (elementType(kValuesTypes[t.params.type]) === TypeF16) { + if (scalarTypeOf(kValuesTypes[t.params.type]) === Type.f16) { t.selectDeviceOrSkipTestCase('shader-f16'); } }) @@ -66,7 +65,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec ); }); -const kIntegerArgumentTypes = objectsToRecord([TypeF32, ...kConcreteIntegerScalarsAndVectors]); +const kIntegerArgumentTypes = objectsToRecord([Type.f32, ...kConcreteIntegerScalarsAndVectors]); g.test('integer_argument') .desc( @@ -80,7 +79,7 @@ Validates that scalar and vector integer arguments are rejected by ${builtin}() validateConstOrOverrideBuiltinEval( t, builtin, - /* expectedResult */ type === TypeF32, + /* expectedResult */ type === Type.f32, [type.create(0)], 'constant' ); diff --git a/src/webgpu/shader/validation/expression/call/builtin/atomics.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/atomics.spec.ts index 57c5aae61334..fdb85664d254 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/atomics.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/atomics.spec.ts @@ -8,18 +8,44 @@ import { ShaderValidationTest } from '../../../shader_validation_test.js'; export const g = makeTestGroup(ShaderValidationTest); -const kAtomicOps = { - add: { src: 'atomicAdd(&a,1)' }, - sub: { src: 'atomicSub(&a,1)' }, - max: { src: 'atomicMax(&a,1)' }, - min: { src: 'atomicMin(&a,1)' }, - and: { src: 'atomicAnd(&a,1)' }, - or: { src: 'atomicOr(&a,1)' }, - xor: { src: 'atomicXor(&a,1)' }, - load: { src: 'atomicLoad(&a)' }, - store: { src: 'atomicStore(&a,1)' }, - exchange: { src: 'atomicExchange(&a,1)' }, - compareexchangeweak: { src: 'atomicCompareExchangeWeak(&a,1,1)' }, +interface stringToString { + (a: string): string; +} + +const kAtomicOps: Record = { + add: (a: string): string => { + return `atomicAdd(${a},1)`; + }, + sub: (a: string): string => { + return `atomicSub(${a},1)`; + }, + max: (a: string): string => { + return `atomicMax(${a},1)`; + }, + min: (a: string): string => { + return `atomicMin(${a},1)`; + }, + and: (a: string): string => { + return `atomicAnd(${a},1)`; + }, + or: (a: string): string => { + return `atomicOr(${a},1)`; + }, + xor: (a: string): string => { + return `atomicXor(${a},1)`; + }, + load: (a: string): string => { + return `atomicLoad(${a})`; + }, + store: (a: string): string => { + return `atomicStore(${a},1)`; + }, + exchange: (a: string): string => { + return `atomicExchange(${a},1)`; + }, + compareexchangeweak: (a: string): string => { + return `atomicCompareExchangeWeak(${a},1,1)`; + }, }; g.test('stage') @@ -35,7 +61,7 @@ Atomic built-in functions must not be used in a vertex shader stage. .combine('atomicOp', keysOf(kAtomicOps)) ) .fn(t => { - const atomicOp = kAtomicOps[t.params.atomicOp].src; + const atomicOp = kAtomicOps[t.params.atomicOp](`&a`); let code = ` @group(0) @binding(0) var a: atomic; `; @@ -68,3 +94,186 @@ Atomic built-in functions must not be used in a vertex shader stage. const pass = t.params.stage !== 'vertex'; t.expectCompileResult(pass, code); }); + +function generateAtomicCode( + type: string, + access: string, + aspace: string, + style: string, + op: string +): string { + let moduleVar = ``; + let functionVar = ``; + let param = ``; + let aParam = ``; + if (style === 'var') { + aParam = `&a`; + switch (aspace) { + case 'storage': + moduleVar = `@group(0) @binding(0) var a : atomic<${type}>;\n`; + break; + case 'workgroup': + moduleVar = `var a : atomic<${type}>;\n`; + break; + case 'uniform': + moduleVar = `@group(0) @binding(0) var a : atomic<${type}>;\n`; + break; + case 'private': + moduleVar = `var a : atomic<${type}>;\n`; + break; + case 'function': + functionVar = `var a : atomic<${type}>;\n`; + break; + default: + break; + } + } else { + const aspaceParam = aspace === 'storage' ? `, ${access}` : ``; + param = `p : ptr<${aspace}, atomic<${type}>${aspaceParam}>`; + aParam = `p`; + } + + return ` +${moduleVar} +fn foo(${param}) { + ${functionVar} + ${kAtomicOps[op](aParam)}; +} +`; +} + +g.test('atomic_parameterization') + .desc('Tests the valid atomic parameters') + .params(u => + u + .combine('op', keysOf(kAtomicOps)) + .beginSubcases() + .combine('aspace', ['storage', 'workgroup', 'private', 'uniform', 'function'] as const) + .combine('access', ['read', 'read_write'] as const) + .combine('type', ['i32', 'u32'] as const) + .combine('style', ['param', 'var'] as const) + .filter(t => { + switch (t.aspace) { + case 'uniform': + return t.style === 'param' && t.access === 'read'; + case 'workgroup': + return t.access === 'read_write'; + case 'function': + case 'private': + return t.style === 'param' && t.access === 'read_write'; + default: + return true; + } + }) + ) + .fn(t => { + if ( + t.params.style === 'param' && + !(t.params.aspace === 'function' || t.params.aspace === 'private') + ) { + t.skipIfLanguageFeatureNotSupported('unrestricted_pointer_parameters'); + } + + const aspaceOK = t.params.aspace === 'storage' || t.params.aspace === 'workgroup'; + const accessOK = t.params.access === 'read_write'; + t.expectCompileResult( + aspaceOK && accessOK, + generateAtomicCode( + t.params.type, + t.params.access, + t.params.aspace, + t.params.style, + t.params.op + ) + ); + }); + +g.test('data_parameters') + .desc('Validates that data parameters must match atomic type (or be implicitly convertible)') + .params(u => + u + .combine('op', [ + 'atomicStore', + 'atomicAdd', + 'atomicSub', + 'atomicMax', + 'atomicMin', + 'atomicAnd', + 'atomicOr', + 'atomicXor', + 'atomicExchange', + 'atomicCompareExchangeWeak1', + 'atomicCompareExchangeWeak2', + ] as const) + .beginSubcases() + .combine('atomicType', ['i32', 'u32'] as const) + .combine('dataType', ['i32', 'u32', 'f32', 'AbstractInt'] as const) + ) + .fn(t => { + let dataValue = ''; + switch (t.params.dataType) { + case 'i32': + dataValue = '1i'; + break; + case 'u32': + dataValue = '1u'; + break; + case 'f32': + dataValue = '1f'; + break; + case 'AbstractInt': + dataValue = '1'; + break; + } + let op = ''; + switch (t.params.op) { + case 'atomicCompareExchangeWeak1': + op = `atomicCompareExchangeWeak(&a, ${dataValue}, 1)`; + break; + case 'atomicCompareExchangeWeak2': + op = `atomicCompareExchangeWeak(&a, 1, ${dataValue})`; + break; + default: + op = `${t.params.op}(&a, ${dataValue})`; + break; + } + const code = ` +var a : atomic<${t.params.atomicType}>; +fn foo() { + ${op}; +} +`; + + const expect = t.params.atomicType === t.params.dataType || t.params.dataType === 'AbstractInt'; + t.expectCompileResult(expect, code); + }); + +g.test('return_types') + .desc('Validates return types of atomics') + .params(u => + u + .combine('op', keysOf(kAtomicOps)) + .beginSubcases() + .combine('atomicType', ['i32', 'u32'] as const) + .combine('returnType', ['i32', 'u32', 'f32'] as const) + ) + .fn(t => { + let op = `${kAtomicOps[t.params.op]('&a')}`; + switch (t.params.op) { + case 'compareexchangeweak': + op = `let tmp : ${t.params.returnType} = ${op}.old_value`; + break; + default: + op = `let tmp : ${t.params.returnType} = ${op}`; + break; + } + const code = ` +var a : atomic<${t.params.atomicType}>; +fn foo() { + ${op}; +} +`; + + const expect = t.params.atomicType === t.params.returnType && t.params.op !== 'store'; + t.expectCompileResult(expect, code); + }); diff --git a/src/webgpu/shader/validation/expression/call/builtin/ceil.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/ceil.spec.ts index 09018d12a3a1..951958d02c12 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/ceil.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/ceil.spec.ts @@ -6,11 +6,10 @@ Validation tests for the ${builtin}() builtin. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js'; import { - TypeF16, - TypeF32, - elementType, + Type, kConcreteIntegerScalarsAndVectors, kConvertableToFloatScalarsAndVectors, + scalarTypeOf, } from '../../../../../util/conversion.js'; import { ShaderValidationTest } from '../../../shader_validation_test.js'; @@ -40,7 +39,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() never .expand('value', u => fullRangeForType(kValuesTypes[u.type])) ) .beforeAllSubcases(t => { - if (elementType(kValuesTypes[t.params.type]) === TypeF16) { + if (scalarTypeOf(kValuesTypes[t.params.type]) === Type.f16) { t.selectDeviceOrSkipTestCase('shader-f16'); } }) @@ -55,7 +54,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() never ); }); -const kIntegerArgumentTypes = objectsToRecord([TypeF32, ...kConcreteIntegerScalarsAndVectors]); +const kIntegerArgumentTypes = objectsToRecord([Type.f32, ...kConcreteIntegerScalarsAndVectors]); g.test('integer_argument') .desc( @@ -69,7 +68,7 @@ Validates that scalar and vector integer arguments are rejected by ${builtin}() validateConstOrOverrideBuiltinEval( t, builtin, - /* expectedResult */ type === TypeF32, + /* expectedResult */ type === Type.f32, [type.create(0)], 'constant' ); diff --git a/src/webgpu/shader/validation/expression/call/builtin/clamp.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/clamp.spec.ts index 6342189ad643..9a23328d650f 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/clamp.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/clamp.spec.ts @@ -6,10 +6,10 @@ Validation tests for the ${builtin}() builtin. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js'; import { - TypeF16, - elementType, + Type, kFloatScalarsAndVectors, kConcreteIntegerScalarsAndVectors, + scalarTypeOf, } from '../../../../../util/conversion.js'; import { ShaderValidationTest } from '../../../shader_validation_test.js'; @@ -44,7 +44,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec .expand('high', u => fullRangeForType(kValuesTypes[u.type], 4)) ) .beforeAllSubcases(t => { - if (elementType(kValuesTypes[t.params.type]) === TypeF16) { + if (scalarTypeOf(kValuesTypes[t.params.type]) === Type.f16) { t.selectDeviceOrSkipTestCase('shader-f16'); } }) diff --git a/src/webgpu/shader/validation/expression/call/builtin/const_override_validation.ts b/src/webgpu/shader/validation/expression/call/builtin/const_override_validation.ts index 62924453f13a..6c46bfb0a054 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/const_override_validation.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/const_override_validation.ts @@ -2,11 +2,11 @@ import { assert, unreachable } from '../../../../../../common/util/util.js'; import { kValue } from '../../../../../util/constants.js'; import { Type, - TypeF16, Value, - elementType, - elementsOf, + elementTypeOf, isAbstractType, + scalarElementsOf, + scalarTypeOf, } from '../../../../../util/conversion.js'; import { scalarF16Range, @@ -23,7 +23,7 @@ export function rangeForType( bigint_range: readonly bigint[] ): (type: Type) => readonly (number | bigint)[] { return (type: Type): readonly (number | bigint)[] => { - switch (elementType(type).kind) { + switch (scalarTypeOf(type).kind) { case 'abstract-float': case 'f32': case 'f16': @@ -132,7 +132,7 @@ export type ConstantOrOverrideStage = 'constant' | 'override'; * @returns true if evaluation stage `stage` supports expressions of type @p. */ export function stageSupportsType(stage: ConstantOrOverrideStage, type: Type) { - if (stage === 'override' && isAbstractType(elementType(type)!)) { + if (stage === 'override' && isAbstractType(elementTypeOf(type)!)) { // Abstract numerics are concretized before being used in an override expression. return false; } @@ -155,8 +155,8 @@ export function validateConstOrOverrideBuiltinEval( args: Value[], stage: ConstantOrOverrideStage ) { - const elTys = args.map(arg => elementType(arg.type)!); - const enables = elTys.some(ty => ty === TypeF16) ? 'enable f16;' : ''; + const elTys = args.map(arg => elementTypeOf(arg.type)!); + const enables = elTys.some(ty => ty === Type.f16) ? 'enable f16;' : ''; switch (stage) { case 'constant': { @@ -175,7 +175,7 @@ const v = ${builtin}(${args.map(arg => arg.wgsl()).join(', ')});` let numOverrides = 0; for (const arg of args) { const argOverrides: string[] = []; - for (const el of elementsOf(arg)) { + for (const el of scalarElementsOf(arg)) { const name = `o${numOverrides++}`; overrideDecls.push(`override ${name} : ${el.type};`); argOverrides.push(name); @@ -201,7 +201,7 @@ export function fullRangeForType(type: Type, count?: number): readonly (number | if (count === undefined) { count = 25; } - switch (elementType(type)?.kind) { + switch (scalarTypeOf(type)?.kind) { case 'abstract-float': return scalarF64Range({ pos_sub: Math.ceil((count * 1) / 5), diff --git a/src/webgpu/shader/validation/expression/call/builtin/cos.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/cos.spec.ts index d010cf499276..81d283abb299 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/cos.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/cos.spec.ts @@ -6,11 +6,10 @@ Validation tests for the ${builtin}() builtin. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js'; import { - TypeF16, - TypeF32, - elementType, + Type, kConcreteIntegerScalarsAndVectors, kConvertableToFloatScalarsAndVectors, + scalarTypeOf, } from '../../../../../util/conversion.js'; import { ShaderValidationTest } from '../../../shader_validation_test.js'; @@ -47,7 +46,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec ) ) .beforeAllSubcases(t => { - if (elementType(kValuesTypes[t.params.type]) === TypeF16) { + if (scalarTypeOf(kValuesTypes[t.params.type]) === Type.f16) { t.selectDeviceOrSkipTestCase('shader-f16'); } }) @@ -61,7 +60,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec ); }); -const kIntegerArgumentTypes = objectsToRecord([TypeF32, ...kConcreteIntegerScalarsAndVectors]); +const kIntegerArgumentTypes = objectsToRecord([Type.f32, ...kConcreteIntegerScalarsAndVectors]); g.test('integer_argument') .desc( @@ -75,7 +74,7 @@ Validates that scalar and vector integer arguments are rejected by ${builtin}() validateConstOrOverrideBuiltinEval( t, builtin, - /* expectedResult */ type === TypeF32, + /* expectedResult */ type === Type.f32, [type.create(0)], 'constant' ); diff --git a/src/webgpu/shader/validation/expression/call/builtin/cosh.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/cosh.spec.ts index 6a7fcddba232..4178f5760d87 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/cosh.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/cosh.spec.ts @@ -6,12 +6,10 @@ Validation tests for the ${builtin}() builtin. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js'; import { - TypeF16, - TypeF32, - elementType, + Type, kConcreteIntegerScalarsAndVectors, kConvertableToFloatScalarsAndVectors, - TypeAbstractFloat, + scalarTypeOf, } from '../../../../../util/conversion.js'; import { isRepresentable } from '../../../../../util/floating_point.js'; import { ShaderValidationTest } from '../../../shader_validation_test.js'; @@ -42,7 +40,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec .expand('value', u => fullRangeForType(kValuesTypes[u.type])) ) .beforeAllSubcases(t => { - if (elementType(kValuesTypes[t.params.type]) === TypeF16) { + if (scalarTypeOf(kValuesTypes[t.params.type]) === Type.f16) { t.selectDeviceOrSkipTestCase('shader-f16'); } }) @@ -51,7 +49,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec const expectedResult = isRepresentable( Math.cosh(Number(t.params.value)), // AbstractInt is converted to AbstractFloat before calling into the builtin - elementType(type).kind === 'abstract-int' ? TypeAbstractFloat : elementType(type) + scalarTypeOf(type).kind === 'abstract-int' ? Type.abstractFloat : scalarTypeOf(type) ); validateConstOrOverrideBuiltinEval( t, @@ -62,7 +60,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec ); }); -const kIntegerArgumentTypes = objectsToRecord([TypeF32, ...kConcreteIntegerScalarsAndVectors]); +const kIntegerArgumentTypes = objectsToRecord([Type.f32, ...kConcreteIntegerScalarsAndVectors]); g.test('integer_argument') .desc( @@ -76,7 +74,7 @@ Validates that scalar and vector integer arguments are rejected by ${builtin}() validateConstOrOverrideBuiltinEval( t, builtin, - /* expectedResult */ type === TypeF32, + /* expectedResult */ type === Type.f32, [type.create(0)], 'constant' ); diff --git a/src/webgpu/shader/validation/expression/call/builtin/degrees.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/degrees.spec.ts index 2805b97b1597..f1cba6a6aef8 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/degrees.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/degrees.spec.ts @@ -6,12 +6,10 @@ Validation tests for the ${builtin}() builtin. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js'; import { - TypeF16, - TypeF32, - elementType, + Type, kConcreteIntegerScalarsAndVectors, kConvertableToFloatScalarsAndVectors, - TypeAbstractFloat, + scalarTypeOf, } from '../../../../../util/conversion.js'; import { isRepresentable } from '../../../../../util/floating_point.js'; import { ShaderValidationTest } from '../../../shader_validation_test.js'; @@ -42,7 +40,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() input .expand('value', u => fullRangeForType(kValuesTypes[u.type])) ) .beforeAllSubcases(t => { - if (elementType(kValuesTypes[t.params.type]) === TypeF16) { + if (scalarTypeOf(kValuesTypes[t.params.type]) === Type.f16) { t.selectDeviceOrSkipTestCase('shader-f16'); } }) @@ -51,7 +49,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() input const expectedResult = isRepresentable( (Number(t.params.value) * 180) / Math.PI, // AbstractInt is converted to AbstractFloat before calling into the builtin - elementType(type).kind === 'abstract-int' ? TypeAbstractFloat : elementType(type) + scalarTypeOf(type).kind === 'abstract-int' ? Type.abstractFloat : scalarTypeOf(type) ); validateConstOrOverrideBuiltinEval( t, @@ -62,7 +60,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() input ); }); -const kIntegerArgumentTypes = objectsToRecord([TypeF32, ...kConcreteIntegerScalarsAndVectors]); +const kIntegerArgumentTypes = objectsToRecord([Type.f32, ...kConcreteIntegerScalarsAndVectors]); g.test('integer_argument') .desc( @@ -76,7 +74,7 @@ Validates that scalar and vector integer arguments are rejected by ${builtin}() validateConstOrOverrideBuiltinEval( t, builtin, - /* expectedResult */ type === TypeF32, + /* expectedResult */ type === Type.f32, [type.create(1)], 'constant' ); diff --git a/src/webgpu/shader/validation/expression/call/builtin/derivatives.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/derivatives.spec.ts index cf5a707ba7c7..54620ce17904 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/derivatives.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/derivatives.spec.ts @@ -5,12 +5,10 @@ Validation tests for derivative builtins. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js'; import { - TypeF16, - TypeF32, - TypeMat, - elementType, + Type, kConcreteIntegerScalarsAndVectors, kConcreteF16ScalarsAndVectors, + scalarTypeOf, } from '../../../../../util/conversion.js'; import { ShaderValidationTest } from '../../../shader_validation_test.js'; @@ -98,10 +96,10 @@ fn foo() { // The list of invalid argument types to test, with an f32 control case. const kArgumentTypes = objectsToRecord([ - TypeF32, + Type.f32, ...kConcreteIntegerScalarsAndVectors, ...kConcreteF16ScalarsAndVectors, - TypeMat(2, 2, TypeF32), + Type.mat2x2f, ]); g.test('invalid_argument_types') @@ -115,17 +113,17 @@ Derivative builtins only accept f32 scalar and vector types. u.combine('type', keysOf(kArgumentTypes)).combine('call', ['', ...kDerivativeBuiltins]) ) .beforeAllSubcases(t => { - if (elementType(kArgumentTypes[t.params.type]) === TypeF16) { + if (scalarTypeOf(kArgumentTypes[t.params.type]) === Type.f16) { t.selectDeviceOrSkipTestCase('shader-f16'); } }) .fn(t => { const type = kArgumentTypes[t.params.type]; const code = ` -${elementType(kArgumentTypes[t.params.type]) === TypeF16 ? 'enable f16;' : ''} +${scalarTypeOf(kArgumentTypes[t.params.type]) === Type.f16 ? 'enable f16;' : ''} fn foo() { let x: ${type.toString()} = ${t.params.call}(${type.create(1).wgsl()}); }`; - t.expectCompileResult(kArgumentTypes[t.params.type] === TypeF32 || t.params.call === '', code); + t.expectCompileResult(kArgumentTypes[t.params.type] === Type.f32 || t.params.call === '', code); }); diff --git a/src/webgpu/shader/validation/expression/call/builtin/dot4I8Packed.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/dot4I8Packed.spec.ts index 12a73ae0c602..56c5cf5403eb 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/dot4I8Packed.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/dot4I8Packed.spec.ts @@ -19,6 +19,8 @@ const kBadArgs = { '1f32': '(1u,2f)', '1bool': '(1u,true)', '1vec2u': '(1u,vec2u())', + bool_bool: '(false,true)', + bool2_bool2: '(vec2(),vec2(false,true))', }; export const g = makeTestGroup(ShaderValidationTest); diff --git a/src/webgpu/shader/validation/expression/call/builtin/dot4U8Packed.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/dot4U8Packed.spec.ts index 18fb97707da1..1d240af5a81b 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/dot4U8Packed.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/dot4U8Packed.spec.ts @@ -19,6 +19,8 @@ const kBadArgs = { '1f32': '(1u,2f)', '1bool': '(1u,true)', '1vec2u': '(1u,vec2u())', + bool_bool: '(false,true)', + bool2_bool2: '(vec2(),vec2(false,true))', }; export const g = makeTestGroup(ShaderValidationTest); diff --git a/src/webgpu/shader/validation/expression/call/builtin/exp.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/exp.spec.ts index 6168fafb2336..dcbd5b79e51d 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/exp.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/exp.spec.ts @@ -7,12 +7,10 @@ import { makeTestGroup } from '../../../../../../common/framework/test_group.js' import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js'; import { kValue } from '../../../../../util/constants.js'; import { - TypeF16, - TypeF32, - TypeAbstractFloat, - elementType, + Type, kConcreteIntegerScalarsAndVectors, kConvertableToFloatScalarsAndVectors, + scalarTypeOf, } from '../../../../../util/conversion.js'; import { isRepresentable } from '../../../../../util/floating_point.js'; import { ShaderValidationTest } from '../../../shader_validation_test.js'; @@ -72,7 +70,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec .expand('value', u => valueForType(kValuesTypes[u.type])) ) .beforeAllSubcases(t => { - if (elementType(kValuesTypes[t.params.type]) === TypeF16) { + if (scalarTypeOf(kValuesTypes[t.params.type]) === Type.f16) { t.selectDeviceOrSkipTestCase('shader-f16'); } }) @@ -81,7 +79,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec const expectedResult = isRepresentable( Math.exp(Number(t.params.value)), // AbstractInt is converted to AbstractFloat before calling into the builtin - elementType(type).kind === 'abstract-int' ? TypeAbstractFloat : elementType(type) + scalarTypeOf(type).kind === 'abstract-int' ? Type.abstractFloat : scalarTypeOf(type) ); validateConstOrOverrideBuiltinEval( t, @@ -92,7 +90,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec ); }); -const kIntegerArgumentTypes = objectsToRecord([TypeF32, ...kConcreteIntegerScalarsAndVectors]); +const kIntegerArgumentTypes = objectsToRecord([Type.f32, ...kConcreteIntegerScalarsAndVectors]); g.test('integer_argument') .desc( @@ -106,7 +104,7 @@ Validates that scalar and vector integer arguments are rejected by ${builtin}() validateConstOrOverrideBuiltinEval( t, builtin, - /* expectedResult */ type === TypeF32, + /* expectedResult */ type === Type.f32, [type.create(0)], 'constant' ); diff --git a/src/webgpu/shader/validation/expression/call/builtin/exp2.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/exp2.spec.ts index 686cb3f69570..0144abeefb04 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/exp2.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/exp2.spec.ts @@ -7,12 +7,10 @@ import { makeTestGroup } from '../../../../../../common/framework/test_group.js' import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js'; import { kValue } from '../../../../../util/constants.js'; import { - TypeF16, - TypeF32, - TypeAbstractFloat, - elementType, + Type, kConcreteIntegerScalarsAndVectors, kConvertableToFloatScalarsAndVectors, + scalarTypeOf, } from '../../../../../util/conversion.js'; import { isRepresentable } from '../../../../../util/floating_point.js'; import { ShaderValidationTest } from '../../../shader_validation_test.js'; @@ -72,7 +70,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec .expand('value', u => valueForType(kValuesTypes[u.type])) ) .beforeAllSubcases(t => { - if (elementType(kValuesTypes[t.params.type]) === TypeF16) { + if (scalarTypeOf(kValuesTypes[t.params.type]) === Type.f16) { t.selectDeviceOrSkipTestCase('shader-f16'); } }) @@ -81,7 +79,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec const expectedResult = isRepresentable( Math.pow(2, Number(t.params.value)), // AbstractInt is converted to AbstractFloat before calling into the builtin - elementType(type).kind === 'abstract-int' ? TypeAbstractFloat : elementType(type) + scalarTypeOf(type).kind === 'abstract-int' ? Type.abstractFloat : scalarTypeOf(type) ); validateConstOrOverrideBuiltinEval( t, @@ -92,7 +90,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec ); }); -const kIntegerArgumentTypes = objectsToRecord([TypeF32, ...kConcreteIntegerScalarsAndVectors]); +const kIntegerArgumentTypes = objectsToRecord([Type.f32, ...kConcreteIntegerScalarsAndVectors]); g.test('integer_argument') .desc( @@ -106,7 +104,7 @@ Validates that scalar and vector integer arguments are rejected by ${builtin}() validateConstOrOverrideBuiltinEval( t, builtin, - /* expectedResult */ type === TypeF32, + /* expectedResult */ type === Type.f32, [type.create(0)], 'constant' ); diff --git a/src/webgpu/shader/validation/expression/call/builtin/floor.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/floor.spec.ts index 25dd950dc602..b65fafc74466 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/floor.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/floor.spec.ts @@ -6,11 +6,10 @@ Validation tests for the ${builtin}() builtin. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js'; import { - TypeF16, - TypeF32, - elementType, + Type, kConcreteIntegerScalarsAndVectors, kConvertableToFloatScalarsAndVectors, + scalarTypeOf, } from '../../../../../util/conversion.js'; import { ShaderValidationTest } from '../../../shader_validation_test.js'; @@ -40,7 +39,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() never .expand('value', u => fullRangeForType(kValuesTypes[u.type])) ) .beforeAllSubcases(t => { - if (elementType(kValuesTypes[t.params.type]) === TypeF16) { + if (scalarTypeOf(kValuesTypes[t.params.type]) === Type.f16) { t.selectDeviceOrSkipTestCase('shader-f16'); } }) @@ -55,7 +54,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() never ); }); -const kIntegerArgumentTypes = objectsToRecord([TypeF32, ...kConcreteIntegerScalarsAndVectors]); +const kIntegerArgumentTypes = objectsToRecord([Type.f32, ...kConcreteIntegerScalarsAndVectors]); g.test('integer_argument') .desc( @@ -69,7 +68,7 @@ Validates that scalar and vector integer arguments are rejected by ${builtin}() validateConstOrOverrideBuiltinEval( t, builtin, - /* expectedResult */ type === TypeF32, + /* expectedResult */ type === Type.f32, [type.create(0)], 'constant' ); diff --git a/src/webgpu/shader/validation/expression/call/builtin/inverseSqrt.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/inverseSqrt.spec.ts index a192bc098cd9..6310bfe25fee 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/inverseSqrt.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/inverseSqrt.spec.ts @@ -6,12 +6,10 @@ Validation tests for the ${builtin}() builtin. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js'; import { - TypeF16, - TypeF32, - elementType, + Type, kConcreteIntegerScalarsAndVectors, - TypeAbstractFloat, kConvertableToFloatScalarsAndVectors, + scalarTypeOf, } from '../../../../../util/conversion.js'; import { isRepresentable } from '../../../../../util/floating_point.js'; import { ShaderValidationTest } from '../../../shader_validation_test.js'; @@ -49,7 +47,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() input ) ) .beforeAllSubcases(t => { - if (elementType(kValuesTypes[t.params.type]) === TypeF16) { + if (scalarTypeOf(kValuesTypes[t.params.type]) === Type.f16) { t.selectDeviceOrSkipTestCase('shader-f16'); } }) @@ -60,7 +58,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() input isRepresentable( 1 / Math.sqrt(Number(t.params.value)), // AbstractInt is converted to AbstractFloat before calling into the builtin - elementType(type).kind === 'abstract-int' ? TypeAbstractFloat : elementType(type) + scalarTypeOf(type).kind === 'abstract-int' ? Type.abstractFloat : scalarTypeOf(type) ); validateConstOrOverrideBuiltinEval( t, @@ -71,7 +69,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() input ); }); -const kIntegerArgumentTypes = objectsToRecord([TypeF32, ...kConcreteIntegerScalarsAndVectors]); +const kIntegerArgumentTypes = objectsToRecord([Type.f32, ...kConcreteIntegerScalarsAndVectors]); g.test('integer_argument') .desc( @@ -85,7 +83,7 @@ Validates that scalar and vector integer arguments are rejected by ${builtin}() validateConstOrOverrideBuiltinEval( t, builtin, - /* expectedResult */ type === TypeF32, + /* expectedResult */ type === Type.f32, [type.create(1)], 'constant' ); diff --git a/src/webgpu/shader/validation/expression/call/builtin/length.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/length.spec.ts index 3fca4fec2cc8..003ad6811d72 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/length.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/length.spec.ts @@ -7,15 +7,13 @@ import { makeTestGroup } from '../../../../../../common/framework/test_group.js' import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js'; import { ScalarType, - TypeF16, - TypeF32, - elementType, + Type, kConcreteIntegerScalarsAndVectors, kConvertableToFloatScalar, kConvertableToFloatVec2, kConvertableToFloatVec3, kConvertableToFloatVec4, - TypeAbstractFloat, + scalarTypeOf, } from '../../../../../util/conversion.js'; import { isRepresentable } from '../../../../../util/floating_point.js'; import { ShaderValidationTest } from '../../../shader_validation_test.js'; @@ -57,12 +55,12 @@ function calculate( isIntermediateRepresentable: isRepresentable( squareSum, // AbstractInt is converted to AbstractFloat before calling into the builtin - elementType(type).kind === 'abstract-int' ? TypeAbstractFloat : elementType(type) + scalarTypeOf(type).kind === 'abstract-int' ? Type.abstractFloat : scalarTypeOf(type) ), isResultRepresentable: isRepresentable( result, // AbstractInt is converted to AbstractFloat before calling into the builtin - elementType(type).kind === 'abstract-int' ? TypeAbstractFloat : elementType(type) + scalarTypeOf(type).kind === 'abstract-int' ? Type.abstractFloat : scalarTypeOf(type) ), result, }; @@ -86,7 +84,7 @@ the input scalar value always compiles without error .expand('value', u => fullRangeForType(kScalarTypes[u.type])) ) .beforeAllSubcases(t => { - if (elementType(kScalarTypes[t.params.type]) === TypeF16) { + if (scalarTypeOf(kScalarTypes[t.params.type]) === Type.f16) { t.selectDeviceOrSkipTestCase('shader-f16'); } }) @@ -118,11 +116,11 @@ Validates that constant evaluation and override evaluation of ${builtin}() with .beginSubcases() .expand('x', u => fullRangeForType(kVec2Types[u.type], 5)) .expand('y', u => fullRangeForType(kVec2Types[u.type], 5)) - .expand('_result', u => [calculate([u.x, u.y], elementType(kVec2Types[u.type]))]) + .expand('_result', u => [calculate([u.x, u.y], scalarTypeOf(kVec2Types[u.type]))]) .filter(u => u._result.isResultRepresentable === u._result.isIntermediateRepresentable) ) .beforeAllSubcases(t => { - if (elementType(kVec2Types[t.params.type]) === TypeF16) { + if (scalarTypeOf(kVec2Types[t.params.type]) === Type.f16) { t.selectDeviceOrSkipTestCase('shader-f16'); } }) @@ -154,11 +152,11 @@ Validates that constant evaluation and override evaluation of ${builtin}() with .expand('x', u => fullRangeForType(kVec3Types[u.type], 4)) .expand('y', u => fullRangeForType(kVec3Types[u.type], 4)) .expand('z', u => fullRangeForType(kVec3Types[u.type], 4)) - .expand('_result', u => [calculate([u.x, u.y, u.z], elementType(kVec3Types[u.type]))]) + .expand('_result', u => [calculate([u.x, u.y, u.z], scalarTypeOf(kVec3Types[u.type]))]) .filter(u => u._result.isResultRepresentable === u._result.isIntermediateRepresentable) ) .beforeAllSubcases(t => { - if (elementType(kVec3Types[t.params.type]) === TypeF16) { + if (scalarTypeOf(kVec3Types[t.params.type]) === Type.f16) { t.selectDeviceOrSkipTestCase('shader-f16'); } }) @@ -191,11 +189,11 @@ Validates that constant evaluation and override evaluation of ${builtin}() with .expand('y', u => fullRangeForType(kVec4Types[u.type], 3)) .expand('z', u => fullRangeForType(kVec4Types[u.type], 3)) .expand('w', u => fullRangeForType(kVec4Types[u.type], 3)) - .expand('_result', u => [calculate([u.x, u.y, u.z, u.w], elementType(kVec4Types[u.type]))]) + .expand('_result', u => [calculate([u.x, u.y, u.z, u.w], scalarTypeOf(kVec4Types[u.type]))]) .filter(u => u._result.isResultRepresentable === u._result.isIntermediateRepresentable) ) .beforeAllSubcases(t => { - if (elementType(kVec4Types[t.params.type]) === TypeF16) { + if (scalarTypeOf(kVec4Types[t.params.type]) === Type.f16) { t.selectDeviceOrSkipTestCase('shader-f16'); } }) @@ -210,7 +208,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() with ); }); -const kIntegerArgumentTypes = objectsToRecord([TypeF32, ...kConcreteIntegerScalarsAndVectors]); +const kIntegerArgumentTypes = objectsToRecord([Type.f32, ...kConcreteIntegerScalarsAndVectors]); g.test('integer_argument') .desc( @@ -224,7 +222,7 @@ Validates that scalar and vector integer arguments are rejected by ${builtin}() validateConstOrOverrideBuiltinEval( t, builtin, - /* expectedResult */ type === TypeF32, + /* expectedResult */ type === Type.f32, [type.create(1)], 'constant' ); diff --git a/src/webgpu/shader/validation/expression/call/builtin/log.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/log.spec.ts index b4cf923a50ce..6d755304f2ff 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/log.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/log.spec.ts @@ -6,11 +6,10 @@ Validation tests for the ${builtin}() builtin. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js'; import { - TypeF16, - TypeF32, - elementType, + Type, kConcreteIntegerScalarsAndVectors, kConvertableToFloatScalarsAndVectors, + scalarTypeOf, } from '../../../../../util/conversion.js'; import { ShaderValidationTest } from '../../../shader_validation_test.js'; @@ -40,7 +39,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() input .expand('value', u => fullRangeForType(kValuesTypes[u.type])) ) .beforeAllSubcases(t => { - if (elementType(kValuesTypes[t.params.type]) === TypeF16) { + if (scalarTypeOf(kValuesTypes[t.params.type]) === Type.f16) { t.selectDeviceOrSkipTestCase('shader-f16'); } }) @@ -55,7 +54,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() input ); }); -const kIntegerArgumentTypes = objectsToRecord([TypeF32, ...kConcreteIntegerScalarsAndVectors]); +const kIntegerArgumentTypes = objectsToRecord([Type.f32, ...kConcreteIntegerScalarsAndVectors]); g.test('integer_argument') .desc( @@ -69,7 +68,7 @@ Validates that scalar and vector integer arguments are rejected by ${builtin}() validateConstOrOverrideBuiltinEval( t, builtin, - /* expectedResult */ type === TypeF32, + /* expectedResult */ type === Type.f32, [type.create(1)], 'constant' ); diff --git a/src/webgpu/shader/validation/expression/call/builtin/log2.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/log2.spec.ts index 066fb652499b..0dfe64153651 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/log2.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/log2.spec.ts @@ -6,11 +6,10 @@ Validation tests for the ${builtin}() builtin. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js'; import { - TypeF16, - TypeF32, - elementType, + Type, kConcreteIntegerScalarsAndVectors, kConvertableToFloatScalarsAndVectors, + scalarTypeOf, } from '../../../../../util/conversion.js'; import { ShaderValidationTest } from '../../../shader_validation_test.js'; @@ -40,7 +39,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() input .expand('value', u => fullRangeForType(kValuesTypes[u.type])) ) .beforeAllSubcases(t => { - if (elementType(kValuesTypes[t.params.type]) === TypeF16) { + if (scalarTypeOf(kValuesTypes[t.params.type]) === Type.f16) { t.selectDeviceOrSkipTestCase('shader-f16'); } }) @@ -55,7 +54,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() input ); }); -const kIntegerArgumentTypes = objectsToRecord([TypeF32, ...kConcreteIntegerScalarsAndVectors]); +const kIntegerArgumentTypes = objectsToRecord([Type.f32, ...kConcreteIntegerScalarsAndVectors]); g.test('integer_argument') .desc( @@ -69,7 +68,7 @@ Validates that scalar and vector integer arguments are rejected by ${builtin}() validateConstOrOverrideBuiltinEval( t, builtin, - /* expectedResult */ type === TypeF32, + /* expectedResult */ type === Type.f32, [type.create(1)], 'constant' ); diff --git a/src/webgpu/shader/validation/expression/call/builtin/modf.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/modf.spec.ts index 3c32e3e37495..2a90fa878ea6 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/modf.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/modf.spec.ts @@ -6,11 +6,10 @@ Validation tests for the ${builtin}() builtin. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js'; import { - TypeF16, - TypeF32, - elementType, + Type, kConcreteIntegerScalarsAndVectors, kConvertableToFloatScalarsAndVectors, + scalarTypeOf, } from '../../../../../util/conversion.js'; import { ShaderValidationTest } from '../../../shader_validation_test.js'; @@ -40,7 +39,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec .expand('value', u => fullRangeForType(kValuesTypes[u.type])) ) .beforeAllSubcases(t => { - if (elementType(kValuesTypes[t.params.type]) === TypeF16) { + if (scalarTypeOf(kValuesTypes[t.params.type]) === Type.f16) { t.selectDeviceOrSkipTestCase('shader-f16'); } }) @@ -55,7 +54,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec ); }); -const kIntegerArgumentTypes = objectsToRecord([TypeF32, ...kConcreteIntegerScalarsAndVectors]); +const kIntegerArgumentTypes = objectsToRecord([Type.f32, ...kConcreteIntegerScalarsAndVectors]); g.test('integer_argument') .desc( @@ -69,7 +68,7 @@ Validates that scalar and vector integer arguments are rejected by ${builtin}() validateConstOrOverrideBuiltinEval( t, builtin, - /* expectedResult */ type === TypeF32, + /* expectedResult */ type === Type.f32, [type.create(0)], 'constant' ); diff --git a/src/webgpu/shader/validation/expression/call/builtin/radians.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/radians.spec.ts index 320bde062098..8689bc3dbbe8 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/radians.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/radians.spec.ts @@ -6,11 +6,10 @@ Validation tests for the ${builtin}() builtin. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js'; import { - TypeF16, - TypeF32, - elementType, + Type, kConcreteIntegerScalarsAndVectors, kConvertableToFloatScalarsAndVectors, + scalarTypeOf, } from '../../../../../util/conversion.js'; import { ShaderValidationTest } from '../../../shader_validation_test.js'; @@ -40,7 +39,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() input .expand('value', u => fullRangeForType(kValuesTypes[u.type])) ) .beforeAllSubcases(t => { - if (elementType(kValuesTypes[t.params.type]) === TypeF16) { + if (scalarTypeOf(kValuesTypes[t.params.type]) === Type.f16) { t.selectDeviceOrSkipTestCase('shader-f16'); } }) @@ -55,7 +54,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() input ); }); -const kIntegerArgumentTypes = objectsToRecord([TypeF32, ...kConcreteIntegerScalarsAndVectors]); +const kIntegerArgumentTypes = objectsToRecord([Type.f32, ...kConcreteIntegerScalarsAndVectors]); g.test('integer_argument') .desc( @@ -69,7 +68,7 @@ Validates that scalar and vector integer arguments are rejected by ${builtin}() validateConstOrOverrideBuiltinEval( t, builtin, - /* expectedResult */ type === TypeF32, + /* expectedResult */ type === Type.f32, [type.create(1)], 'constant' ); diff --git a/src/webgpu/shader/validation/expression/call/builtin/round.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/round.spec.ts index 654729cadb4e..dae7482c18ce 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/round.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/round.spec.ts @@ -6,11 +6,10 @@ Validation tests for the ${builtin}() builtin. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js'; import { - TypeF16, - TypeF32, - elementType, + Type, kConcreteIntegerScalarsAndVectors, kConvertableToFloatScalarsAndVectors, + scalarTypeOf, } from '../../../../../util/conversion.js'; import { fpTraitsFor } from '../../../../../util/floating_point.js'; import { ShaderValidationTest } from '../../../shader_validation_test.js'; @@ -40,10 +39,10 @@ Validates that constant evaluation and override evaluation of ${builtin}() input .filter(u => stageSupportsType(u.stage, kValuesTypes[u.type])) .beginSubcases() .expand('value', u => { - if (elementType(kValuesTypes[u.type]).kind === 'abstract-int') { + if (scalarTypeOf(kValuesTypes[u.type]).kind === 'abstract-int') { return fullRangeForType(kValuesTypes[u.type]); } else { - const constants = fpTraitsFor(elementType(kValuesTypes[u.type])).constants(); + const constants = fpTraitsFor(scalarTypeOf(kValuesTypes[u.type])).constants(); return unique(fullRangeForType(kValuesTypes[u.type]), [ constants.negative.min + 0.1, constants.positive.max - 0.1, @@ -52,7 +51,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() input }) ) .beforeAllSubcases(t => { - if (elementType(kValuesTypes[t.params.type]) === TypeF16) { + if (scalarTypeOf(kValuesTypes[t.params.type]) === Type.f16) { t.selectDeviceOrSkipTestCase('shader-f16'); } }) @@ -67,7 +66,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() input ); }); -const kIntegerArgumentTypes = objectsToRecord([TypeF32, ...kConcreteIntegerScalarsAndVectors]); +const kIntegerArgumentTypes = objectsToRecord([Type.f32, ...kConcreteIntegerScalarsAndVectors]); g.test('integer_argument') .desc( @@ -81,7 +80,7 @@ Validates that scalar and vector integer arguments are rejected by ${builtin}() validateConstOrOverrideBuiltinEval( t, builtin, - /* expectedResult */ type === TypeF32, + /* expectedResult */ type === Type.f32, [type.create(1)], 'constant' ); diff --git a/src/webgpu/shader/validation/expression/call/builtin/saturate.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/saturate.spec.ts index 709a006ea8bd..cbd1b3f369ff 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/saturate.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/saturate.spec.ts @@ -6,11 +6,10 @@ Validation tests for the ${builtin}() builtin. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js'; import { - TypeF16, - TypeF32, - elementType, + Type, kConcreteIntegerScalarsAndVectors, kConvertableToFloatScalarsAndVectors, + scalarTypeOf, } from '../../../../../util/conversion.js'; import { ShaderValidationTest } from '../../../shader_validation_test.js'; @@ -40,7 +39,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() input .expand('value', u => fullRangeForType(kValuesTypes[u.type])) ) .beforeAllSubcases(t => { - if (elementType(kValuesTypes[t.params.type]) === TypeF16) { + if (scalarTypeOf(kValuesTypes[t.params.type]) === Type.f16) { t.selectDeviceOrSkipTestCase('shader-f16'); } }) @@ -55,7 +54,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() input ); }); -const kIntegerArgumentTypes = objectsToRecord([TypeF32, ...kConcreteIntegerScalarsAndVectors]); +const kIntegerArgumentTypes = objectsToRecord([Type.f32, ...kConcreteIntegerScalarsAndVectors]); g.test('integer_argument') .desc( @@ -69,7 +68,7 @@ Validates that scalar and vector integer arguments are rejected by ${builtin}() validateConstOrOverrideBuiltinEval( t, builtin, - /* expectedResult */ type === TypeF32, + /* expectedResult */ type === Type.f32, [type.create(1)], 'constant' ); diff --git a/src/webgpu/shader/validation/expression/call/builtin/sign.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/sign.spec.ts index 2a4560576ca5..f8e00ab9486d 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/sign.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/sign.spec.ts @@ -6,12 +6,11 @@ Validation tests for the ${builtin}() builtin. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js'; import { - TypeF16, - TypeF32, - elementType, + Type, kFloatScalarsAndVectors, kConcreteSignedIntegerScalarsAndVectors, kConcreteUnsignedIntegerScalarsAndVectors, + scalarTypeOf, } from '../../../../../util/conversion.js'; import { ShaderValidationTest } from '../../../shader_validation_test.js'; @@ -44,7 +43,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() input .expand('value', u => fullRangeForType(kValuesTypes[u.type])) ) .beforeAllSubcases(t => { - if (elementType(kValuesTypes[t.params.type]) === TypeF16) { + if (scalarTypeOf(kValuesTypes[t.params.type]) === Type.f16) { t.selectDeviceOrSkipTestCase('shader-f16'); } }) @@ -60,7 +59,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() input }); const kUnsignedIntegerArgumentTypes = objectsToRecord([ - TypeF32, + Type.f32, ...kConcreteUnsignedIntegerScalarsAndVectors, ]); @@ -76,7 +75,7 @@ Validates that scalar and vector integer arguments are rejected by ${builtin}() validateConstOrOverrideBuiltinEval( t, builtin, - /* expectedResult */ type === TypeF32, + /* expectedResult */ type === Type.f32, [type.create(1)], 'constant' ); diff --git a/src/webgpu/shader/validation/expression/call/builtin/sin.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/sin.spec.ts index 2cd4ee002a3f..3c807d094c5c 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/sin.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/sin.spec.ts @@ -6,11 +6,10 @@ Validation tests for the ${builtin}() builtin. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js'; import { - TypeF16, - TypeF32, - elementType, + Type, kConcreteIntegerScalarsAndVectors, kConvertableToFloatScalarsAndVectors, + scalarTypeOf, } from '../../../../../util/conversion.js'; import { ShaderValidationTest } from '../../../shader_validation_test.js'; @@ -47,7 +46,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec ) ) .beforeAllSubcases(t => { - if (elementType(kValuesTypes[t.params.type]) === TypeF16) { + if (scalarTypeOf(kValuesTypes[t.params.type]) === Type.f16) { t.selectDeviceOrSkipTestCase('shader-f16'); } }) @@ -61,7 +60,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec ); }); -const kIntegerArgumentTypes = objectsToRecord([TypeF32, ...kConcreteIntegerScalarsAndVectors]); +const kIntegerArgumentTypes = objectsToRecord([Type.f32, ...kConcreteIntegerScalarsAndVectors]); g.test('integer_argument') .desc( @@ -75,7 +74,7 @@ Validates that scalar and vector integer arguments are rejected by ${builtin}() validateConstOrOverrideBuiltinEval( t, builtin, - /* expectedResult */ type === TypeF32, + /* expectedResult */ type === Type.f32, [type.create(0)], 'constant' ); diff --git a/src/webgpu/shader/validation/expression/call/builtin/sinh.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/sinh.spec.ts index 45550d5c088f..1983d0e1a7e4 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/sinh.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/sinh.spec.ts @@ -6,12 +6,10 @@ Validation tests for the ${builtin}() builtin. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js'; import { - TypeF16, - TypeF32, - elementType, + Type, kConcreteIntegerScalarsAndVectors, kConvertableToFloatScalarsAndVectors, - TypeAbstractFloat, + scalarTypeOf, } from '../../../../../util/conversion.js'; import { isRepresentable } from '../../../../../util/floating_point.js'; import { ShaderValidationTest } from '../../../shader_validation_test.js'; @@ -42,7 +40,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec .expand('value', u => fullRangeForType(kValuesTypes[u.type])) ) .beforeAllSubcases(t => { - if (elementType(kValuesTypes[t.params.type]) === TypeF16) { + if (scalarTypeOf(kValuesTypes[t.params.type]) === Type.f16) { t.selectDeviceOrSkipTestCase('shader-f16'); } }) @@ -51,7 +49,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec const expectedResult = isRepresentable( Math.sinh(Number(t.params.value)), // AbstractInt is converted to AbstractFloat before calling into the builtin - elementType(type).kind === 'abstract-int' ? TypeAbstractFloat : elementType(type) + scalarTypeOf(type).kind === 'abstract-int' ? Type.abstractFloat : scalarTypeOf(type) ); validateConstOrOverrideBuiltinEval( t, @@ -62,7 +60,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec ); }); -const kIntegerArgumentTypes = objectsToRecord([TypeF32, ...kConcreteIntegerScalarsAndVectors]); +const kIntegerArgumentTypes = objectsToRecord([Type.f32, ...kConcreteIntegerScalarsAndVectors]); g.test('integer_argument') .desc( @@ -76,7 +74,7 @@ Validates that scalar and vector integer arguments are rejected by ${builtin}() validateConstOrOverrideBuiltinEval( t, builtin, - /* expectedResult */ type === TypeF32, + /* expectedResult */ type === Type.f32, [type.create(0)], 'constant' ); diff --git a/src/webgpu/shader/validation/expression/call/builtin/sqrt.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/sqrt.spec.ts index 125a9d20de62..7e983adf188c 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/sqrt.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/sqrt.spec.ts @@ -6,12 +6,10 @@ Validation tests for the ${builtin}() builtin. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js'; import { - TypeF16, - TypeF32, - elementType, + Type, kConcreteIntegerScalarsAndVectors, kConvertableToFloatScalarsAndVectors, - TypeAbstractFloat, + scalarTypeOf, } from '../../../../../util/conversion.js'; import { isRepresentable } from '../../../../../util/floating_point.js'; import { ShaderValidationTest } from '../../../shader_validation_test.js'; @@ -49,7 +47,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() input ) ) .beforeAllSubcases(t => { - if (elementType(kValuesTypes[t.params.type]) === TypeF16) { + if (scalarTypeOf(kValuesTypes[t.params.type]) === Type.f16) { t.selectDeviceOrSkipTestCase('shader-f16'); } }) @@ -60,7 +58,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() input isRepresentable( Math.sqrt(Number(t.params.value)), // AbstractInt is converted to AbstractFloat before calling into the builtin - elementType(type).kind === 'abstract-int' ? TypeAbstractFloat : elementType(type) + scalarTypeOf(type).kind === 'abstract-int' ? Type.abstractFloat : scalarTypeOf(type) ); validateConstOrOverrideBuiltinEval( t, @@ -71,7 +69,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() input ); }); -const kIntegerArgumentTypes = objectsToRecord([TypeF32, ...kConcreteIntegerScalarsAndVectors]); +const kIntegerArgumentTypes = objectsToRecord([Type.f32, ...kConcreteIntegerScalarsAndVectors]); g.test('integer_argument') .desc( @@ -85,7 +83,7 @@ Validates that scalar and vector integer arguments are rejected by ${builtin}() validateConstOrOverrideBuiltinEval( t, builtin, - /* expectedResult */ type === TypeF32, + /* expectedResult */ type === Type.f32, [type.create(1)], 'constant' ); diff --git a/src/webgpu/shader/validation/expression/call/builtin/tan.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/tan.spec.ts index 38b0b204059c..097c2b374d95 100644 --- a/src/webgpu/shader/validation/expression/call/builtin/tan.spec.ts +++ b/src/webgpu/shader/validation/expression/call/builtin/tan.spec.ts @@ -6,12 +6,10 @@ Validation tests for the ${builtin}() builtin. import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js'; import { - TypeF16, - TypeF32, - elementType, + Type, kConcreteIntegerScalarsAndVectors, - TypeAbstractFloat, kConvertableToFloatScalarsAndVectors, + scalarTypeOf, } from '../../../../../util/conversion.js'; import { fpTraitsFor } from '../../../../../util/floating_point.js'; import { ShaderValidationTest } from '../../../shader_validation_test.js'; @@ -49,7 +47,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec ) ) .beforeAllSubcases(t => { - if (elementType(kValuesTypes[t.params.type]) === TypeF16) { + if (scalarTypeOf(kValuesTypes[t.params.type]) === Type.f16) { t.selectDeviceOrSkipTestCase('shader-f16'); } }) @@ -57,7 +55,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec const type = kValuesTypes[t.params.type]; const fp = fpTraitsFor( // AbstractInt is converted to AbstractFloat before calling into the builtin - elementType(type).kind === 'abstract-int' ? TypeAbstractFloat : elementType(type) + scalarTypeOf(type).kind === 'abstract-int' ? Type.abstractFloat : scalarTypeOf(type) ); const smallestPositive = fp.constants().positive.min; const v = fp.quantize(Number(t.params.value)); @@ -71,7 +69,7 @@ Validates that constant evaluation and override evaluation of ${builtin}() rejec ); }); -const kIntegerArgumentTypes = objectsToRecord([TypeF32, ...kConcreteIntegerScalarsAndVectors]); +const kIntegerArgumentTypes = objectsToRecord([Type.f32, ...kConcreteIntegerScalarsAndVectors]); g.test('integer_argument') .desc( @@ -85,7 +83,7 @@ Validates that scalar and vector integer arguments are rejected by ${builtin}() validateConstOrOverrideBuiltinEval( t, builtin, - /* expectedResult */ type === TypeF32, + /* expectedResult */ type === Type.f32, [type.create(0)], 'constant' ); diff --git a/src/webgpu/shader/validation/expression/call/builtin/textureSample.spec.ts b/src/webgpu/shader/validation/expression/call/builtin/textureSample.spec.ts new file mode 100644 index 000000000000..0d63c059d719 --- /dev/null +++ b/src/webgpu/shader/validation/expression/call/builtin/textureSample.spec.ts @@ -0,0 +1,218 @@ +const builtin = 'textureSample'; +export const description = ` +Validation tests for the ${builtin}() builtin. + +* test textureSample coords parameter must be correct type +* test textureSample array_index parameter must be correct type +* test textureSample coords parameter must be correct type +* test textureSample offset parameter must be correct type +* test textureSample offset parameter must be a const-expression +* test textureSample offset parameter must be between -8 and +7 inclusive +`; + +import { makeTestGroup } from '../../../../../../common/framework/test_group.js'; +import { keysOf, objectsToRecord } from '../../../../../../common/util/data_tables.js'; +import { + Type, + kAllScalarsAndVectors, + isConvertible, + ScalarType, + VectorType, +} from '../../../../../util/conversion.js'; +import { ShaderValidationTest } from '../../../shader_validation_test.js'; + +type TextureSampleArguments = { + coordsArgType: ScalarType | VectorType; + hasArrayIndexArg?: boolean; + offsetArgType?: VectorType; +}; + +const kValidTextureSampleParameterTypes: { [n: string]: TextureSampleArguments } = { + 'texture_1d': { coordsArgType: Type.f32 }, + 'texture_2d': { coordsArgType: Type.vec2f, offsetArgType: Type.vec2i }, + 'texture_2d_array': { + coordsArgType: Type.vec2f, + hasArrayIndexArg: true, + offsetArgType: Type.vec2i, + }, + 'texture_3d': { coordsArgType: Type.vec3f, offsetArgType: Type.vec3i }, + 'texture_cube': { coordsArgType: Type.vec3f }, + 'texture_cube_array': { coordsArgType: Type.vec3f, hasArrayIndexArg: true }, + texture_depth_2d: { coordsArgType: Type.vec2f, offsetArgType: Type.vec2i }, + texture_depth_2d_array: { coordsArgType: Type.vec2f, hasArrayIndexArg: true }, + texture_depth_cube: { coordsArgType: Type.vec3f }, + texture_depth_cube_array: { coordsArgType: Type.vec3f, hasArrayIndexArg: true }, +} as const; + +const kTextureTypes = keysOf(kValidTextureSampleParameterTypes); +const kValuesTypes = objectsToRecord(kAllScalarsAndVectors); + +export const g = makeTestGroup(ShaderValidationTest); + +g.test('coords_argument') + .desc( + ` +Validates that only incorrect coords arguments are rejected by ${builtin} +` + ) + .params(u => + u + .combine('textureType', keysOf(kValidTextureSampleParameterTypes)) + .combine('coordType', keysOf(kValuesTypes)) + .beginSubcases() + .combine('value', [-1, 0, 1] as const) + .expand('offset', ({ textureType }) => { + const offset = kValidTextureSampleParameterTypes[textureType].offsetArgType; + return offset ? [false, true] : [false]; + }) + ) + .fn(t => { + const { textureType, coordType, offset, value } = t.params; + const coordArgType = kValuesTypes[coordType]; + const { + offsetArgType, + coordsArgType: coordsRequiredType, + hasArrayIndexArg, + } = kValidTextureSampleParameterTypes[textureType]; + + const coordWGSL = coordArgType.create(value).wgsl(); + const arrayWGSL = hasArrayIndexArg ? ', 0' : ''; + const offsetWGSL = offset ? `, ${offsetArgType?.create(0).wgsl()}` : ''; + + const code = ` +@group(0) @binding(0) var s: sampler; +@group(0) @binding(1) var t: ${textureType}; +@fragment fn fs() -> @location(0) vec4f { + let v = textureSample(t, s, ${coordWGSL}${arrayWGSL}${offsetWGSL}); + return vec4f(0); +} +`; + const expectSuccess = isConvertible(coordArgType, coordsRequiredType); + t.expectCompileResult(expectSuccess, code); + }); + +g.test('array_index_argument') + .desc( + ` +Validates that only incorrect array_index arguments are rejected by ${builtin} +` + ) + .params(u => + u + .combine('textureType', kTextureTypes) + // filter out types with no array_index + .filter( + ({ textureType }) => !!kValidTextureSampleParameterTypes[textureType].hasArrayIndexArg + ) + .combine('arrayIndexType', keysOf(kValuesTypes)) + .beginSubcases() + .combine('value', [-9, -8, 0, 7, 8]) + ) + .fn(t => { + const { textureType, arrayIndexType, value } = t.params; + const arrayIndexArgType = kValuesTypes[arrayIndexType]; + const args = [arrayIndexArgType.create(value)]; + const { coordsArgType, offsetArgType } = kValidTextureSampleParameterTypes[textureType]; + + const coordWGSL = coordsArgType.create(0).wgsl(); + const arrayWGSL = args.map(arg => arg.wgsl()).join(', '); + const offsetWGSL = offsetArgType ? `, ${offsetArgType.create(0).wgsl()}` : ''; + + const code = ` +@group(0) @binding(0) var s: sampler; +@group(0) @binding(1) var t: ${textureType}; +@fragment fn fs() -> @location(0) vec4f { + let v = textureSample(t, s, ${coordWGSL}, ${arrayWGSL}${offsetWGSL}); + return vec4f(0); +} +`; + const expectSuccess = + isConvertible(arrayIndexArgType, Type.i32) || isConvertible(arrayIndexArgType, Type.u32); + t.expectCompileResult(expectSuccess, code); + }); + +g.test('offset_argument') + .desc( + ` +Validates that only incorrect offset arguments are rejected by ${builtin} +` + ) + .params(u => + u + .combine('textureType', kTextureTypes) + // filter out types with no offset + .filter( + ({ textureType }) => + kValidTextureSampleParameterTypes[textureType].offsetArgType !== undefined + ) + .combine('offsetType', keysOf(kValuesTypes)) + .beginSubcases() + .combine('value', [-9, -8, 0, 7, 8]) + ) + .fn(t => { + const { textureType, offsetType, value } = t.params; + const offsetArgType = kValuesTypes[offsetType]; + const args = [offsetArgType.create(value)]; + const { + coordsArgType, + hasArrayIndexArg, + offsetArgType: offsetRequiredType, + } = kValidTextureSampleParameterTypes[textureType]; + + const coordWGSL = coordsArgType.create(0).wgsl(); + const arrayWGSL = hasArrayIndexArg ? ', 0' : ''; + const offsetWGSL = args.map(arg => arg.wgsl()).join(', '); + + const code = ` +@group(0) @binding(0) var s: sampler; +@group(0) @binding(1) var t: ${textureType}; +@fragment fn fs() -> @location(0) vec4f { + let v = textureSample(t, s, ${coordWGSL}${arrayWGSL}, ${offsetWGSL}); + return vec4f(0); +} +`; + const expectSuccess = + isConvertible(offsetArgType, offsetRequiredType!) && value >= -8 && value <= 7; + t.expectCompileResult(expectSuccess, code); + }); + +g.test('offset_argument,non_const') + .desc( + ` +Validates that only non-const offset arguments are rejected by ${builtin} +` + ) + .params(u => + u + .combine('textureType', kTextureTypes) + .combine('varType', ['c', 'u', 'l']) + // filter out types with no offset + .filter( + ({ textureType }) => + kValidTextureSampleParameterTypes[textureType].offsetArgType !== undefined + ) + ) + .fn(t => { + const { textureType, varType } = t.params; + const { coordsArgType, hasArrayIndexArg, offsetArgType } = + kValidTextureSampleParameterTypes[textureType]; + + const coordWGSL = coordsArgType.create(0).wgsl(); + const arrayWGSL = hasArrayIndexArg ? ', 0' : ''; + const offsetWGSL = `${offsetArgType}(${varType})`; + const castWGSL = offsetArgType!.elementType.toString(); + + const code = ` +@group(0) @binding(0) var s: sampler; +@group(0) @binding(1) var t: ${textureType}; +@group(0) @binding(2) var u: ${offsetArgType}; +@fragment fn fs(@builtin(position) p: vec4f) -> @location(0) vec4f { + const c = 1; + let l = ${offsetArgType}(${castWGSL}(p.x)); + let v = textureSample(t, s, ${coordWGSL}${arrayWGSL}, ${offsetWGSL}); + return vec4f(0); +} +`; + const expectSuccess = varType === 'c'; + t.expectCompileResult(expectSuccess, code); + }); diff --git a/src/webgpu/shader/validation/expression/unary/bitwise_complement.spec.ts b/src/webgpu/shader/validation/expression/unary/bitwise_complement.spec.ts new file mode 100644 index 000000000000..b5b8556b9d51 --- /dev/null +++ b/src/webgpu/shader/validation/expression/unary/bitwise_complement.spec.ts @@ -0,0 +1,114 @@ +export const description = ` +Validation tests for bitwise complement expressions. +`; + +import { makeTestGroup } from '../../../../../common/framework/test_group.js'; +import { keysOf, objectsToRecord } from '../../../../../common/util/data_tables.js'; +import { kAllScalarsAndVectors, scalarTypeOf, Type } from '../../../../util/conversion.js'; +import { ShaderValidationTest } from '../../shader_validation_test.js'; + +export const g = makeTestGroup(ShaderValidationTest); + +// A list of scalar and vector types. +const kScalarAndVectorTypes = objectsToRecord(kAllScalarsAndVectors); + +g.test('scalar_vector') + .desc( + ` + Validates that scalar and vector bitwise complement expressions are only accepted for integers. + ` + ) + .params(u => u.combine('type', keysOf(kScalarAndVectorTypes)).beginSubcases()) + .beforeAllSubcases(t => { + if (scalarTypeOf(kScalarAndVectorTypes[t.params.type]) === Type.f16) { + t.selectDeviceOrSkipTestCase('shader-f16'); + } + }) + .fn(t => { + const type = kScalarAndVectorTypes[t.params.type]; + const elementTy = scalarTypeOf(type); + const hasF16 = elementTy === Type.f16; + const code = ` +${hasF16 ? 'enable f16;' : ''} +const rhs = ${type.create(0).wgsl()}; +const foo = ~rhs; +`; + + t.expectCompileResult([Type.abstractInt, Type.i32, Type.u32].includes(elementTy), code); + }); + +interface InvalidTypeConfig { + // An expression that produces a value of the target type. + expr: string; + // A function that converts an expression of the target type into a valid complement operand. + control: (x: string) => string; +} +const kInvalidTypes: Record = { + mat2x2f: { + expr: 'm', + control: e => `i32(${e}[0][0])`, + }, + + array: { + expr: 'arr', + control: e => `${e}[0]`, + }, + + ptr: { + expr: '(&u)', + control: e => `*${e}`, + }, + + atomic: { + expr: 'a', + control: e => `atomicLoad(&${e})`, + }, + + texture: { + expr: 't', + control: e => `i32(textureLoad(${e}, vec2(), 0).x)`, + }, + + sampler: { + expr: 's', + control: e => `i32(textureSampleLevel(t, ${e}, vec2(), 0).x)`, + }, + + struct: { + expr: 'str', + control: e => `${e}.u`, + }, +}; + +g.test('invalid_types') + .desc( + ` + Validates that bitwise complement expressions are never accepted for non-scalar and non-vector types. + ` + ) + .params(u => + u.combine('type', keysOf(kInvalidTypes)).combine('control', [true, false]).beginSubcases() + ) + .fn(t => { + const type = kInvalidTypes[t.params.type]; + const expr = t.params.control ? type.control(type.expr) : type.expr; + const code = ` +@group(0) @binding(0) var t : texture_2d; +@group(0) @binding(1) var s : sampler; +@group(0) @binding(2) var a : atomic; + +struct S { u : u32 } + +var u : u32; +var m : mat2x2f; +var arr : array; +var str : S; + +@compute @workgroup_size(1) +fn main() { + let foo = ~${expr}; +} +`; + + t.expectCompileResult(t.params.control, code); + }); diff --git a/src/webgpu/shader/validation/expression/unary/logical_negation.spec.ts b/src/webgpu/shader/validation/expression/unary/logical_negation.spec.ts new file mode 100644 index 000000000000..a85516ec3f88 --- /dev/null +++ b/src/webgpu/shader/validation/expression/unary/logical_negation.spec.ts @@ -0,0 +1,114 @@ +export const description = ` +Validation tests for logical negation expressions. +`; + +import { makeTestGroup } from '../../../../../common/framework/test_group.js'; +import { keysOf, objectsToRecord } from '../../../../../common/util/data_tables.js'; +import { kAllScalarsAndVectors, scalarTypeOf, Type } from '../../../../util/conversion.js'; +import { ShaderValidationTest } from '../../shader_validation_test.js'; + +export const g = makeTestGroup(ShaderValidationTest); + +// A list of scalar and vector types. +const kScalarAndVectorTypes = objectsToRecord(kAllScalarsAndVectors); + +g.test('scalar_vector') + .desc( + ` + Validates that scalar and vector logical negation expressions are only accepted for bool types. + ` + ) + .params(u => u.combine('type', keysOf(kScalarAndVectorTypes)).beginSubcases()) + .beforeAllSubcases(t => { + if (scalarTypeOf(kScalarAndVectorTypes[t.params.type]) === Type.f16) { + t.selectDeviceOrSkipTestCase('shader-f16'); + } + }) + .fn(t => { + const type = kScalarAndVectorTypes[t.params.type]; + const elementTy = scalarTypeOf(type); + const hasF16 = elementTy === Type.f16; + const code = ` +${hasF16 ? 'enable f16;' : ''} +const rhs = ${type.create(0).wgsl()}; +const foo = !rhs; +`; + + t.expectCompileResult(elementTy === Type.bool, code); + }); + +interface InvalidTypeConfig { + // An expression that produces a value of the target type. + expr: string; + // A function that converts an expression of the target type into a valid negation operand. + control: (x: string) => string; +} +const kInvalidTypes: Record = { + mat2x2f: { + expr: 'm', + control: e => `bool(${e}[0][0])`, + }, + + array: { + expr: 'arr', + control: e => `${e}[0]`, + }, + + ptr: { + expr: '(&b)', + control: e => `*${e}`, + }, + + atomic: { + expr: 'a', + control: e => `bool(atomicLoad(&${e}))`, + }, + + texture: { + expr: 't', + control: e => `bool(textureLoad(${e}, vec2(), 0).x)`, + }, + + sampler: { + expr: 's', + control: e => `bool(textureSampleLevel(t, ${e}, vec2(), 0).x)`, + }, + + struct: { + expr: 'str', + control: e => `${e}.b`, + }, +}; + +g.test('invalid_types') + .desc( + ` + Validates that logical negation expressions are never accepted for non-scalar and non-vector types. + ` + ) + .params(u => + u.combine('type', keysOf(kInvalidTypes)).combine('control', [true, false]).beginSubcases() + ) + .fn(t => { + const type = kInvalidTypes[t.params.type]; + const expr = t.params.control ? type.control(type.expr) : type.expr; + const code = ` +@group(0) @binding(0) var t : texture_2d; +@group(0) @binding(1) var s : sampler; +@group(0) @binding(2) var a : atomic; + +struct S { b : bool } + +var b : bool; +var m : mat2x2f; +var arr : array; +var str : S; + +@compute @workgroup_size(1) +fn main() { + let foo = !${expr}; +} +`; + + t.expectCompileResult(t.params.control, code); + }); diff --git a/src/webgpu/shader/validation/types/atomics.spec.ts b/src/webgpu/shader/validation/types/atomics.spec.ts new file mode 100644 index 000000000000..36c37176e8af --- /dev/null +++ b/src/webgpu/shader/validation/types/atomics.spec.ts @@ -0,0 +1,145 @@ +export const description = ` +Validation tests for atomic types + +Tests covered: +* Base type +* Address spaces +* Invalid operations (non-exhaustive) + +Note: valid operations (e.g. atomic built-in functions) are tested in the builtin tests. +`; + +import { makeTestGroup } from '../../../../common/framework/test_group.js'; +import { keysOf } from '../../../../common/util/data_tables.js'; +import { ShaderValidationTest } from '../shader_validation_test.js'; + +export const g = makeTestGroup(ShaderValidationTest); + +g.test('type') + .desc('Test of the underlying atomic data type') + .specURL('https://gpuweb.github.io/gpuweb/wgsl/#atomic-types') + .params(u => + u.combine('type', [ + 'u32', + 'i32', + 'f32', + 'f16', + 'bool', + 'vec2u', + 'vec3i', + 'vec4f', + 'mat2x2f', + 'R', + 'S', + 'array', + 'array', + 'array', + 'array', + 'atomic', + 'atomic', + ] as const) + ) + .beforeAllSubcases(t => { + if (t.params.type === 'f16') { + t.selectDeviceOrSkipTestCase('shader-f16'); + } + }) + .fn(t => { + const code = ` +struct S { + x : u32 +} +struct T { + x : i32 +} +struct R { + x : f32 +} + +struct Test { + x : atomic<${t.params.type}> +} +`; + + const expect = t.params.type === 'u32' || t.params.type === 'i32'; + t.expectCompileResult(expect, code); + }); + +g.test('address_space') + .desc('Test allowed address spaces for atomics') + .specURL('https://gpuweb.github.io/gpuweb/wgsl/#atomic-types') + .params(u => + u + .combine('aspace', [ + 'storage', + 'workgroup', + 'storage-ro', + 'uniform', + 'private', + 'function', + 'function-let', + ] as const) + .beginSubcases() + .combine('type', ['i32', 'u32'] as const) + ) + .fn(t => { + let moduleVar = ``; + let functionVar = ''; + switch (t.params.aspace) { + case 'storage-ro': + moduleVar = `@group(0) @binding(0) var x : atomic<${t.params.type}>;\n`; + break; + case 'storage': + moduleVar = `@group(0) @binding(0) var x : atomic<${t.params.type}>;\n`; + break; + case 'uniform': + moduleVar = `@group(0) @binding(0) var x : atomic<${t.params.type}>;\n`; + break; + case 'workgroup': + case 'private': + moduleVar = `var<${t.params.aspace}> x : atomic<${t.params.type}>;\n`; + break; + case 'function': + functionVar = `var x : atomic<${t.params.type}>;\n`; + break; + case 'function-let': + functionVar = `let x : atomic<${t.params.type}>;\n`; + break; + } + const code = ` +${moduleVar} + +fn foo() { + ${functionVar} +} +`; + + const expect = t.params.aspace === 'storage' || t.params.aspace === 'workgroup'; + t.expectCompileResult(expect, code); + }); + +const kInvalidOperations = { + add: `a1 + a2`, + load: `a1`, + store: `a1 = 1u`, + deref: `*a1 = 1u`, + equality: `a1 == a2`, + abs: `abs(a1)`, + address_abs: `abs(&a1)`, +}; + +g.test('invalid_operations') + .desc('Tests that a selection of invalid operations are invalid') + .params(u => u.combine('op', keysOf(kInvalidOperations))) + .fn(t => { + const code = ` +var a1 : atomic; +var a2 : atomic; + +fn foo() { + let x : u32 = ${kInvalidOperations[t.params.op]}; +} +`; + + t.expectCompileResult(false, code); + }); diff --git a/src/webgpu/util/compare.ts b/src/webgpu/util/compare.ts index 95573e6ceae2..7cb71ca8de5a 100644 --- a/src/webgpu/util/compare.ts +++ b/src/webgpu/util/compare.ts @@ -8,7 +8,14 @@ import { import { Expectation, toComparator } from '../shader/execution/expression/expectation.js'; import BinaryStream from './binary_stream.js'; -import { isFloatValue, Matrix, Scalar, Value, Vector } from './conversion.js'; +import { + isFloatValue, + isScalarValue, + MatrixValue, + ScalarValue, + Value, + VectorValue, +} from './conversion.js'; import { FPInterval } from './floating_point.js'; /** Comparison describes the result of a Comparator function. */ @@ -98,9 +105,9 @@ function compareValue(got: Value, expected: Value): Comparison { } } - if (got instanceof Scalar) { + if (isScalarValue(got)) { const g = got; - const e = expected as Scalar; + const e = expected as ScalarValue; const isFloat = g.type.kind === 'f64' || g.type.kind === 'f32' || g.type.kind === 'f16'; const matched = (isFloat && (g.value as number) === (e.value as number)) || (!isFloat && g.value === e.value); @@ -111,8 +118,8 @@ function compareValue(got: Value, expected: Value): Comparison { }; } - if (got instanceof Vector) { - const e = expected as Vector; + if (got instanceof VectorValue) { + const e = expected as VectorValue; const gLen = got.elements.length; const eLen = e.elements.length; let matched = gLen === eLen; @@ -130,8 +137,8 @@ function compareValue(got: Value, expected: Value): Comparison { }; } - if (got instanceof Matrix) { - const e = expected as Matrix; + if (got instanceof MatrixValue) { + const e = expected as MatrixValue; const gCols = got.type.cols; const eCols = e.type.cols; const gRows = got.type.rows; @@ -175,7 +182,7 @@ function compareInterval(got: Value, expected: FPInterval): Comparison { } } - if (got instanceof Scalar) { + if (isScalarValue(got)) { const g = got.value as number; const matched = expected.contains(g); return { @@ -197,7 +204,7 @@ function compareInterval(got: Value, expected: FPInterval): Comparison { */ function compareVector(got: Value, expected: FPInterval[]): Comparison { // Check got type - if (!(got instanceof Vector)) { + if (!(got instanceof VectorValue)) { return { matched: false, got: `${Colors.red((typeof got).toString())}(${got})`, @@ -262,7 +269,7 @@ function convertArrayToString(m: T[]): string { */ function compareMatrix(got: Value, expected: FPInterval[][]): Comparison { // Check got type - if (!(got instanceof Matrix)) { + if (!(got instanceof MatrixValue)) { return { matched: false, got: `${Colors.red((typeof got).toString())}(${got})`, diff --git a/src/webgpu/util/conversion.ts b/src/webgpu/util/conversion.ts index 8599e2335869..4925899811b5 100644 --- a/src/webgpu/util/conversion.ts +++ b/src/webgpu/util/conversion.ts @@ -6,6 +6,7 @@ import { Float16Array } from '../../external/petamoriken/float16/float16.js'; import BinaryStream from './binary_stream.js'; import { kBit } from './constants.js'; import { + align, cartesianProduct, clamp, correctlyRoundedF16, @@ -596,9 +597,13 @@ export type ScalarKind = export class ScalarType { readonly kind: ScalarKind; // The named type readonly _size: number; // In bytes - readonly read: (buf: Uint8Array, offset: number) => Scalar; // reads a scalar from a buffer + readonly read: (buf: Uint8Array, offset: number) => ScalarValue; // reads a scalar from a buffer - constructor(kind: ScalarKind, size: number, read: (buf: Uint8Array, offset: number) => Scalar) { + constructor( + kind: ScalarKind, + size: number, + read: (buf: Uint8Array, offset: number) => ScalarValue + ) { this.kind = kind; this._size = size; this.read = read; @@ -612,13 +617,19 @@ export class ScalarType { return this._size; } - /** Constructs a Scalar of this type with `value` */ - public create(value: number | bigint): Scalar { + public get alignment(): number { + return this._size; + } + + /** Constructs a ScalarValue of this type with `value` */ + public create(value: number | bigint): ScalarValue { switch (typeof value) { case 'number': switch (this.kind) { case 'abstract-float': return abstractFloat(value); + case 'abstract-int': + return abstractInt(BigInt(value)); case 'f64': return f64(value); case 'f32': @@ -659,6 +670,20 @@ export class VectorType { readonly width: number; // Number of elements in the vector readonly elementType: ScalarType; // Element type + // Maps a string representation of a vector type to vector type. + private static instances = new Map(); + + static create(width: number, elementType: ScalarType): VectorType { + const key = `${elementType.toString()} ${width}}`; + let ty = this.instances.get(key); + if (ty !== undefined) { + return ty; + } + ty = new VectorType(width, elementType); + this.instances.set(key, ty); + return ty; + } + constructor(width: number, elementType: ScalarType) { this.width = width; this.elementType = elementType; @@ -668,13 +693,13 @@ export class VectorType { * @returns a vector constructed from the values read from the buffer at the * given byte offset */ - public read(buf: Uint8Array, offset: number): Vector { - const elements: Array = []; + public read(buf: Uint8Array, offset: number): VectorValue { + const elements: Array = []; for (let i = 0; i < this.width; i++) { elements[i] = this.elementType.read(buf, offset); offset += this.elementType.size; } - return new Vector(elements); + return new VectorValue(elements); } public toString(): string { @@ -685,29 +710,23 @@ export class VectorType { return this.elementType.size * this.width; } + public get alignment(): number { + return VectorType.alignmentOf(this.width, this.elementType); + } + + public static alignmentOf(width: number, elementType: ScalarType) { + return elementType.size * (width === 3 ? 4 : width); + } + /** Constructs a Vector of this type with the given values */ - public create(value: (number | bigint) | readonly (number | bigint)[]): Vector { + public create(value: (number | bigint) | readonly (number | bigint)[]): VectorValue { if (value instanceof Array) { assert(value.length === this.width); } else { value = Array(this.width).fill(value); } - return new Vector(value.map(v => this.elementType.create(v))); - } -} - -// Maps a string representation of a vector type to vector type. -const vectorTypes = new Map(); - -export function TypeVec(width: number, elementType: ScalarType): VectorType { - const key = `${elementType.toString()} ${width}}`; - let ty = vectorTypes.get(key); - if (ty !== undefined) { - return ty; + return new VectorValue(value.map(v => this.elementType.create(v))); } - ty = new VectorType(width, elementType); - vectorTypes.set(key, ty); - return ty; } /** MatrixType describes the type of WGSL Matrix. */ @@ -716,6 +735,20 @@ export class MatrixType { readonly rows: number; // Number of elements per column in the Matrix readonly elementType: ScalarType; // Element type + // Maps a string representation of a Matrix type to Matrix type. + private static instances = new Map(); + + static create(cols: number, rows: number, elementType: ScalarType): MatrixType { + const key = `${elementType.toString()} ${cols} ${rows}`; + let ty = this.instances.get(key); + if (ty !== undefined) { + return ty; + } + ty = new MatrixType(cols, rows, elementType); + this.instances.set(key, ty); + return ty; + } + constructor(cols: number, rows: number, elementType: ScalarType) { this.cols = cols; this.rows = rows; @@ -732,8 +765,8 @@ export class MatrixType { * @returns a Matrix constructed from the values read from the buffer at the * given byte offset */ - public read(buf: Uint8Array, offset: number): Matrix { - const elements: Scalar[][] = [...Array(this.cols)].map(_ => [...Array(this.rows)]); + public read(buf: Uint8Array, offset: number): MatrixValue { + const elements: ScalarValue[][] = [...Array(this.cols)].map(_ => [...Array(this.rows)]); for (let c = 0; c < this.cols; c++) { for (let r = 0; r < this.rows; r++) { elements[c][r] = this.elementType.read(buf, offset); @@ -745,15 +778,23 @@ export class MatrixType { offset += this.elementType.size; } } - return new Matrix(elements); + return new MatrixValue(elements); } public toString(): string { return `mat${this.cols}x${this.rows}<${this.elementType}>`; } + public get size(): number { + return VectorType.alignmentOf(this.rows, this.elementType) * this.cols; + } + + public get alignment(): number { + return VectorType.alignmentOf(this.rows, this.elementType); + } + /** Constructs a Matrix of this type with the given values */ - public create(value: (number | bigint) | readonly (number | bigint)[]): Matrix { + public create(value: (number | bigint) | readonly (number | bigint)[]): MatrixValue { if (value instanceof Array) { assert(value.length === this.cols * this.rows); } else { @@ -764,26 +805,64 @@ export class MatrixType { const start = i * this.rows; columns.push(value.slice(start, start + this.rows)); } - return new Matrix(columns.map(c => c.map(v => this.elementType.create(v)))); + return new MatrixValue(columns.map(c => c.map(v => this.elementType.create(v)))); } } -// Maps a string representation of a Matrix type to Matrix type. -const matrixTypes = new Map(); +/** ArrayType describes the type of WGSL Array. */ +export class ArrayType { + readonly count: number; // Number of elements in the array + readonly elementType: Type; // Element type + + // Maps a string representation of a array type to array type. + private static instances = new Map(); -export function TypeMat(cols: number, rows: number, elementType: ScalarType): MatrixType { - const key = `${elementType.toString()} ${cols} ${rows}`; - let ty = matrixTypes.get(key); - if (ty !== undefined) { + static create(count: number, elementType: Type): ArrayType { + const key = `${elementType.toString()} ${count}`; + let ty = this.instances.get(key); + if (ty !== undefined) { + return ty; + } + ty = new ArrayType(count, elementType); + this.instances.set(key, ty); return ty; } - ty = new MatrixType(cols, rows, elementType); - matrixTypes.set(key, ty); - return ty; -} -/** Type is a ScalarType, VectorType, or MatrixType. */ -export type Type = ScalarType | VectorType | MatrixType; + constructor(count: number, elementType: Type) { + this.count = count; + this.elementType = elementType; + } + + /** + * @returns a array constructed from the values read from the buffer at the + * given byte offset + */ + public read(buf: Uint8Array, offset: number): ArrayValue { + const elements: Array = []; + + for (let i = 0; i < this.count; i++) { + elements[i] = this.elementType.read(buf, offset); + offset += this.stride; + } + return new ArrayValue(elements); + } + + public toString(): string { + return `array<${this.elementType}, ${this.count}>`; + } + + public get stride(): number { + return align(this.elementType.size, this.elementType.alignment); + } + + public get size(): number { + return this.stride * this.count; + } + + public get alignment(): number { + return this.elementType.alignment; + } +} /** ArrayElementType infers the element type of the indexable type A */ type ArrayElementType = A extends { [index: number]: infer T } ? T : never; @@ -800,74 +879,132 @@ function valueFromBytes( return workingDataOut[0] as ArrayElementType; } -export const TypeAbstractInt = new ScalarType( - 'abstract-int', - 8, - (buf: Uint8Array, offset: number) => abstractInt(valueFromBytes(workingDataI64, buf, offset)) +const abstractIntType = new ScalarType('abstract-int', 8, (buf: Uint8Array, offset: number) => + abstractInt(valueFromBytes(workingDataI64, buf, offset)) ); -export const TypeI32 = new ScalarType('i32', 4, (buf: Uint8Array, offset: number) => +const i32Type = new ScalarType('i32', 4, (buf: Uint8Array, offset: number) => i32(valueFromBytes(workingDataI32, buf, offset)) ); -export const TypeU32 = new ScalarType('u32', 4, (buf: Uint8Array, offset: number) => +const u32Type = new ScalarType('u32', 4, (buf: Uint8Array, offset: number) => u32(valueFromBytes(workingDataU32, buf, offset)) ); -export const TypeAbstractFloat = new ScalarType( - 'abstract-float', - 8, - (buf: Uint8Array, offset: number) => abstractFloat(valueFromBytes(workingDataF64, buf, offset)) -); -export const TypeF64 = new ScalarType('f64', 8, (buf: Uint8Array, offset: number) => - f64(valueFromBytes(workingDataF64, buf, offset)) -); -export const TypeF32 = new ScalarType('f32', 4, (buf: Uint8Array, offset: number) => - f32(valueFromBytes(workingDataF32, buf, offset)) -); -export const TypeI16 = new ScalarType('i16', 2, (buf: Uint8Array, offset: number) => +const i16Type = new ScalarType('i16', 2, (buf: Uint8Array, offset: number) => i16(valueFromBytes(workingDataI16, buf, offset)) ); -export const TypeU16 = new ScalarType('u16', 2, (buf: Uint8Array, offset: number) => +const u16Type = new ScalarType('u16', 2, (buf: Uint8Array, offset: number) => u16(valueFromBytes(workingDataU16, buf, offset)) ); -export const TypeF16 = new ScalarType('f16', 2, (buf: Uint8Array, offset: number) => - f16Bits(valueFromBytes(workingDataU16, buf, offset)) -); -export const TypeI8 = new ScalarType('i8', 1, (buf: Uint8Array, offset: number) => +const i8Type = new ScalarType('i8', 1, (buf: Uint8Array, offset: number) => i8(valueFromBytes(workingDataI8, buf, offset)) ); -export const TypeU8 = new ScalarType('u8', 1, (buf: Uint8Array, offset: number) => +const u8Type = new ScalarType('u8', 1, (buf: Uint8Array, offset: number) => u8(valueFromBytes(workingDataU8, buf, offset)) ); -export const TypeBool = new ScalarType('bool', 4, (buf: Uint8Array, offset: number) => +const abstractFloatType = new ScalarType('abstract-float', 8, (buf: Uint8Array, offset: number) => + abstractFloat(valueFromBytes(workingDataF64, buf, offset)) +); +const f64Type = new ScalarType('f64', 8, (buf: Uint8Array, offset: number) => + f64(valueFromBytes(workingDataF64, buf, offset)) +); +const f32Type = new ScalarType('f32', 4, (buf: Uint8Array, offset: number) => + f32(valueFromBytes(workingDataF32, buf, offset)) +); +const f16Type = new ScalarType('f16', 2, (buf: Uint8Array, offset: number) => + f16Bits(valueFromBytes(workingDataU16, buf, offset)) +); +const boolType = new ScalarType('bool', 4, (buf: Uint8Array, offset: number) => bool(valueFromBytes(workingDataU32, buf, offset) !== 0) ); +/** Type is a ScalarType, VectorType, MatrixType or ArrayType. */ +export type Type = ScalarType | VectorType | MatrixType | ArrayType; + +/** Type holds pre-declared Types along with helper constructor functions. */ +export const Type = { + abstractInt: abstractIntType, + 'abstract-int': abstractIntType, + i32: i32Type, + u32: u32Type, + i16: i16Type, + u16: u16Type, + i8: i8Type, + u8: u8Type, + + abstractFloat: abstractFloatType, + 'abstract-float': abstractFloatType, + f64: f64Type, + f32: f32Type, + f16: f16Type, + + bool: boolType, + + vec: (width: number, elementType: ScalarType) => VectorType.create(width, elementType), + + vec2i: VectorType.create(2, i32Type), + vec2u: VectorType.create(2, u32Type), + vec2f: VectorType.create(2, f32Type), + vec2h: VectorType.create(2, f16Type), + vec3i: VectorType.create(3, i32Type), + vec3u: VectorType.create(3, u32Type), + vec3f: VectorType.create(3, f32Type), + vec3h: VectorType.create(3, f16Type), + vec4i: VectorType.create(4, i32Type), + vec4u: VectorType.create(4, u32Type), + vec4f: VectorType.create(4, f32Type), + vec4h: VectorType.create(4, f16Type), + + mat: (cols: number, rows: number, elementType: ScalarType) => + MatrixType.create(cols, rows, elementType), + + mat2x2f: MatrixType.create(2, 2, f32Type), + mat2x2h: MatrixType.create(2, 2, f16Type), + mat3x2f: MatrixType.create(3, 2, f32Type), + mat3x2h: MatrixType.create(3, 2, f16Type), + mat4x2f: MatrixType.create(4, 2, f32Type), + mat4x2h: MatrixType.create(4, 2, f16Type), + mat2x3f: MatrixType.create(2, 3, f32Type), + mat2x3h: MatrixType.create(2, 3, f16Type), + mat3x3f: MatrixType.create(3, 3, f32Type), + mat3x3h: MatrixType.create(3, 3, f16Type), + mat4x3f: MatrixType.create(4, 3, f32Type), + mat4x3h: MatrixType.create(4, 3, f16Type), + mat2x4f: MatrixType.create(2, 4, f32Type), + mat2x4h: MatrixType.create(2, 4, f16Type), + mat3x4f: MatrixType.create(3, 4, f32Type), + mat3x4h: MatrixType.create(3, 4, f16Type), + mat4x4f: MatrixType.create(4, 4, f32Type), + mat4x4h: MatrixType.create(4, 4, f16Type), + + array: (count: number, elementType: Type) => ArrayType.create(count, elementType), +}; + /** @returns the ScalarType from the ScalarKind */ export function scalarType(kind: ScalarKind): ScalarType { switch (kind) { case 'abstract-float': - return TypeAbstractFloat; + return Type.abstractFloat; case 'f64': - return TypeF64; + return Type.f64; case 'f32': - return TypeF32; + return Type.f32; case 'f16': - return TypeF16; + return Type.f16; case 'u32': - return TypeU32; + return Type.u32; case 'u16': - return TypeU16; + return Type.u16; case 'u8': - return TypeU8; + return Type.u8; case 'abstract-int': - return TypeAbstractInt; + return Type.abstractInt; case 'i32': - return TypeI32; + return Type.i32; case 'i16': - return TypeI16; + return Type.i16; case 'i8': - return TypeI8; + return Type.i8; case 'bool': - return TypeBool; + return Type.bool; } } @@ -882,23 +1019,54 @@ export function numElementsOf(ty: Type): number { if (ty instanceof MatrixType) { return ty.cols * ty.rows; } + if (ty instanceof ArrayType) { + return ty.count; + } throw new Error(`unhandled type ${ty}`); } /** @returns the scalar elements of the given Value */ -export function elementsOf(value: Value): Scalar[] { - if (value instanceof Scalar) { +export function elementsOf(value: Value): Value[] { + if (isScalarValue(value)) { return [value]; } - if (value instanceof Vector) { + if (value instanceof VectorValue) { return value.elements; } - if (value instanceof Matrix) { + if (value instanceof MatrixValue) { return value.elements.flat(); } + if (value instanceof ArrayValue) { + return value.elements; + } throw new Error(`unhandled value ${value}`); } +/** @returns the scalar elements of the given Value */ +export function scalarElementsOf(value: Value): ScalarValue[] { + if (isScalarValue(value)) { + return [value]; + } + if (value instanceof VectorValue) { + return value.elements; + } + if (value instanceof MatrixValue) { + return value.elements.flat(); + } + if (value instanceof ArrayValue) { + return value.elements.map(els => scalarElementsOf(els)).flat(); + } + throw new Error(`unhandled value ${value}`); +} + +/** @returns the inner element type of the given type */ +export function elementTypeOf(t: Type) { + if (t instanceof ScalarType) { + return t; + } + return t.elementType; +} + /** @returns the scalar (element) type of the given Type */ export function scalarTypeOf(ty: Type): ScalarType { if (ty instanceof ScalarType) { @@ -910,27 +1078,40 @@ export function scalarTypeOf(ty: Type): ScalarType { if (ty instanceof MatrixType) { return ty.elementType; } + if (ty instanceof ArrayType) { + return scalarTypeOf(ty.elementType); + } throw new Error(`unhandled type ${ty}`); } -/** ScalarValue is the JS type that can be held by a Scalar */ -type ScalarValue = boolean | number | bigint; +function hex(sizeInBytes: number, bitsLow: number, bitsHigh?: number) { + let hex = ''; + workingDataU32[0] = bitsLow; + if (bitsHigh !== undefined) { + workingDataU32[1] = bitsHigh; + } + for (let i = 0; i < sizeInBytes; ++i) { + hex = workingDataU8[i].toString(16).padStart(2, '0') + hex; + } + return `0x${hex}`; +} -/** Class that encapsulates a single scalar value of various types. */ -export class Scalar { - readonly value: ScalarValue; // The scalar value - readonly type: ScalarType; // The type of the scalar +function withPoint(x: number) { + const str = `${x}`; + return str.indexOf('.') > 0 || str.indexOf('e') > 0 ? str : `${str}.0`; +} - // The scalar value, packed in one or two 32-bit unsigned integers. - // Whether or not the bits1 is used depends on `this.type.size`. - readonly bits1: number; - readonly bits0: number; +/** Class that encapsulates a single abstract-int value. */ +export class AbstractIntValue { + readonly value: bigint; // The abstract-integer value + readonly bitsLow: number; // The low 32 bits of the abstract-integer value. + readonly bitsHigh: number; // The high 32 bits of the abstract-integer value. + readonly type = Type.abstractInt; // The type of the value. - public constructor(type: ScalarType, value: ScalarValue, bits1: number, bits0: number) { + public constructor(value: bigint, bitsLow: number, bitsHigh: number) { this.value = value; - this.type = type; - this.bits1 = bits1; - this.bits0 = bits0; + this.bitsLow = bitsLow; + this.bitsHigh = bitsHigh; } /** @@ -939,229 +1120,583 @@ export class Scalar { * @param offset the offset in buffer, in units of `buffer` */ public copyTo(buffer: TypedArrayBufferView, offset: number) { - assert( - this.type.kind !== 'abstract-int', - `Copying 'abstract-int' values to/from buffers is yet implemented` - ); - assert(this.type.kind !== 'f64', `Copying f64 values to/from buffers is not defined`); - workingDataU32[1] = this.bits1; - workingDataU32[0] = this.bits0; - for (let i = 0; i < this.type.size; i++) { + workingDataU32[0] = this.bitsLow; + workingDataU32[1] = this.bitsHigh; + for (let i = 0; i < 8; i++) { buffer[offset + i] = workingDataU8[i]; } } + /** @returns the WGSL representation of this scalar value */ + public wgsl(): string { + // WGSL parses negative numbers as a negated positive. + // This means '-9223372036854775808' parses as `-' & '9223372036854775808', so must be written as + // '(-9223372036854775807 - 1)' in WGSL, because '9223372036854775808' is not a valid AbstractInt. + if (this.value === -9223372036854775808n) { + return `(-9223372036854775807 - 1)`; + } + return `${this.value}`; + } + + public toString(): string { + return `${Colors.bold(this.value.toString())} (${hex(8, this.bitsLow, this.bitsHigh)})`; + } +} + +/** Class that encapsulates a single abstract-float value. */ +export class AbstractFloatValue { + readonly value: number; // The f32 value + readonly bitsLow: number; // The low 32 bits of the abstract-float value. + readonly bitsHigh: number; // The high 32 bits of the abstract-float value. + readonly type = Type.abstractFloat; // The type of the value. + + public constructor(value: number, bitsLow: number, bitsHigh: number) { + this.value = value; + this.bitsLow = bitsLow; + this.bitsHigh = bitsHigh; + } + /** - * @returns the WGSL representation of this scalar value + * Copies the scalar value to the buffer at the provided byte offset. + * @param buffer the destination buffer + * @param offset the offset in buffer, in units of `buffer` */ + public copyTo(buffer: TypedArrayBufferView, offset: number) { + workingDataU32[0] = this.bitsLow; + workingDataU32[1] = this.bitsHigh; + for (let i = 0; i < 8; i++) { + buffer[offset + i] = workingDataU8[i]; + } + } + + /** @returns the WGSL representation of this scalar value */ public wgsl(): string { - const withPoint = (x: number) => { - const str = `${x}`; - return str.indexOf('.') > 0 || str.indexOf('e') > 0 ? str : `${str}.0`; - }; + return `${withPoint(this.value)}`; + } - switch (typeof this.value) { - case 'bigint': - if (this.type.kind === 'abstract-int') { - // WGSL parses negative numbers as a negated positive. - // This means '-9223372036854775808' parses as `-' & - // '9223372036854775808', so must be written as - // '(-9223372036854775807 - 1)' in WGSL, because '9223372036854775808' - // is not a valid AbstractInt. - if (this.value === -9223372036854775808n) { - return `(-9223372036854775807 - 1)`; - } - return `${this.value}`; - } - break; - case 'number': - if (!isFinite(this.value)) break; - switch (this.type.kind) { - case 'abstract-float': - return `${withPoint(this.value)}`; - case 'f64': - return `${withPoint(this.value)}`; - case 'f32': - return `${withPoint(this.value)}f`; - case 'f16': - return `${withPoint(this.value)}h`; - case 'u32': - return `${this.value}u`; - case 'i32': - return `i32(${this.value})`; - } - break; - case 'boolean': - return `${this.value}`; + public toString(): string { + switch (this.value) { + case Infinity: + case -Infinity: + return Colors.bold(this.value.toString()); + default: { + let str = this.value.toString(); + str = str.indexOf('.') > 0 || str.indexOf('e') > 0 ? str : `${str}.0`; + return isSubnormalNumberF64(this.value.valueOf()) + ? `${Colors.bold(str)} (${hex(8, this.bitsLow, this.bitsHigh)} subnormal)` + : `${Colors.bold(str)} (${hex(8, this.bitsLow, this.bitsHigh)})`; + } } + } +} - throw new Error( - `scalar of value ${this.value} and type ${this.type} has no WGSL representation` - ); +/** Class that encapsulates a single i32 value. */ +export class I32Value { + readonly value: number; // The i32 value + readonly bits: number; // The i32 value, bitcast to a 32-bit integer. + readonly type = Type.i32; // The type of the value. + + public constructor(value: number, bits: number) { + this.value = value; + this.bits = bits; + } + + /** + * Copies the scalar value to the buffer at the provided byte offset. + * @param buffer the destination buffer + * @param offset the offset in buffer, in units of `buffer` + */ + public copyTo(buffer: TypedArrayBufferView, offset: number) { + workingDataU32[0] = this.bits; + for (let i = 0; i < 4; i++) { + buffer[offset + i] = workingDataU8[i]; + } + } + + /** @returns the WGSL representation of this scalar value */ + public wgsl(): string { + return `i32(${this.value})`; + } + + public toString(): string { + return `${Colors.bold(this.value.toString())} (${hex(4, this.bits)})`; + } +} + +/** Class that encapsulates a single u32 value. */ +export class U32Value { + readonly value: number; // The u32 value + readonly type = Type.u32; // The type of the value. + + public constructor(value: number) { + this.value = value; + } + + /** + * Copies the scalar value to the buffer at the provided byte offset. + * @param buffer the destination buffer + * @param offset the offset in buffer, in units of `buffer` + */ + public copyTo(buffer: TypedArrayBufferView, offset: number) { + workingDataU32[0] = this.value; + for (let i = 0; i < 4; i++) { + buffer[offset + i] = workingDataU8[i]; + } + } + + /** @returns the WGSL representation of this scalar value */ + public wgsl(): string { + return `${this.value}u`; + } + + public toString(): string { + return `${Colors.bold(this.value.toString())} (${hex(4, this.value)})`; + } +} + +/** + * Class that encapsulates a single i16 value. + * @note type does not exist in WGSL yet + */ +export class I16Value { + readonly value: number; // The i16 value + readonly bits: number; // The i16 value, bitcast to a 16-bit integer. + readonly type = Type.i16; // The type of the value. + + public constructor(value: number, bits: number) { + this.value = value; + this.bits = bits; + } + + /** + * Copies the scalar value to the buffer at the provided byte offset. + * @param buffer the destination buffer + * @param offset the offset in buffer, in units of `buffer` + */ + public copyTo(buffer: TypedArrayBufferView, offset: number) { + workingDataU16[0] = this.bits; + for (let i = 0; i < 4; i++) { + buffer[offset + i] = workingDataU8[i]; + } + } + + /** @returns the WGSL representation of this scalar value */ + public wgsl(): string { + return `i16(${this.value})`; + } + + public toString(): string { + return `${Colors.bold(this.value.toString())} (${hex(2, this.bits)})`; + } +} + +/** + * Class that encapsulates a single u16 value. + * @note type does not exist in WGSL yet + */ +export class U16Value { + readonly value: number; // The u16 value + readonly type = Type.u16; // The type of the value. + + public constructor(value: number) { + this.value = value; + } + + /** + * Copies the scalar value to the buffer at the provided byte offset. + * @param buffer the destination buffer + * @param offset the offset in buffer, in units of `buffer` + */ + public copyTo(buffer: TypedArrayBufferView, offset: number) { + workingDataU16[0] = this.value; + for (let i = 0; i < 2; i++) { + buffer[offset + i] = workingDataU8[i]; + } + } + + /** @returns the WGSL representation of this scalar value */ + public wgsl(): string { + assert(false, 'u16 is not a WGSL type'); + return `u16(${this.value})`; + } + + public toString(): string { + return `${Colors.bold(this.value.toString())} (${hex(2, this.value)})`; + } +} + +/** + * Class that encapsulates a single i8 value. + * @note type does not exist in WGSL yet + */ +export class I8Value { + readonly value: number; // The i8 value + readonly bits: number; // The i8 value, bitcast to a 8-bit integer. + readonly type = Type.i8; // The type of the value. + + public constructor(value: number, bits: number) { + this.value = value; + this.bits = bits; + } + + /** + * Copies the scalar value to the buffer at the provided byte offset. + * @param buffer the destination buffer + * @param offset the offset in buffer, in units of `buffer` + */ + public copyTo(buffer: TypedArrayBufferView, offset: number) { + workingDataU8[0] = this.bits; + for (let i = 0; i < 4; i++) { + buffer[offset + i] = workingDataU8[i]; + } + } + + /** @returns the WGSL representation of this scalar value */ + public wgsl(): string { + return `i8(${this.value})`; } public toString(): string { - if (this.type.kind === 'bool') { - return Colors.bold(this.value.toString()); + return `${Colors.bold(this.value.toString())} (${hex(2, this.bits)})`; + } +} + +/** + * Class that encapsulates a single u8 value. + * @note type does not exist in WGSL yet + */ +export class U8Value { + readonly value: number; // The u8 value + readonly type = Type.u8; // The type of the value. + + public constructor(value: number) { + this.value = value; + } + + /** + * Copies the scalar value to the buffer at the provided byte offset. + * @param buffer the destination buffer + * @param offset the offset in buffer, in units of `buffer` + */ + public copyTo(buffer: TypedArrayBufferView, offset: number) { + workingDataU8[0] = this.value; + for (let i = 0; i < 2; i++) { + buffer[offset + i] = workingDataU8[i]; } + } + + /** @returns the WGSL representation of this scalar value */ + public wgsl(): string { + assert(false, 'u8 is not a WGSL type'); + return `u8(${this.value})`; + } + + public toString(): string { + return `${Colors.bold(this.value.toString())} (${hex(2, this.value)})`; + } +} + +/** + * Class that encapsulates a single f64 value + * @note type does not exist in WGSL yet + */ +export class F64Value { + readonly value: number; // The f32 value + readonly bitsLow: number; // The low 32 bits of the abstract-float value. + readonly bitsHigh: number; // The high 32 bits of the abstract-float value. + readonly type = Type.f64; // The type of the value. + + public constructor(value: number, bitsLow: number, bitsHigh: number) { + this.value = value; + this.bitsLow = bitsLow; + this.bitsHigh = bitsHigh; + } + + /** + * Copies the scalar value to the buffer at the provided byte offset. + * @param buffer the destination buffer + * @param offset the offset in buffer, in units of `buffer` + */ + public copyTo(buffer: TypedArrayBufferView, offset: number) { + workingDataU32[0] = this.bitsLow; + workingDataU32[1] = this.bitsHigh; + for (let i = 0; i < 8; i++) { + buffer[offset + i] = workingDataU8[i]; + } + } + + /** @returns the WGSL representation of this scalar value */ + public wgsl(): string { + assert(false, 'f64 is not a WGSL type'); + return `${withPoint(this.value)}`; + } + + public toString(): string { switch (this.value) { case Infinity: case -Infinity: return Colors.bold(this.value.toString()); default: { - workingDataU32[1] = this.bits1; - workingDataU32[0] = this.bits0; - let hex = ''; - for (let i = 0; i < this.type.size; ++i) { - hex = workingDataU8[i].toString(16).padStart(2, '0') + hex; - } - const n = this.value as Number; - if (n !== null && isFloatValue(this)) { - let str = this.value.toString(); - str = str.indexOf('.') > 0 || str.indexOf('e') > 0 ? str : `${str}.0`; - switch (this.type.kind) { - case 'abstract-float': - return isSubnormalNumberF64(n.valueOf()) - ? `${Colors.bold(str)} (0x${hex} subnormal)` - : `${Colors.bold(str)} (0x${hex})`; - case 'f64': - return isSubnormalNumberF64(n.valueOf()) - ? `${Colors.bold(str)} (0x${hex} subnormal)` - : `${Colors.bold(str)} (0x${hex})`; - case 'f32': - return isSubnormalNumberF32(n.valueOf()) - ? `${Colors.bold(str)} (0x${hex} subnormal)` - : `${Colors.bold(str)} (0x${hex})`; - case 'f16': - return isSubnormalNumberF16(n.valueOf()) - ? `${Colors.bold(str)} (0x${hex} subnormal)` - : `${Colors.bold(str)} (0x${hex})`; - default: - unreachable( - `Printing of floating point kind ${this.type.kind} is not implemented...` - ); - } - } - return `${Colors.bold(this.value.toString())} (0x${hex})`; + let str = this.value.toString(); + str = str.indexOf('.') > 0 || str.indexOf('e') > 0 ? str : `${str}.0`; + return isSubnormalNumberF64(this.value.valueOf()) + ? `${Colors.bold(str)} (${hex(8, this.bitsLow, this.bitsHigh)} subnormal)` + : `${Colors.bold(str)} (${hex(8, this.bitsLow, this.bitsHigh)})`; } } } } -export interface ScalarBuilder { - (value: T): Scalar; +/** Class that encapsulates a single f32 value. */ +export class F32Value { + readonly value: number; // The f32 value + readonly bits: number; // The f32 value, bitcast to a 32-bit integer. + readonly type = Type.f32; // The type of the value. + + public constructor(value: number, bits: number) { + this.value = value; + this.bits = bits; + } + + /** + * Copies the scalar value to the buffer at the provided byte offset. + * @param buffer the destination buffer + * @param offset the offset in buffer, in units of `buffer` + */ + public copyTo(buffer: TypedArrayBufferView, offset: number) { + workingDataU32[0] = this.bits; + for (let i = 0; i < 4; i++) { + buffer[offset + i] = workingDataU8[i]; + } + } + + /** @returns the WGSL representation of this scalar value */ + public wgsl(): string { + return `${withPoint(this.value)}f`; + } + + public toString(): string { + switch (this.value) { + case Infinity: + case -Infinity: + return Colors.bold(this.value.toString()); + default: { + let str = this.value.toString(); + str = str.indexOf('.') > 0 || str.indexOf('e') > 0 ? str : `${str}.0`; + return isSubnormalNumberF32(this.value.valueOf()) + ? `${Colors.bold(str)} (${hex(4, this.bits)} subnormal)` + : `${Colors.bold(str)} (${hex(4, this.bits)})`; + } + } + } } -/** Create a Scalar of `type` by storing `value` as an element of `workingDataArray` and retrieving it. - * The working data array *must* be an alias of `workingData`. - */ -function scalarFromValue( - type: ScalarType, - workingDataArray: A, - value: ArrayElementType -): Scalar { - // Clear all bits of the working data since `value` may be smaller; the upper bits should be 0. - workingDataU32[1] = 0; - workingDataU32[0] = 0; - workingDataArray[0] = value; - return new Scalar(type, workingDataArray[0], workingDataU32[1], workingDataU32[0]); -} - -/** Create a Scalar of `type` by storing `value` as an element of `workingDataStoreArray` and - * reinterpreting it as an element of `workingDataLoadArray`. - * Both working data arrays *must* be aliases of `workingData`. - */ -function scalarFromBits( - type: ScalarType, - workingDataStoreArray: A, - workingDataLoadArray: TypedArrayBufferView, - bits: ArrayElementType -): Scalar { - // Clear all bits of the working data since `value` may be smaller; the upper bits should be 0. - workingDataU32[1] = 0; - workingDataU32[0] = 0; - workingDataStoreArray[0] = bits; - return new Scalar(type, workingDataLoadArray[0], workingDataU32[1], workingDataU32[0]); +/** Class that encapsulates a single f16 value. */ +export class F16Value { + readonly value: number; // The f16 value + readonly bits: number; // The f16 value, bitcast to a 16-bit integer. + readonly type = Type.f16; // The type of the value. + + public constructor(value: number, bits: number) { + this.value = value; + this.bits = bits; + } + + /** + * Copies the scalar value to the buffer at the provided byte offset. + * @param buffer the destination buffer + * @param offset the offset in buffer, in units of `buffer` + */ + public copyTo(buffer: TypedArrayBufferView, offset: number) { + workingDataU16[0] = this.bits; + for (let i = 0; i < 2; i++) { + buffer[offset + i] = workingDataU8[i]; + } + } + + /** @returns the WGSL representation of this scalar value */ + public wgsl(): string { + return `${withPoint(this.value)}h`; + } + + public toString(): string { + switch (this.value) { + case Infinity: + case -Infinity: + return Colors.bold(this.value.toString()); + default: { + let str = this.value.toString(); + str = str.indexOf('.') > 0 || str.indexOf('e') > 0 ? str : `${str}.0`; + return isSubnormalNumberF16(this.value.valueOf()) + ? `${Colors.bold(str)} (${hex(2, this.bits)} subnormal)` + : `${Colors.bold(str)} (${hex(2, this.bits)})`; + } + } + } } +/** Class that encapsulates a single bool value. */ +export class BoolValue { + readonly value: boolean; // The bool value + readonly type = Type.bool; // The type of the value. -/** Create an AbstractFloat from a numeric value, a JS `number`. */ -export const abstractFloat = (value: number): Scalar => - scalarFromValue(TypeAbstractFloat, workingDataF64, value); + public constructor(value: boolean) { + this.value = value; + } -/** Create an f64 from a numeric value, a JS `number`. */ -export const f64 = (value: number): Scalar => scalarFromValue(TypeF64, workingDataF64, value); + /** + * Copies the scalar value to the buffer at the provided byte offset. + * @param buffer the destination buffer + * @param offset the offset in buffer, in units of `buffer` + */ + public copyTo(buffer: TypedArrayBufferView, offset: number) { + buffer[offset] = this.value ? 1 : 0; + } -/** Create an f32 from a numeric value, a JS `number`. */ -export const f32 = (value: number): Scalar => scalarFromValue(TypeF32, workingDataF32, value); + /** @returns the WGSL representation of this scalar value */ + public wgsl(): string { + return this.value.toString(); + } -/** Create an f16 from a numeric value, a JS `number`. */ -export const f16 = (value: number): Scalar => scalarFromValue(TypeF16, workingDataF16, value); + public toString(): string { + return Colors.bold(this.value.toString()); + } +} -/** Create an f32 from a bit representation, a uint32 represented as a JS `number`. */ -export const f32Bits = (bits: number): Scalar => - scalarFromBits(TypeF32, workingDataU32, workingDataF32, bits); +/** Scalar represents all the scalar value types */ +export type ScalarValue = + | AbstractIntValue + | AbstractFloatValue + | I32Value + | U32Value + | I16Value + | U16Value + | I8Value + | U8Value + | F64Value + | F32Value + | F16Value + | BoolValue; -/** Create an f16 from a bit representation, a uint16 represented as a JS `number`. */ -export const f16Bits = (bits: number): Scalar => - scalarFromBits(TypeF16, workingDataU16, workingDataF16, bits); +export interface ScalarBuilder { + (value: T): ScalarValue; +} -/** Create an AbstractInt from a numeric value, a JS `bigint`. */ -export const abstractInt = (value: bigint): Scalar => - scalarFromValue(TypeAbstractInt, workingDataI64, value); +export function isScalarValue(value: object): value is ScalarValue { + return ( + value instanceof AbstractIntValue || + value instanceof AbstractFloatValue || + value instanceof I32Value || + value instanceof U32Value || + value instanceof I16Value || + value instanceof U16Value || + value instanceof I8Value || + value instanceof U8Value || + value instanceof F64Value || + value instanceof F32Value || + value instanceof F16Value || + value instanceof BoolValue + ); +} -export const abstractIntBits = (bits: bigint): Scalar => - scalarFromBits(TypeAbstractInt, workingDataU64, workingDataI64, bits); +/** Create an AbstractInt from a numeric value, a JS `bigint`. */ +export function abstractInt(value: bigint) { + workingDataI64[0] = value; + return new AbstractIntValue(workingDataI64[0], workingDataU32[0], workingDataU32[1]); +} -/** Create an i32 from a numeric value, a JS `number`. */ -export const i32 = (value: number): Scalar => scalarFromValue(TypeI32, workingDataI32, value); +/** Create an AbstractInt from a bit representation, a uint64 represented as a JS `bigint`. */ +export function abstractIntBits(value: bigint) { + workingDataU64[0] = value; + return new AbstractIntValue(workingDataI64[0], workingDataU32[0], workingDataU32[1]); +} -/** Create an i16 from a numeric value, a JS `number`. */ -export const i16 = (value: number): Scalar => scalarFromValue(TypeI16, workingDataI16, value); +/** Create an AbstractFloat from a numeric value, a JS `number`. */ +export function abstractFloat(value: number) { + workingDataF64[0] = value; + return new AbstractFloatValue(workingDataF64[0], workingDataU32[0], workingDataU32[1]); +} -/** Create an i8 from a numeric value, a JS `number`. */ -export const i8 = (value: number): Scalar => scalarFromValue(TypeI8, workingDataI8, value); +/** Create an i32 from a numeric value, a JS `number`. */ +export function i32(value: number) { + workingDataI32[0] = value; + return new I32Value(workingDataI32[0], workingDataU32[0]); +} /** Create an i32 from a bit representation, a uint32 represented as a JS `number`. */ -export const i32Bits = (bits: number): Scalar => - scalarFromBits(TypeI32, workingDataU32, workingDataI32, bits); +export function i32Bits(bits: number) { + workingDataU32[0] = bits; + return new I32Value(workingDataI32[0], workingDataU32[0]); +} -/** Create an i16 from a bit representation, a uint16 represented as a JS `number`. */ -export const i16Bits = (bits: number): Scalar => - scalarFromBits(TypeI16, workingDataU16, workingDataI16, bits); +/** Create a u32 from a numeric value, a JS `number`. */ +export function u32(value: number) { + workingDataU32[0] = value; + return new U32Value(workingDataU32[0]); +} -/** Create an i8 from a bit representation, a uint8 represented as a JS `number`. */ -export const i8Bits = (bits: number): Scalar => - scalarFromBits(TypeI8, workingDataU8, workingDataI8, bits); +/** Create a u32 from a bit representation, a uint32 represented as a JS `number`. */ +export function u32Bits(bits: number) { + workingDataU32[0] = bits; + return new U32Value(workingDataU32[0]); +} -/** Create a u32 from a numeric value, a JS `number`. */ -export const u32 = (value: number): Scalar => scalarFromValue(TypeU32, workingDataU32, value); +/** Create an i16 from a numeric value, a JS `number`. */ +export function i16(value: number) { + workingDataI16[0] = value; + return new I16Value(workingDataI16[0], workingDataU16[0]); +} /** Create a u16 from a numeric value, a JS `number`. */ -export const u16 = (value: number): Scalar => scalarFromValue(TypeU16, workingDataU16, value); +export function u16(value: number) { + workingDataU16[0] = value; + return new U16Value(workingDataU16[0]); +} + +/** Create an i8 from a numeric value, a JS `number`. */ +export function i8(value: number) { + workingDataI8[0] = value; + return new I8Value(workingDataI8[0], workingDataU8[0]); +} /** Create a u8 from a numeric value, a JS `number`. */ -export const u8 = (value: number): Scalar => scalarFromValue(TypeU8, workingDataU8, value); +export function u8(value: number) { + workingDataU8[0] = value; + return new U8Value(workingDataU8[0]); +} + +/** Create an f64 from a numeric value, a JS `number`. */ +export function f64(value: number) { + workingDataF64[0] = value; + return new F64Value(workingDataF64[0], workingDataU32[0], workingDataU32[1]); +} + +/** Create an f32 from a numeric value, a JS `number`. */ +export function f32(value: number) { + workingDataF32[0] = value; + return new F32Value(workingDataF32[0], workingDataU32[0]); +} -/** Create an u32 from a bit representation, a uint32 represented as a JS `number`. */ -export const u32Bits = (bits: number): Scalar => - scalarFromBits(TypeU32, workingDataU32, workingDataU32, bits); +/** Create an f32 from a bit representation, a uint32 represented as a JS `number`. */ +export function f32Bits(bits: number) { + workingDataU32[0] = bits; + return new F32Value(workingDataF32[0], workingDataU32[0]); +} -/** Create an u16 from a bit representation, a uint16 represented as a JS `number`. */ -export const u16Bits = (bits: number): Scalar => - scalarFromBits(TypeU16, workingDataU16, workingDataU16, bits); +/** Create an f16 from a numeric value, a JS `number`. */ +export function f16(value: number) { + workingDataF16[0] = value; + return new F16Value(value, workingDataU16[0]); +} -/** Create an u8 from a bit representation, a uint8 represented as a JS `number`. */ -export const u8Bits = (bits: number): Scalar => - scalarFromBits(TypeU8, workingDataU8, workingDataU8, bits); +/** Create an f16 from a bit representation, a uint16 represented as a JS `number`. */ +export function f16Bits(bits: number) { + workingDataU16[0] = bits; + return new F16Value(workingDataF16[0], workingDataU16[0]); +} /** Create a boolean value. */ -export function bool(value: boolean): Scalar { - // WGSL does not support using 'bool' types directly in storage / uniform - // buffers, so instead we pack booleans in a u32, where 'false' is zero and - // 'true' is any non-zero value. - workingDataU32[0] = value ? 1 : 0; - workingDataU32[1] = 0; - return new Scalar(TypeBool, value, workingDataU32[1], workingDataU32[0]); +export function bool(value: boolean): ScalarValue { + return new BoolValue(value); } /** A 'true' literal value */ @@ -1173,11 +1708,11 @@ export const False = bool(false); /** * Class that encapsulates a vector value. */ -export class Vector { - readonly elements: Array; +export class VectorValue { + readonly elements: Array; readonly type: VectorType; - public constructor(elements: Array) { + public constructor(elements: Array) { if (elements.length < 2 || elements.length > 4) { throw new Error(`vector element count must be between 2 and 4, got ${elements.length}`); } @@ -1191,7 +1726,7 @@ export class Vector { } } this.elements = elements; - this.type = TypeVec(elements.length, elements[0].type); + this.type = VectorType.create(elements.length, elements[0].type); } /** @@ -1240,18 +1775,18 @@ export class Vector { } /** Helper for constructing a new two-element vector with the provided values */ -export function vec2(x: Scalar, y: Scalar) { - return new Vector([x, y]); +export function vec2(x: ScalarValue, y: ScalarValue) { + return new VectorValue([x, y]); } /** Helper for constructing a new three-element vector with the provided values */ -export function vec3(x: Scalar, y: Scalar, z: Scalar) { - return new Vector([x, y, z]); +export function vec3(x: ScalarValue, y: ScalarValue, z: ScalarValue) { + return new VectorValue([x, y, z]); } /** Helper for constructing a new four-element vector with the provided values */ -export function vec4(x: Scalar, y: Scalar, z: Scalar, w: Scalar) { - return new Vector([x, y, z, w]); +export function vec4(x: ScalarValue, y: ScalarValue, z: ScalarValue, w: ScalarValue) { + return new VectorValue([x, y, z, w]); } /** @@ -1260,7 +1795,7 @@ export function vec4(x: Scalar, y: Scalar, z: Scalar, w: Scalar) { * @param v array of numbers to be converted, must contain 2, 3 or 4 elements * @param op function to convert from number to Scalar, e.g. 'f32` */ -export function toVector(v: readonly number[], op: (n: number) => Scalar): Vector { +export function toVector(v: readonly number[], op: (n: number) => ScalarValue): VectorValue { switch (v.length) { case 2: return vec2(op(v[0]), op(v[1])); @@ -1275,11 +1810,11 @@ export function toVector(v: readonly number[], op: (n: number) => Scalar): Vecto /** * Class that encapsulates a Matrix value. */ -export class Matrix { - readonly elements: Scalar[][]; +export class MatrixValue { + readonly elements: ScalarValue[][]; readonly type: MatrixType; - public constructor(elements: Array>) { + public constructor(elements: Array>) { const num_cols = elements.length; if (num_cols < 2 || num_cols > 4) { throw new Error(`matrix cols count must be between 2 and 4, got ${num_cols}`); @@ -1300,7 +1835,7 @@ export class Matrix { } this.elements = elements; - this.type = TypeMat(num_cols, num_rows, elem_type); + this.type = MatrixType.create(num_cols, num_rows, elem_type); } /** @@ -1335,6 +1870,53 @@ export class Matrix { } } +/** + * Class that encapsulates an Array value. + */ +export class ArrayValue { + readonly elements: Value[]; + readonly type: ArrayType; + + public constructor(elements: Array) { + const elem_type = elements[0].type; + if (!elements.every(c => elements.every(r => objectEquals(r.type, elem_type)))) { + throw new Error(`cannot mix array element types`); + } + + this.elements = elements; + this.type = ArrayType.create(elements.length, elem_type); + } + + /** + * Copies the array value to the Uint8Array buffer at the provided byte offset. + * @param buffer the destination buffer + * @param offset the byte offset within buffer + */ + public copyTo(buffer: Uint8Array, offset: number) { + for (const element of this.elements) { + element.copyTo(buffer, offset); + offset += this.type.elementType.size; + } + } + + /** + * @returns the WGSL representation of this array value + */ + public wgsl(): string { + const els = this.elements.map(r => r.wgsl()).join(', '); + return isAbstractType(this.type.elementType) ? `array(${els})` : `${this.type}(${els})`; + } + + public toString(): string { + return this.wgsl(); + } +} + +/** Helper for constructing an ArrayValue with the provided values */ +export function array(...elements: Value[]) { + return new ArrayValue(elements); +} + /** * Helper for constructing Matrices from arrays of numbers * @@ -1342,35 +1924,37 @@ export class Matrix { * be of the same length. All Arrays must have 2, 3, or 4 elements. * @param op function to convert from number to Scalar, e.g. 'f32` */ -export function toMatrix(m: ROArrayArray, op: (n: number) => Scalar): Matrix { +export function toMatrix(m: ROArrayArray, op: (n: number) => ScalarValue): MatrixValue { const cols = m.length; const rows = m[0].length; - const elements: Scalar[][] = [...Array(cols)].map(_ => [...Array(rows)]); + const elements: ScalarValue[][] = [...Array(cols)].map(_ => [ + ...Array(rows), + ]); for (let i = 0; i < cols; i++) { for (let j = 0; j < rows; j++) { elements[i][j] = op(m[i][j]); } } - return new Matrix(elements); + return new MatrixValue(elements); } -/** Value is a Scalar or Vector value. */ -export type Value = Scalar | Vector | Matrix; +/** Value is a Scalar, Vector, Matrix or Array value. */ +export type Value = ScalarValue | VectorValue | MatrixValue | ArrayValue; -export type SerializedValueScalar = { +export type SerializedScalarValue = { kind: 'scalar'; type: ScalarKind; value: boolean | number; }; -export type SerializedValueVector = { +export type SerializedVectorValue = { kind: 'vector'; type: ScalarKind; value: boolean[] | readonly number[]; }; -export type SerializedValueMatrix = { +export type SerializedMatrixValue = { kind: 'matrix'; type: ScalarKind; value: ROArrayArray; @@ -1475,7 +2059,7 @@ enum SerializedValueKind { /** serializeValue() serializes a Value to a BinaryStream */ export function serializeValue(s: BinaryStream, v: Value) { - const serializeScalar = (scalar: Scalar, kind: ScalarKind) => { + const serializeScalar = (scalar: ScalarValue, kind: ScalarKind) => { switch (typeof scalar.value) { case 'number': switch (kind) { @@ -1528,13 +2112,13 @@ export function serializeValue(s: BinaryStream, v: Value) { } }; - if (v instanceof Scalar) { + if (isScalarValue(v)) { s.writeU8(SerializedValueKind.Scalar); serializeScalarKind(s, v.type.kind); serializeScalar(v, v.type.kind); return; } - if (v instanceof Vector) { + if (v instanceof VectorValue) { s.writeU8(SerializedValueKind.Vector); serializeScalarKind(s, v.type.elementType.kind); s.writeU8(v.type.width); @@ -1543,7 +2127,7 @@ export function serializeValue(s: BinaryStream, v: Value) { } return; } - if (v instanceof Matrix) { + if (v instanceof MatrixValue) { s.writeU8(SerializedValueKind.Matrix); serializeScalarKind(s, v.type.elementType.kind); s.writeU8(v.type.cols); @@ -1596,23 +2180,23 @@ export function deserializeValue(s: BinaryStream): Value { return deserializeScalar(scalarKind); case SerializedValueKind.Vector: { const width = s.readU8(); - const scalars = new Array(width); + const scalars = new Array(width); for (let i = 0; i < width; i++) { scalars[i] = deserializeScalar(scalarKind); } - return new Vector(scalars); + return new VectorValue(scalars); } case SerializedValueKind.Matrix: { const numCols = s.readU8(); const numRows = s.readU8(); - const columns = new Array(numCols); + const columns = new Array(numCols); for (let c = 0; c < numCols; c++) { - columns[c] = new Array(numRows); + columns[c] = new Array(numRows); for (let i = 0; i < numRows; i++) { columns[c][i] = deserializeScalar(scalarKind); } } - return new Matrix(columns); + return new MatrixValue(columns); } default: unreachable(`invalid serialized value kind: ${valueKind}`); @@ -1650,36 +2234,74 @@ export function isFloatType(ty: Type): boolean { return false; } +/** @returns true if an argument of type 'src' can be used for a parameter of type 'dst' */ +export function isConvertible(src: Type, dst: Type) { + if (src === dst) { + return true; + } + + const widthOf = (ty: Type) => { + return ty instanceof VectorType ? ty.width : 1; + }; + + if (widthOf(src) !== widthOf(dst)) { + return false; + } + + const elSrc = scalarTypeOf(src); + const elDst = scalarTypeOf(dst); + + switch (elSrc.kind) { + case 'abstract-float': + switch (elDst.kind) { + case 'abstract-float': + case 'f16': + case 'f32': + case 'f64': + return true; + default: + return false; + } + case 'abstract-int': + switch (elDst.kind) { + case 'abstract-int': + case 'abstract-float': + case 'f16': + case 'f32': + case 'f64': + case 'u16': + case 'u32': + case 'u8': + case 'i16': + case 'i32': + case 'i8': + return true; + default: + return false; + } + default: + return false; + } +} + /// All floating-point scalar types -const kFloatScalars = [TypeAbstractFloat, TypeF32, TypeF16] as const; +const kFloatScalars = [Type.abstractFloat, Type.f32, Type.f16] as const; /// All floating-point vec2 types -const kFloatVec2 = [ - TypeVec(2, TypeAbstractFloat), - TypeVec(2, TypeF32), - TypeVec(2, TypeF16), -] as const; +const kFloatVec2 = [Type.vec(2, Type.abstractFloat), Type.vec2f, Type.vec2h] as const; /// All floating-point vec3 types -const kFloatVec3 = [ - TypeVec(3, TypeAbstractFloat), - TypeVec(3, TypeF32), - TypeVec(3, TypeF16), -] as const; +const kFloatVec3 = [Type.vec(3, Type.abstractFloat), Type.vec3f, Type.vec3h] as const; /// All floating-point vec4 types -const kFloatVec4 = [ - TypeVec(4, TypeAbstractFloat), - TypeVec(4, TypeF32), - TypeVec(4, TypeF16), -] as const; +const kFloatVec4 = [Type.vec(4, Type.abstractFloat), Type.vec4f, Type.vec4h] as const; /// All f16 floating-point scalar and vector types export const kConcreteF16ScalarsAndVectors = [ - TypeF16, - TypeVec(2, TypeF16), - TypeVec(3, TypeF16), - TypeVec(4, TypeF16), + Type.f16, + Type.vec2h, + Type.vec3h, + Type.vec4h, ] as const; /// All floating-point scalar and vector types @@ -1699,63 +2321,64 @@ export const kFloatScalarsAndVectors = [ /// All concrete integer scalar and vector types export const kConcreteIntegerScalarsAndVectors = [ - TypeI32, - TypeVec(2, TypeI32), - TypeVec(3, TypeI32), - TypeVec(4, TypeI32), - TypeU32, - TypeVec(2, TypeU32), - TypeVec(3, TypeU32), - TypeVec(4, TypeU32), + Type.i32, + Type.vec2i, + Type.vec3i, + Type.vec4i, + Type.u32, + Type.vec2u, + Type.vec3u, + Type.vec4u, ] as const; /// All signed integer scalar and vector types export const kConcreteSignedIntegerScalarsAndVectors = [ - TypeI32, - TypeVec(2, TypeI32), - TypeVec(3, TypeI32), - TypeVec(4, TypeI32), + Type.i32, + Type.vec2i, + Type.vec3i, + Type.vec4i, ] as const; /// All unsigned integer scalar and vector types export const kConcreteUnsignedIntegerScalarsAndVectors = [ - TypeU32, - TypeVec(2, TypeU32), - TypeVec(3, TypeU32), - TypeVec(4, TypeU32), + Type.u32, + Type.vec2u, + Type.vec3u, + Type.vec4u, ] as const; /// All types which are convertable to floating-point scalar types. -export const kConvertableToFloatScalar = [TypeAbstractInt, ...kFloatScalars] as const; +export const kConvertableToFloatScalar = [Type.abstractInt, ...kFloatScalars] as const; /// All types which are convertable to floating-point vector 2 types. -export const kConvertableToFloatVec2 = [TypeVec(2, TypeAbstractInt), ...kFloatVec2] as const; +export const kConvertableToFloatVec2 = [Type.vec(2, Type.abstractInt), ...kFloatVec2] as const; /// All types which are convertable to floating-point vector 3 types. -export const kConvertableToFloatVec3 = [TypeVec(3, TypeAbstractInt), ...kFloatVec3] as const; +export const kConvertableToFloatVec3 = [Type.vec(3, Type.abstractInt), ...kFloatVec3] as const; /// All types which are convertable to floating-point vector 4 types. -export const kConvertableToFloatVec4 = [TypeVec(4, TypeAbstractInt), ...kFloatVec4] as const; +export const kConvertableToFloatVec4 = [Type.vec(4, Type.abstractInt), ...kFloatVec4] as const; /// All types which are convertable to floating-point scalar or vector types. export const kConvertableToFloatScalarsAndVectors = [ - TypeAbstractInt, - TypeVec(2, TypeAbstractInt), - TypeVec(3, TypeAbstractInt), - TypeVec(4, TypeAbstractInt), + Type.abstractInt, + Type.vec(2, Type.abstractInt), + Type.vec(3, Type.abstractInt), + Type.vec(4, Type.abstractInt), ...kFloatScalarsAndVectors, ] as const; -/// All the scalar and vector types -export const kAllScalarsAndVectors = [ +/// All the numeric scalar and vector types. +export const kAllNumericScalarsAndVectors = [ ...kConvertableToFloatScalarsAndVectors, ...kConcreteIntegerScalarsAndVectors, ] as const; -/** @returns the inner element type of the given type */ -export function elementType(t: ScalarType | VectorType | MatrixType) { - if (t instanceof ScalarType) { - return t; - } - return t.elementType; -} +/// All the scalar and vector types. +export const kAllScalarsAndVectors = [ + Type.bool, + Type.vec(2, Type.bool), + Type.vec(3, Type.bool), + Type.vec(4, Type.bool), + ...kAllNumericScalarsAndVectors, +] as const; diff --git a/src/webgpu/util/device_pool.ts b/src/webgpu/util/device_pool.ts index 4e45aac76bb8..8f734c75aec7 100644 --- a/src/webgpu/util/device_pool.ts +++ b/src/webgpu/util/device_pool.ts @@ -22,33 +22,21 @@ class FeaturesNotSupported extends Error {} export class TestOOMedShouldAttemptGC extends Error {} export class DevicePool { - private holders: 'uninitialized' | 'failed' | DescriptorToHolderMap = 'uninitialized'; + private holders = new DescriptorToHolderMap(); + + async requestAdapter(recorder: TestCaseRecorder) { + const gpu = getGPU(recorder); + const adapter = await gpu.requestAdapter(); + assert(adapter !== null, 'requestAdapter returned null'); + return adapter; + } /** Acquire a device from the pool and begin the error scopes. */ async acquire( - recorder: TestCaseRecorder, + adapter: GPUAdapter, descriptor?: UncanonicalizedDeviceDescriptor ): Promise { - let errorMessage = ''; - if (this.holders === 'uninitialized') { - this.holders = new DescriptorToHolderMap(); - try { - await this.holders.getOrCreate(recorder, undefined); - } catch (ex) { - this.holders = 'failed'; - if (ex instanceof Error) { - errorMessage = ` with ${ex.name} "${ex.message}"`; - } - } - } - - assert( - this.holders !== 'failed', - `WebGPU device failed to initialize${errorMessage}; not retrying` - ); - - const holder = await this.holders.getOrCreate(recorder, descriptor); - + const holder = await this.holders.getOrCreate(adapter, descriptor); assert(holder.state === 'free', 'Device was in use on DevicePool.acquire'); holder.state = 'acquired'; holder.beginTestScope(); @@ -138,7 +126,7 @@ class DescriptorToHolderMap { * Throws SkipTestCase if devices with this descriptor are unsupported. */ async getOrCreate( - recorder: TestCaseRecorder, + adapter: GPUAdapter, uncanonicalizedDescriptor: UncanonicalizedDeviceDescriptor | undefined ): Promise { const [descriptor, key] = canonicalizeDescriptor(uncanonicalizedDescriptor); @@ -163,7 +151,7 @@ class DescriptorToHolderMap { // No existing item was found; add a new one. let value; try { - value = await DeviceHolder.create(recorder, descriptor); + value = await DeviceHolder.create(adapter, descriptor); } catch (ex) { if (ex instanceof FeaturesNotSupported) { this.unsupported.add(key); @@ -298,15 +286,14 @@ class DeviceHolder implements DeviceProvider { // Gets a device and creates a DeviceHolder. // If the device is lost, DeviceHolder.lost gets set. static async create( - recorder: TestCaseRecorder, + adapter: GPUAdapter, descriptor: CanonicalDeviceDescriptor | undefined ): Promise { - const gpu = getGPU(recorder); - const adapter = await gpu.requestAdapter(); - assert(adapter !== null, 'requestAdapter returned null'); + assert(adapter !== null, 'requestAdapter is null'); if (!supportsFeature(adapter, descriptor)) { throw new FeaturesNotSupported('One or more features are not supported'); } + const device = await adapter.requestDevice(descriptor); assert(device !== null, 'requestDevice returned null'); diff --git a/src/webgpu/util/floating_point.ts b/src/webgpu/util/floating_point.ts index ea7bb838d4ca..7887d82aaf70 100644 --- a/src/webgpu/util/floating_point.ts +++ b/src/webgpu/util/floating_point.ts @@ -12,7 +12,7 @@ import { f16, f32, isFloatType, - Scalar, + ScalarValue, ScalarType, toMatrix, toVector, @@ -1047,14 +1047,14 @@ export abstract class FPTraits { unreachable(`'refract' is not yet implemented for '${this.kind}'`); } - /** Version of absoluteErrorInterval that always returns the unboundedInterval */ - protected unboundedAbsoluteErrorInterval(_n: number, _error_range: number): FPInterval { - return this.constants().unboundedInterval; + /** Stub for absolute errors */ + protected unimplementedAbsoluteErrorInterval(_n: number, _error_range: number): FPInterval { + unreachable(`Absolute Error is not implement for '${this.kind}'`); } - /** Version of ulpInterval that always returns the unboundedInterval */ - protected unboundedUlpInterval(_n: number, _numULP: number): FPInterval { - return this.constants().unboundedInterval; + /** Stub for ULP errors */ + protected unimplementedUlpInterval(_n: number, _numULP: number): FPInterval { + unreachable(`ULP Error is not implement for '${this.kind}'`); } // Utilities - Defined by subclass @@ -1073,8 +1073,8 @@ export abstract class FPTraits { public abstract readonly flushSubnormal: (n: number) => number; /** @returns 1 * ULP: (number) */ public abstract readonly oneULP: (target: number, mode?: FlushMode) => number; - /** @returns a builder for converting numbers to Scalars */ - public abstract readonly scalarBuilder: (n: number) => Scalar; + /** @returns a builder for converting numbers to ScalarsValues */ + public abstract readonly scalarBuilder: (n: number) => ScalarValue; /** @returns a range of scalars for testing */ public abstract scalarRange(): readonly number[]; /** @returns a reduced range of scalars for testing */ @@ -5091,12 +5091,10 @@ class FPAbstractTraits extends FPTraits { public readonly sparseMatrixRange = sparseMatrixF64Range; // Framework - Fundamental Error Intervals - Overrides - public readonly absoluteErrorInterval = this.unboundedAbsoluteErrorInterval.bind(this); + public readonly absoluteErrorInterval = this.unimplementedAbsoluteErrorInterval.bind(this); // Should use FP.f32 instead public readonly correctlyRoundedInterval = this.correctlyRoundedIntervalImpl.bind(this); public readonly correctlyRoundedMatrix = this.correctlyRoundedMatrixImpl.bind(this); - public readonly ulpInterval = (n: number, numULP: number): FPInterval => { - return this.toInterval(kF32Traits.ulpInterval(n, numULP)); - }; + public readonly ulpInterval = this.unimplementedUlpInterval.bind(this); // Should use FP.f32 instead // Framework - API - Overrides public readonly absInterval = this.absIntervalImpl.bind(this); @@ -5120,7 +5118,7 @@ class FPAbstractTraits extends FPTraits { 'atan2Interval' ); public readonly atanhInterval = this.unimplementedScalarToInterval.bind(this, 'atanhInterval'); - public readonly ceilInterval = this.unimplementedScalarToInterval.bind(this, 'ceilInterval'); + public readonly ceilInterval = this.ceilIntervalImpl.bind(this); public readonly clampMedianInterval = this.clampMedianIntervalImpl.bind(this); public readonly clampMinMaxInterval = this.clampMinMaxIntervalImpl.bind(this); public readonly clampIntervals = [this.clampMedianInterval, this.clampMinMaxInterval]; @@ -5128,10 +5126,7 @@ class FPAbstractTraits extends FPTraits { public readonly coshInterval = this.unimplementedScalarToInterval.bind(this, 'coshInterval'); public readonly crossInterval = this.crossIntervalImpl.bind(this); public readonly degreesInterval = this.degreesIntervalImpl.bind(this); - public readonly determinantInterval = this.unimplementedMatrixToInterval.bind( - this, - 'determinantInterval' - ); + public readonly determinantInterval = this.determinantIntervalImpl.bind(this); public readonly distanceInterval = this.unimplementedDistance.bind(this); public readonly divisionInterval = ( x: number | FPInterval, diff --git a/src/webgpu/web_platform/worker/worker.spec.ts b/src/webgpu/web_platform/worker/worker.spec.ts index 0f34a58ddaa5..14fe135633c9 100644 --- a/src/webgpu/web_platform/worker/worker.spec.ts +++ b/src/webgpu/web_platform/worker/worker.spec.ts @@ -1,9 +1,13 @@ export const description = ` Tests WebGPU is available in a dedicated worker and a shared worker. -Note: The CTS test can be run respectively in a dedicated worker and a shared worker by -passing in worker=dedicated and worker=shared as a query parameter. These tests -are specifically to check that WebGPU is available in a dedicated worker and a shared worker. +Note: Any CTS test can be run in a worker by passing ?worker=dedicated, ?worker=shared, +?worker=service as a query parameter. The tests in this file are specifically to check +that WebGPU is available in each worker type. When run in combination with a ?worker flag, +they will test workers created from other workers (where APIs exist to do so). + +TODO[2]: Figure out how to make these tests run in service workers (not actually +important unless service workers gain the ability to launch other workers). `; import { Fixture } from '../../../common/framework/fixture.js'; @@ -12,24 +16,26 @@ import { assert } from '../../../common/util/util.js'; export const g = makeTestGroup(Fixture); -function isNode(): boolean { - return typeof process !== 'undefined' && process?.versions?.node !== undefined; -} +const isNode = typeof process !== 'undefined' && process?.versions?.node !== undefined; + +// [1]: we load worker_launcher dynamically because ts-node support +// is using commonjs which doesn't support import.meta. Further, +// we need to put the url in a string and pass the string to import +// otherwise typescript tries to parse the file which again, fails. +// worker_launcher.js is excluded in node.tsconfig.json. + +// [2]: That hack does not work in Service Workers. +const isServiceWorker = globalThis.constructor.name === 'ServiceWorkerGlobalScope'; g.test('dedicated_worker') .desc(`test WebGPU is available in dedicated workers and check for basic functionality`) .fn(async t => { - if (isNode()) { - t.skip('node does not support 100% compatible workers'); - return; - } - // Note: we load worker_launcher dynamically because ts-node support - // is using commonjs which doesn't support import.meta. Further, - // we need to put the url in a string add pass the string to import - // otherwise typescript tries to parse the file which again, fails. - // worker_launcher.js is excluded in node.tsconfig.json. + t.skipIf(isNode, 'node does not support 100% compatible workers'); + + t.skipIf(isServiceWorker, 'Service workers do not support this import() hack'); // [2] const url = './worker_launcher.js'; - const { launchDedicatedWorker } = await import(url); + const { launchDedicatedWorker } = await import(url); // [1] + const result = await launchDedicatedWorker(); assert(result.error === undefined, `should be no error from worker but was: ${result.error}`); }); @@ -37,17 +43,25 @@ g.test('dedicated_worker') g.test('shared_worker') .desc(`test WebGPU is available in shared workers and check for basic functionality`) .fn(async t => { - if (isNode()) { - t.skip('node does not support 100% compatible workers'); - return; - } - // Note: we load worker_launcher dynamically because ts-node support - // is using commonjs which doesn't support import.meta. Further, - // we need to put the url in a string add pass the string to import - // otherwise typescript tries to parse the file which again, fails. - // worker_launcher.js is excluded in node.tsconfig.json. + t.skipIf(isNode, 'node does not support 100% compatible workers'); + + t.skipIf(isServiceWorker, 'Service workers do not support this import() hack'); // [2] const url = './worker_launcher.js'; - const { launchSharedWorker } = await import(url); + const { launchSharedWorker } = await import(url); // [1] + const result = await launchSharedWorker(); assert(result.error === undefined, `should be no error from worker but was: ${result.error}`); }); + +g.test('service_worker') + .desc(`test WebGPU is available in service workers and check for basic functionality`) + .fn(async t => { + t.skipIf(isNode, 'node does not support 100% compatible workers'); + + t.skipIf(isServiceWorker, 'Service workers do not support this import() hack'); // [2] + const url = './worker_launcher.js'; + const { launchServiceWorker } = await import(url); // [1] + + const result = await launchServiceWorker(); + assert(result.error === undefined, `should be no error from worker but was: ${result.error}`); + }); diff --git a/src/webgpu/web_platform/worker/worker.ts b/src/webgpu/web_platform/worker/worker.ts index f3c907a4118a..033473d63a97 100644 --- a/src/webgpu/web_platform/worker/worker.ts +++ b/src/webgpu/web_platform/worker/worker.ts @@ -87,7 +87,7 @@ async function reportTestResults(this: MessagePort | Worker, ev: MessageEvent) { } self.onmessage = (ev: MessageEvent) => { - void reportTestResults.call(self, ev); + void reportTestResults.call(ev.source || self, ev); }; self.onconnect = (event: MessageEvent) => { diff --git a/src/webgpu/web_platform/worker/worker_launcher.ts b/src/webgpu/web_platform/worker/worker_launcher.ts index 0487e4ad38b4..4b1d31ae4921 100644 --- a/src/webgpu/web_platform/worker/worker_launcher.ts +++ b/src/webgpu/web_platform/worker/worker_launcher.ts @@ -1,3 +1,4 @@ +import { SkipTestCase } from '../../../common/framework/fixture.js'; import { getDefaultRequestAdapterOptions } from '../../../common/util/navigator_gpu.js'; export type TestResult = { @@ -5,6 +6,10 @@ export type TestResult = { }; export async function launchDedicatedWorker() { + if (typeof Worker === 'undefined') { + throw new SkipTestCase(`Worker undefined in context ${globalThis.constructor.name}`); + } + const selfPath = import.meta.url; const selfPathDir = selfPath.substring(0, selfPath.lastIndexOf('/')); const workerPath = selfPathDir + '/worker.js'; @@ -18,6 +23,10 @@ export async function launchDedicatedWorker() { } export async function launchSharedWorker() { + if (typeof SharedWorker === 'undefined') { + throw new SkipTestCase(`SharedWorker undefined in context ${globalThis.constructor.name}`); + } + const selfPath = import.meta.url; const selfPathDir = selfPath.substring(0, selfPath.lastIndexOf('/')); const workerPath = selfPathDir + '/worker.js'; @@ -33,3 +42,34 @@ export async function launchSharedWorker() { }); return await promise; } + +export async function launchServiceWorker() { + if (typeof navigator === 'undefined' || typeof navigator.serviceWorker === 'undefined') { + throw new SkipTestCase( + `navigator.serviceWorker undefined in context ${globalThis.constructor.name}` + ); + } + + const selfPath = import.meta.url; + const selfPathDir = selfPath.substring(0, selfPath.lastIndexOf('/')); + const serviceWorkerPath = selfPathDir + '/worker.js'; + const registration = await navigator.serviceWorker.register(serviceWorkerPath, { + type: 'module', + }); + await registration.update(); + + const promise = new Promise(resolve => { + navigator.serviceWorker.addEventListener( + 'message', + ev => { + resolve(ev.data as TestResult); + void registration.unregister(); + }, + { once: true } + ); + }); + registration.active?.postMessage({ + defaultRequestAdapterOptions: getDefaultRequestAdapterOptions(), + }); + return await promise; +} diff --git a/src/webgpu/webworker/.gitignore b/src/webgpu/webworker/.gitignore new file mode 100644 index 000000000000..8496277ad72e --- /dev/null +++ b/src/webgpu/webworker/.gitignore @@ -0,0 +1,2 @@ +# DIRECTORY RESERVED FOR GENERATED FILES. See gen_listings_and_webworkers. +* diff --git a/tools/gen_listings b/tools/gen_listings deleted file mode 100755 index 6c25622423a1..000000000000 --- a/tools/gen_listings +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env node - -// Crawl a suite directory (e.g. src/webgpu/) to generate a listing.js containing -// the listing of test files in the suite. - -require('../src/common/tools/setup-ts-in-node.js'); -require('../src/common/tools/gen_listings.ts'); diff --git a/tools/gen_listings_and_webworkers b/tools/gen_listings_and_webworkers new file mode 100755 index 000000000000..285df3657d2a --- /dev/null +++ b/tools/gen_listings_and_webworkers @@ -0,0 +1,8 @@ +#!/usr/bin/env node + +// Crawl a suite directory (e.g. src/webgpu/) to generate a listing.js containing +// the listing of test files in the suite, and some generated test files +// (like suite/serviceworker/**/*.spec.js). + +require('../src/common/tools/setup-ts-in-node.js'); +require('../src/common/tools/gen_listings_and_webworkers.ts');