From d4a925c48832d7d09ecde02246e14156f54a4c17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Beaufort?= Date: Mon, 29 Jan 2024 15:41:56 +0100 Subject: [PATCH] Add shared worker support --- docs/intro/developing.md | 5 +- src/common/internal/query/query.ts | 6 +- src/common/runtime/helper/options.ts | 14 +- .../runtime/helper/test_worker-worker.ts | 18 +- src/common/runtime/helper/test_worker.ts | 49 +++- src/common/runtime/standalone.ts | 12 +- src/common/runtime/wpt.ts | 15 +- src/common/tools/gen_wpt_cts_html.ts | 12 +- src/resources/cache/hashes.json | 214 +++++++++--------- .../cache/webgpu/shader/execution/bitcast.bin | Bin 2221448 -> 2221448 bytes src/webgpu/listing_meta.json | 159 ++++++------- src/webgpu/web_platform/worker/worker.spec.ts | 34 ++- src/webgpu/web_platform/worker/worker.ts | 20 +- .../web_platform/worker/worker_launcher.ts | 19 +- 14 files changed, 351 insertions(+), 226 deletions(-) diff --git a/docs/intro/developing.md b/docs/intro/developing.md index a942a6842d75..d8869f985b31 100644 --- a/docs/intro/developing.md +++ b/docs/intro/developing.md @@ -48,7 +48,7 @@ You can use this to preview how your test plan will appear. You can view different suites (webgpu, unittests, stress, etc.) or different subtrees of the test suite. -- `http://localhost:8080/standalone/` (defaults to `?runnow=0&worker=0&debug=0&q=webgpu:*`) +- `http://localhost:8080/standalone/` (defaults to `?runnow=0&debug=0&q=webgpu:*`) - `http://localhost:8080/standalone/?q=unittests:*` - `http://localhost:8080/standalone/?q=unittests:basic:*` @@ -56,7 +56,8 @@ 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=1` runs the tests on a Web Worker instead of the main thread. +- `worker=dedicated` 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. - `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/src/common/internal/query/query.ts b/src/common/internal/query/query.ts index 7c72a62f885a..ad7cf246e9d9 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 { optionEnabled } from '../../runtime/helper/options.js'; +import { optionString } from '../../runtime/helper/options.js'; import { assert, unreachable } from '../../util/util.js'; import { Expectation } from '../logging/result.js'; @@ -188,12 +188,12 @@ export function parseExpectationsForTestQuery( assert( expectationURL.pathname === wptURL.pathname, `Invalid expectation path ${expectationURL.pathname} -Expectation should be of the form path/to/cts.https.html?worker=0&q=suite:test_path:test_name:foo=1;bar=2;... +Expectation should be of the form path/to/cts.https.html?debug=0&q=suite:test_path:test_name:foo=1;bar=2;... ` ); const params = expectationURL.searchParams; - if (optionEnabled('worker', params) !== optionEnabled('worker', wptURL.searchParams)) { + if (optionString('worker', params) !== optionString('worker', wptURL.searchParams)) { continue; } diff --git a/src/common/runtime/helper/options.ts b/src/common/runtime/helper/options.ts index 80bd4bccc2f4..60c2d1069181 100644 --- a/src/common/runtime/helper/options.ts +++ b/src/common/runtime/helper/options.ts @@ -25,7 +25,7 @@ export function optionString( * The possible options for the tests. */ export interface CTSOptions { - worker: boolean; + worker?: 'dedicated' | 'shared' | ''; debug: boolean; compatibility: boolean; forceFallbackAdapter: boolean; @@ -34,7 +34,7 @@ export interface CTSOptions { } export const kDefaultCTSOptions: CTSOptions = { - worker: false, + worker: '', debug: true, compatibility: false, forceFallbackAdapter: false, @@ -61,7 +61,15 @@ export type OptionsInfos = Record; * Options to the CTS. */ export const kCTSOptionsInfo: OptionsInfos = { - worker: { description: 'run in a worker' }, + worker: { + description: 'run in a worker', + parser: optionString, + selectValueDescriptions: [ + { value: '', description: 'no worker' }, + { value: 'dedicated', description: 'dedicated worker' }, + { value: 'shared', description: 'shared worker' }, + ], + }, debug: { description: 'show more info' }, compatibility: { description: 'run in compatibility mode' }, forceFallbackAdapter: { description: 'pass forceFallbackAdapter: true to requestAdapter' }, diff --git a/src/common/runtime/helper/test_worker-worker.ts b/src/common/runtime/helper/test_worker-worker.ts index e8d187ea7e3d..caf6e7a1bc17 100644 --- a/src/common/runtime/helper/test_worker-worker.ts +++ b/src/common/runtime/helper/test_worker-worker.ts @@ -9,7 +9,7 @@ import { assert } from '../../util/util.js'; import { CTSOptions } from './options.js'; -// Should be DedicatedWorkerGlobalScope, but importing lib "webworker" conflicts with lib "dom". +// Should be WorkerGlobalScope, but importing lib "webworker" conflicts with lib "dom". /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ declare const self: any; @@ -17,7 +17,7 @@ const loader = new DefaultTestFileLoader(); setBaseResourcePath('../../../resources'); -self.onmessage = async (ev: MessageEvent) => { +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; @@ -44,5 +44,17 @@ self.onmessage = async (ev: MessageEvent) => { const [rec, result] = log.record(testcase.query.toString()); await testcase.run(rec, expectations); - self.postMessage({ query, result }); + this.postMessage({ query, result }); +} + +self.onmessage = (ev: MessageEvent) => { + void reportTestResults.call(self, ev); +}; + +self.onconnect = (event: MessageEvent) => { + const port = event.ports[0]; + + port.onmessage = (ev: MessageEvent) => { + void reportTestResults.call(port, ev); + }; }; diff --git a/src/common/runtime/helper/test_worker.ts b/src/common/runtime/helper/test_worker.ts index 9bbcab094671..a9ca4e2338c7 100644 --- a/src/common/runtime/helper/test_worker.ts +++ b/src/common/runtime/helper/test_worker.ts @@ -5,13 +5,13 @@ import { TestQueryWithExpectation } from '../../internal/query/query.js'; import { CTSOptions, kDefaultCTSOptions } from './options.js'; -export class TestWorker { +export class TestDedicatedWorker { private readonly ctsOptions: CTSOptions; private readonly worker: Worker; private readonly resolvers = new Map void>(); constructor(ctsOptions?: CTSOptions) { - this.ctsOptions = { ...(ctsOptions || kDefaultCTSOptions), ...{ worker: true } }; + 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'; @@ -47,3 +47,48 @@ export class TestWorker { rec.injectResult(workerResult); } } + +export class TestSharedWorker { + private readonly ctsOptions: CTSOptions; + private readonly port: MessagePort; + private readonly resolvers = new Map void>(); + + constructor(ctsOptions?: CTSOptions) { + this.ctsOptions = { ...(ctsOptions || kDefaultCTSOptions), ...{ worker: 'shared' } }; + 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); + + // 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 { + this.port.postMessage({ + query, + expectations, + ctsOptions: this.ctsOptions, + }); + const workerResult = await new Promise(resolve => { + this.resolvers.set(query, resolve); + }); + rec.injectResult(workerResult); + } +} diff --git a/src/common/runtime/standalone.ts b/src/common/runtime/standalone.ts index aaee30df6c5e..fa938c55a276 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 { TestWorker } from './helper/test_worker.js'; +import { TestDedicatedWorker, TestSharedWorker } from './helper/test_worker.js'; const rootQuerySpec = 'webgpu:*'; let promptBeforeReload = false; @@ -63,7 +63,9 @@ const logger = new Logger(); setBaseResourcePath('../out/resources'); -const worker = options.worker ? new TestWorker(options) : undefined; +const dedicatedWorker = + options.worker === 'dedicated' ? new TestDedicatedWorker(options) : undefined; +const sharedWorker = options.worker === 'shared' ? new TestSharedWorker(options) : undefined; const autoCloseOnPass = document.getElementById('autoCloseOnPass') as HTMLInputElement; const resultsVis = document.getElementById('resultsVis')!; @@ -176,8 +178,10 @@ function makeCaseHTML(t: TestTreeLeaf): VisualizedSubtree { const [rec, res] = logger.record(name); caseResult = res; - if (worker) { - await worker.run(rec, name); + if (dedicatedWorker) { + await dedicatedWorker.run(rec, name); + } else if (sharedWorker) { + await sharedWorker.run(rec, name); } else { await t.run(rec); } diff --git a/src/common/runtime/wpt.ts b/src/common/runtime/wpt.ts index d4a40081540e..aacd34b13e51 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 } from './helper/options.js'; -import { TestWorker } from './helper/test_worker.js'; +import { optionEnabled, optionString } from './helper/options.js'; +import { TestDedicatedWorker, TestSharedWorker } from './helper/test_worker.js'; // testharness.js API (https://web-platform-tests.org/writing-tests/testharness-api.html) declare interface WptTestObject { @@ -31,8 +31,9 @@ setup({ }); void (async () => { - const workerEnabled = optionEnabled('worker'); - const worker = workerEnabled ? new TestWorker() : undefined; + const workerString = optionString('worker'); + const dedicatedWorker = workerString === 'dedicated' ? new TestDedicatedWorker() : undefined; + const sharedWorker = workerString === 'shared' ? new TestSharedWorker() : undefined; globalTestConfig.unrollConstEvalLoops = optionEnabled('unroll_const_eval_loops'); @@ -63,8 +64,10 @@ void (async () => { const wpt_fn = async () => { const [rec, res] = log.record(name); - if (worker) { - await worker.run(rec, name, expectations); + if (dedicatedWorker) { + await dedicatedWorker.run(rec, name, expectations); + } else if (sharedWorker) { + await sharedWorker.run(rec, name, expectations); } else { await testcase.run(rec, expectations); } diff --git a/src/common/tools/gen_wpt_cts_html.ts b/src/common/tools/gen_wpt_cts_html.ts index 90c7cd4ef4c5..8293d6612671 100644 --- a/src/common/tools/gen_wpt_cts_html.ts +++ b/src/common/tools/gen_wpt_cts_html.ts @@ -35,15 +35,15 @@ where arguments.txt is a file containing a list of arguments prefixes to both ge in the expectations. The entire variant list generation runs *once per prefix*, so this multiplies the size of the variant list. - ?worker=0&q= - ?worker=1&q= + ?debug=0&q= + ?debug=1&q= and myexpectations.txt is a file containing a list of WPT paths to suppress, e.g.: - path/to/cts.https.html?worker=0&q=webgpu:a/foo:bar={"x":1} - path/to/cts.https.html?worker=1&q=webgpu:a/foo:bar={"x":1} + path/to/cts.https.html?debug=0&q=webgpu:a/foo:bar={"x":1} + path/to/cts.https.html?debug=1&q=webgpu:a/foo:bar={"x":1} - path/to/cts.https.html?worker=1&q=webgpu:a/foo:bar={"x":3} + path/to/cts.https.html?debug=1&q=webgpu:a/foo:bar={"x":3} `); process.exit(rc); } @@ -224,7 +224,7 @@ ${queryString}` } lines.push({ - urlQueryString: prefix + query.toString(), // "?worker=0&q=..." + urlQueryString: prefix + query.toString(), // "?debug=0&q=..." comment: useChunking ? `estimated: ${subtreeCounts?.totalTimeMS.toFixed(3)} ms` : undefined, }); diff --git a/src/resources/cache/hashes.json b/src/resources/cache/hashes.json index 791bd3a0354b..73df50c4d73f 100644 --- a/src/resources/cache/hashes.json +++ b/src/resources/cache/hashes.json @@ -1,109 +1,109 @@ { - "webgpu/shader/execution/binary/af_addition.bin": "6a22792d", - "webgpu/shader/execution/binary/af_logical.bin": "d124cf64", - "webgpu/shader/execution/binary/af_division.bin": "7d78cca7", - "webgpu/shader/execution/binary/af_matrix_addition.bin": "fd87a833", - "webgpu/shader/execution/binary/af_matrix_subtraction.bin": "814fc609", - "webgpu/shader/execution/binary/af_multiplication.bin": "5a2c3c94", - "webgpu/shader/execution/binary/af_remainder.bin": "f1a63570", - "webgpu/shader/execution/binary/af_subtraction.bin": "3ecadf73", - "webgpu/shader/execution/binary/f16_addition.bin": "6c64f032", - "webgpu/shader/execution/binary/f16_logical.bin": "3120fe75", - "webgpu/shader/execution/binary/f16_division.bin": "a432967b", - "webgpu/shader/execution/binary/f16_matrix_addition.bin": "42c4a69e", - "webgpu/shader/execution/binary/f16_matrix_matrix_multiplication.bin": "9a04c20", - "webgpu/shader/execution/binary/f16_matrix_scalar_multiplication.bin": "8c4dcf3c", - "webgpu/shader/execution/binary/f16_matrix_subtraction.bin": "755f369d", - "webgpu/shader/execution/binary/f16_matrix_vector_multiplication.bin": "eae889e3", - "webgpu/shader/execution/binary/f16_multiplication.bin": "53d2e0ea", - "webgpu/shader/execution/binary/f16_remainder.bin": "c0f8829e", - "webgpu/shader/execution/binary/f16_subtraction.bin": "d63e8b7b", - "webgpu/shader/execution/binary/f32_addition.bin": "7bd51700", - "webgpu/shader/execution/binary/f32_logical.bin": "72dfd230", - "webgpu/shader/execution/binary/f32_division.bin": "c93dbaa5", - "webgpu/shader/execution/binary/f32_matrix_addition.bin": "bb08a2c6", - "webgpu/shader/execution/binary/f32_matrix_matrix_multiplication.bin": "e61f22cf", - "webgpu/shader/execution/binary/f32_matrix_scalar_multiplication.bin": "a8c61bd4", - "webgpu/shader/execution/binary/f32_matrix_subtraction.bin": "82d727d", - "webgpu/shader/execution/binary/f32_matrix_vector_multiplication.bin": "1c21512", - "webgpu/shader/execution/binary/f32_multiplication.bin": "dadd324d", - "webgpu/shader/execution/binary/f32_remainder.bin": "6a3bac80", - "webgpu/shader/execution/binary/f32_subtraction.bin": "813f8e0d", - "webgpu/shader/execution/binary/i32_arithmetic.bin": "12b039ce", - "webgpu/shader/execution/binary/i32_comparison.bin": "dec54fb8", - "webgpu/shader/execution/binary/u32_arithmetic.bin": "548fc8ea", - "webgpu/shader/execution/binary/u32_comparison.bin": "62be0c6d", - "webgpu/shader/execution/abs.bin": "cf195671", - "webgpu/shader/execution/acos.bin": "7b18783a", - "webgpu/shader/execution/acosh.bin": "1f24550", - "webgpu/shader/execution/asin.bin": "9afbbed6", - "webgpu/shader/execution/asinh.bin": "e1c343ec", - "webgpu/shader/execution/atan.bin": "8457e2a8", - "webgpu/shader/execution/atan2.bin": "f20f1292", - "webgpu/shader/execution/atanh.bin": "dc1a948b", - "webgpu/shader/execution/bitcast.bin": "67023663", - "webgpu/shader/execution/ceil.bin": "f98273c3", - "webgpu/shader/execution/clamp.bin": "fb634e90", - "webgpu/shader/execution/cos.bin": "33cce38a", - "webgpu/shader/execution/cosh.bin": "1c55ac51", - "webgpu/shader/execution/cross.bin": "d5a28621", - "webgpu/shader/execution/degrees.bin": "4fcc3175", - "webgpu/shader/execution/determinant.bin": "4e335eb0", - "webgpu/shader/execution/distance.bin": "d39f063c", - "webgpu/shader/execution/dot.bin": "4feda0d8", - "webgpu/shader/execution/exp.bin": "4c948963", - "webgpu/shader/execution/exp2.bin": "454497e2", - "webgpu/shader/execution/faceForward.bin": "97413daf", - "webgpu/shader/execution/floor.bin": "7da41e10", - "webgpu/shader/execution/fma.bin": "65588609", - "webgpu/shader/execution/fract.bin": "47272979", - "webgpu/shader/execution/frexp.bin": "50c7d61a", - "webgpu/shader/execution/inverseSqrt.bin": "50261c42", - "webgpu/shader/execution/ldexp.bin": "1fb40fae", - "webgpu/shader/execution/length.bin": "738be1d5", - "webgpu/shader/execution/log.bin": "9c5e72c3", - "webgpu/shader/execution/log2.bin": "b2a40016", - "webgpu/shader/execution/max.bin": "85e864a8", - "webgpu/shader/execution/min.bin": "f9a02244", - "webgpu/shader/execution/mix.bin": "2b126c4f", - "webgpu/shader/execution/modf.bin": "6321456f", - "webgpu/shader/execution/normalize.bin": "5e1fab03", - "webgpu/shader/execution/pack2x16float.bin": "a0ee7786", - "webgpu/shader/execution/pow.bin": "94dbc1e8", - "webgpu/shader/execution/quantizeToF16.bin": "f9072ec0", - "webgpu/shader/execution/radians.bin": "bce17911", - "webgpu/shader/execution/reflect.bin": "f9f4128a", - "webgpu/shader/execution/refract.bin": "a1829a6e", - "webgpu/shader/execution/round.bin": "4e431ad7", - "webgpu/shader/execution/saturate.bin": "dea37ddb", - "webgpu/shader/execution/sign.bin": "830ec10", - "webgpu/shader/execution/sin.bin": "922531b5", - "webgpu/shader/execution/sinh.bin": "3193d989", - "webgpu/shader/execution/smoothstep.bin": "51503cb", - "webgpu/shader/execution/sqrt.bin": "f933e0d2", - "webgpu/shader/execution/step.bin": "ce02367d", - "webgpu/shader/execution/tan.bin": "b9a3a310", - "webgpu/shader/execution/tanh.bin": "98685dd3", - "webgpu/shader/execution/transpose.bin": "bef30077", - "webgpu/shader/execution/trunc.bin": "b8b5c091", - "webgpu/shader/execution/unpack2x16float.bin": "9343b29f", - "webgpu/shader/execution/unpack2x16snorm.bin": "e56ec75e", - "webgpu/shader/execution/unpack2x16unorm.bin": "26504819", - "webgpu/shader/execution/unpack4x8snorm.bin": "e550de72", - "webgpu/shader/execution/unpack4x8unorm.bin": "acdf694f", - "webgpu/shader/execution/unary/af_arithmetic.bin": "d371eefd", - "webgpu/shader/execution/unary/af_assignment.bin": "4cae15c1", - "webgpu/shader/execution/unary/bool_conversion.bin": "be4a17e6", - "webgpu/shader/execution/unary/f16_arithmetic.bin": "cf8bd6e9", - "webgpu/shader/execution/unary/f16_conversion.bin": "44ea8241", - "webgpu/shader/execution/unary/f32_arithmetic.bin": "e046d177", - "webgpu/shader/execution/unary/f32_conversion.bin": "9ef137d6", - "webgpu/shader/execution/unary/i32_arithmetic.bin": "44c3fd63", - "webgpu/shader/execution/unary/i32_complement.bin": "82e58655", - "webgpu/shader/execution/unary/i32_conversion.bin": "4b164846", - "webgpu/shader/execution/unary/u32_complement.bin": "51de4a0f", - "webgpu/shader/execution/unary/u32_conversion.bin": "659c2f08", - "webgpu/shader/execution/unary/ai_assignment.bin": "bf7d58b9", - "webgpu/shader/execution/binary/ai_arithmetic.bin": "7881600d", - "webgpu/shader/execution/unary/ai_arithmetic.bin": "eda6e030" + "webgpu/shader/execution/binary/af_addition.bin": "f9c25825", + "webgpu/shader/execution/binary/af_logical.bin": "c3c5c046", + "webgpu/shader/execution/binary/af_division.bin": "8eec7360", + "webgpu/shader/execution/binary/af_matrix_addition.bin": "92f5acd", + "webgpu/shader/execution/binary/af_matrix_subtraction.bin": "cf1920bc", + "webgpu/shader/execution/binary/af_multiplication.bin": "c3ca2d36", + "webgpu/shader/execution/binary/af_remainder.bin": "ef236c3e", + "webgpu/shader/execution/binary/af_subtraction.bin": "823c3d19", + "webgpu/shader/execution/binary/f16_addition.bin": "72625726", + "webgpu/shader/execution/binary/f16_logical.bin": "d20f2684", + "webgpu/shader/execution/binary/f16_division.bin": "865fb316", + "webgpu/shader/execution/binary/f16_matrix_addition.bin": "2908c1e6", + "webgpu/shader/execution/binary/f16_matrix_matrix_multiplication.bin": "dbc6dd4a", + "webgpu/shader/execution/binary/f16_matrix_scalar_multiplication.bin": "fff001f3", + "webgpu/shader/execution/binary/f16_matrix_subtraction.bin": "f6557db8", + "webgpu/shader/execution/binary/f16_matrix_vector_multiplication.bin": "7d0beef1", + "webgpu/shader/execution/binary/f16_multiplication.bin": "fe1eeb2f", + "webgpu/shader/execution/binary/f16_remainder.bin": "44c68db0", + "webgpu/shader/execution/binary/f16_subtraction.bin": "4d349e03", + "webgpu/shader/execution/binary/f32_addition.bin": "3d909f18", + "webgpu/shader/execution/binary/f32_logical.bin": "300cb917", + "webgpu/shader/execution/binary/f32_division.bin": "26126d0b", + "webgpu/shader/execution/binary/f32_matrix_addition.bin": "8e3b7347", + "webgpu/shader/execution/binary/f32_matrix_matrix_multiplication.bin": "eba8334f", + "webgpu/shader/execution/binary/f32_matrix_scalar_multiplication.bin": "5f633cc4", + "webgpu/shader/execution/binary/f32_matrix_subtraction.bin": "ee699077", + "webgpu/shader/execution/binary/f32_matrix_vector_multiplication.bin": "6e8e9044", + "webgpu/shader/execution/binary/f32_multiplication.bin": "9e8aa842", + "webgpu/shader/execution/binary/f32_remainder.bin": "44997694", + "webgpu/shader/execution/binary/f32_subtraction.bin": "7da0351c", + "webgpu/shader/execution/binary/i32_arithmetic.bin": "78991d8", + "webgpu/shader/execution/binary/i32_comparison.bin": "eeb5a624", + "webgpu/shader/execution/binary/u32_arithmetic.bin": "e317f38", + "webgpu/shader/execution/binary/u32_comparison.bin": "3bd52719", + "webgpu/shader/execution/abs.bin": "58d33fc0", + "webgpu/shader/execution/acos.bin": "8ab770e1", + "webgpu/shader/execution/acosh.bin": "1b797a55", + "webgpu/shader/execution/asin.bin": "49c3e54", + "webgpu/shader/execution/asinh.bin": "ec965820", + "webgpu/shader/execution/atan.bin": "13292f0c", + "webgpu/shader/execution/atan2.bin": "943937cf", + "webgpu/shader/execution/atanh.bin": "113723aa", + "webgpu/shader/execution/bitcast.bin": "49055551", + "webgpu/shader/execution/ceil.bin": "fc4d440", + "webgpu/shader/execution/clamp.bin": "f0590b61", + "webgpu/shader/execution/cos.bin": "dc6a6d3c", + "webgpu/shader/execution/cosh.bin": "682a8b93", + "webgpu/shader/execution/cross.bin": "c2cf537f", + "webgpu/shader/execution/degrees.bin": "b9044d85", + "webgpu/shader/execution/determinant.bin": "c872e66b", + "webgpu/shader/execution/distance.bin": "8df8d8a7", + "webgpu/shader/execution/dot.bin": "84aacdd9", + "webgpu/shader/execution/exp.bin": "1e815ae0", + "webgpu/shader/execution/exp2.bin": "ee9fd571", + "webgpu/shader/execution/faceForward.bin": "e2b2e81c", + "webgpu/shader/execution/floor.bin": "9d437a66", + "webgpu/shader/execution/fma.bin": "352b140", + "webgpu/shader/execution/fract.bin": "95a1650d", + "webgpu/shader/execution/frexp.bin": "c9ed5769", + "webgpu/shader/execution/inverseSqrt.bin": "8a275a8d", + "webgpu/shader/execution/ldexp.bin": "cb51dbe1", + "webgpu/shader/execution/length.bin": "53468ea4", + "webgpu/shader/execution/log.bin": "33bef86d", + "webgpu/shader/execution/log2.bin": "42fc6f07", + "webgpu/shader/execution/max.bin": "33b63886", + "webgpu/shader/execution/min.bin": "f4e85c7", + "webgpu/shader/execution/mix.bin": "b7346332", + "webgpu/shader/execution/modf.bin": "b291939c", + "webgpu/shader/execution/normalize.bin": "8d42f4e4", + "webgpu/shader/execution/pack2x16float.bin": "32836353", + "webgpu/shader/execution/pow.bin": "5fd2851d", + "webgpu/shader/execution/quantizeToF16.bin": "7a1878ee", + "webgpu/shader/execution/radians.bin": "dbb58186", + "webgpu/shader/execution/reflect.bin": "9f1132c5", + "webgpu/shader/execution/refract.bin": "508a9b82", + "webgpu/shader/execution/round.bin": "47ccb377", + "webgpu/shader/execution/saturate.bin": "771426ff", + "webgpu/shader/execution/sign.bin": "6b04f125", + "webgpu/shader/execution/sin.bin": "8e2495ec", + "webgpu/shader/execution/sinh.bin": "77ab8cf1", + "webgpu/shader/execution/smoothstep.bin": "bdd40525", + "webgpu/shader/execution/sqrt.bin": "d6b16a43", + "webgpu/shader/execution/step.bin": "34fd45ba", + "webgpu/shader/execution/tan.bin": "7df2e6b4", + "webgpu/shader/execution/tanh.bin": "e303ee3c", + "webgpu/shader/execution/transpose.bin": "985b9dd0", + "webgpu/shader/execution/trunc.bin": "b244b3d9", + "webgpu/shader/execution/unpack2x16float.bin": "c1ebb8d5", + "webgpu/shader/execution/unpack2x16snorm.bin": "f7fd89e", + "webgpu/shader/execution/unpack2x16unorm.bin": "35e0330e", + "webgpu/shader/execution/unpack4x8snorm.bin": "3d4ca4cd", + "webgpu/shader/execution/unpack4x8unorm.bin": "985e1f9a", + "webgpu/shader/execution/unary/af_arithmetic.bin": "fab31dec", + "webgpu/shader/execution/unary/af_assignment.bin": "af1899", + "webgpu/shader/execution/unary/bool_conversion.bin": "c4e6e40c", + "webgpu/shader/execution/unary/f16_arithmetic.bin": "db964478", + "webgpu/shader/execution/unary/f16_conversion.bin": "df65cc9a", + "webgpu/shader/execution/unary/f32_arithmetic.bin": "bd022e24", + "webgpu/shader/execution/unary/f32_conversion.bin": "ff00ace3", + "webgpu/shader/execution/unary/i32_arithmetic.bin": "239e3b46", + "webgpu/shader/execution/unary/i32_complement.bin": "81fe7e5b", + "webgpu/shader/execution/unary/i32_conversion.bin": "24deb50a", + "webgpu/shader/execution/unary/u32_complement.bin": "37ba2547", + "webgpu/shader/execution/unary/u32_conversion.bin": "f26f8c3a", + "webgpu/shader/execution/unary/ai_assignment.bin": "46ee1c6f", + "webgpu/shader/execution/binary/ai_arithmetic.bin": "aa09a4bc", + "webgpu/shader/execution/unary/ai_arithmetic.bin": "6e2d927f" } \ No newline at end of file diff --git a/src/resources/cache/webgpu/shader/execution/bitcast.bin b/src/resources/cache/webgpu/shader/execution/bitcast.bin index 3c24c88e1ffbc42f87639912bacab411154e6d63..ab435f3902a6e2124845cfba3625a2184be02b02 100644 GIT binary patch delta 152 zcmWN=yAgsw6hP5g1OxZN delta 151 zcmWN=#|eNy002SEIp?e`T!C`nL(36-ScKLj?!X++t{gm9p}yZH#V& { if (isNode()) { t.skip('node does not support 100% compatible workers'); @@ -29,7 +29,25 @@ g.test('worker') // otherwise typescript tries to parse the file which again, fails. // worker_launcher.js is excluded in node.tsconfig.json. const url = './worker_launcher.js'; - const { launchWorker } = await import(url); - const result = await launchWorker(); + const { launchDedicatedWorker } = await import(url); + const result = await launchDedicatedWorker(); + assert(result.error === undefined, `should be no error from worker but was: ${result.error}`); + }); + +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. + const url = './worker_launcher.js'; + const { launchSharedWorker } = await import(url); + const result = await launchSharedWorker(); 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 a3cf8064e26a..f3c907a4118a 100644 --- a/src/webgpu/web_platform/worker/worker.ts +++ b/src/webgpu/web_platform/worker/worker.ts @@ -1,6 +1,10 @@ import { getGPU, setDefaultRequestAdapterOptions } from '../../../common/util/navigator_gpu.js'; import { assert, objectEquals, iterRange } from '../../../common/util/util.js'; +// Should be WorkerGlobalScope, but importing lib "webworker" conflicts with lib "dom". +/* eslint-disable-next-line @typescript-eslint/no-explicit-any */ +declare const self: any; + async function basicTest() { const adapter = await getGPU(null).requestAdapter(); assert(adapter !== null, 'Failed to get adapter.'); @@ -68,7 +72,7 @@ async function basicTest() { device.destroy(); } -self.onmessage = async (ev: MessageEvent) => { +async function reportTestResults(this: MessagePort | Worker, ev: MessageEvent) { const defaultRequestAdapterOptions: GPURequestAdapterOptions = ev.data.defaultRequestAdapterOptions; setDefaultRequestAdapterOptions(defaultRequestAdapterOptions); @@ -79,5 +83,17 @@ self.onmessage = async (ev: MessageEvent) => { } catch (err: unknown) { error = (err as Error).toString(); } - self.postMessage({ error }); + this.postMessage({ error }); +} + +self.onmessage = (ev: MessageEvent) => { + void reportTestResults.call(self, ev); +}; + +self.onconnect = (event: MessageEvent) => { + const port = event.ports[0]; + + port.onmessage = (ev: MessageEvent) => { + void reportTestResults.call(port, ev); + }; }; diff --git a/src/webgpu/web_platform/worker/worker_launcher.ts b/src/webgpu/web_platform/worker/worker_launcher.ts index 72059eb99fda..0487e4ad38b4 100644 --- a/src/webgpu/web_platform/worker/worker_launcher.ts +++ b/src/webgpu/web_platform/worker/worker_launcher.ts @@ -4,7 +4,7 @@ export type TestResult = { error: String | undefined; }; -export async function launchWorker() { +export async function launchDedicatedWorker() { const selfPath = import.meta.url; const selfPathDir = selfPath.substring(0, selfPath.lastIndexOf('/')); const workerPath = selfPathDir + '/worker.js'; @@ -16,3 +16,20 @@ export async function launchWorker() { worker.postMessage({ defaultRequestAdapterOptions: getDefaultRequestAdapterOptions() }); return await promise; } + +export async function launchSharedWorker() { + const selfPath = import.meta.url; + const selfPathDir = selfPath.substring(0, selfPath.lastIndexOf('/')); + const workerPath = selfPathDir + '/worker.js'; + const worker = new SharedWorker(workerPath, { type: 'module' }); + + const port = worker.port; + const promise = new Promise(resolve => { + port.addEventListener('message', ev => resolve(ev.data as TestResult), { once: true }); + }); + port.start(); + port.postMessage({ + defaultRequestAdapterOptions: getDefaultRequestAdapterOptions(), + }); + return await promise; +}