Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebNN: Enable in SharedWorker and ServiceWorker contexts #50976

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 6 additions & 8 deletions interfaces/webnn.idl
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ dictionary MLContextOptions {
MLPowerPreference powerPreference = "default";
};

[SecureContext, Exposed=(Window, DedicatedWorker)]
interface ML {
[SecureContext, Exposed = (Window, Worker)] interface ML {
Promise<MLContext> createContext(optional MLContextOptions options = {});
Promise<MLContext> createContext(GPUDevice gpuDevice);
};
Expand All @@ -31,8 +30,7 @@ dictionary MLContextLostInfo {
DOMString message;
};

[SecureContext, Exposed=(Window, DedicatedWorker)]
interface MLContext {
[SecureContext, Exposed = (Window, Worker)] interface MLContext {
undefined dispatch(MLGraph graph, MLNamedTensors inputs, MLNamedTensors outputs);

Promise<MLTensor> createTensor(MLTensorDescriptor descriptor);
Expand Down Expand Up @@ -71,7 +69,7 @@ dictionary MLSingleInputSupportLimits {
MLSupportLimits output;
};

[SecureContext, Exposed=(Window, DedicatedWorker)]
[SecureContext, Exposed=(Window, Worker)]
interface MLGraph {
undefined destroy();
};
Expand All @@ -97,7 +95,7 @@ dictionary MLOperandDescriptor {
required sequence<[EnforceRange] unsigned long> shape;
};

[SecureContext, Exposed=(Window, DedicatedWorker)]
[SecureContext, Exposed=(Window, Worker)]
interface MLOperand {
readonly attribute MLOperandDataType dataType;
readonly attribute FrozenArray<unsigned long> shape;
Expand All @@ -114,7 +112,7 @@ dictionary MLTensorDescriptor : MLOperandDescriptor {
boolean writable = false;
};

[SecureContext, Exposed=(Window, DedicatedWorker)]
[SecureContext, Exposed=(Window, Worker)]
interface MLTensor {
readonly attribute MLOperandDataType dataType;
readonly attribute FrozenArray<unsigned long> shape;
Expand All @@ -126,7 +124,7 @@ interface MLTensor {

typedef record<USVString, MLOperand> MLNamedOperands;

[SecureContext, Exposed=(Window, DedicatedWorker)]
[SecureContext, Exposed=(Window, Worker)]
interface MLGraphBuilder {
// Construct the graph builder from the context.
constructor(MLContext context);
Expand Down
26 changes: 14 additions & 12 deletions webnn/conformance_tests/byob_readtensor.https.any.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: title=test WebNN API tensor operations
// META: global=window,dedicatedworker
// META: global=window,worker
// META: variant=?cpu
// META: variant=?gpu
// META: variant=?npu
Expand Down Expand Up @@ -94,22 +94,24 @@ promise_test(async () => {
assert_array_equals(new Uint32Array(arrayBuffer), testContents);
}, `readTensor() with an ArrayBuffer`);

promise_test(async () => {
const sharedArrayBuffer = new SharedArrayBuffer(testContents.byteLength);
if ('SharedArrayBuffer' in globalThis) {
promise_test(async () => {
const sharedArrayBuffer = new SharedArrayBuffer(testContents.byteLength);

await mlContext.readTensor(mlTensor, sharedArrayBuffer);
await mlContext.readTensor(mlTensor, sharedArrayBuffer);

assert_array_equals(new Uint32Array(sharedArrayBuffer), testContents);
}, `readTensor() with a SharedArrayBuffer`);
assert_array_equals(new Uint32Array(sharedArrayBuffer), testContents);
}, `readTensor() with a SharedArrayBuffer`);

promise_test(async () => {
const sharedArrayBuffer = new SharedArrayBuffer(testContents.byteLength);
const typedArray = new Uint32Array(sharedArrayBuffer);
promise_test(async () => {
const sharedArrayBuffer = new SharedArrayBuffer(testContents.byteLength);
const typedArray = new Uint32Array(sharedArrayBuffer);

await mlContext.readTensor(mlTensor, typedArray);
await mlContext.readTensor(mlTensor, typedArray);

assert_array_equals(typedArray, testContents);
}, `readTensor() with a typeArray from a SharedArrayBuffer`);
assert_array_equals(typedArray, testContents);
}, `readTensor() with a typeArray from a SharedArrayBuffer`);
}

promise_test(async () => {
// Create a slightly larger ArrayBuffer and set up the TypedArray at an
Expand Down
2 changes: 1 addition & 1 deletion webnn/conformance_tests/identity.https.any.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: title=test WebNN API element-wise identity operation
// META: global=window,dedicatedworker
// META: global=window,worker
// META: variant=?cpu
// META: variant=?gpu
// META: variant=?npu
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: title=test that input tensors are not modified during a call to dispatch()
// META: global=window,dedicatedworker
// META: global=window,worker
// META: variant=?cpu
// META: variant=?gpu
// META: variant=?npu
Expand Down
2 changes: 1 addition & 1 deletion webnn/conformance_tests/parallel-dispatch.https.any.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: title=test parallel WebNN API dispatch calls
// META: global=window,dedicatedworker
// META: global=window,worker
// META: variant=?cpu
// META: variant=?gpu
// META: variant=?npu
Expand Down
2 changes: 1 addition & 1 deletion webnn/conformance_tests/scalars.https.any.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: title=test that scalar values work as expected
// META: global=window,dedicatedworker
// META: global=window,worker
// META: variant=?cpu
// META: variant=?gpu
// META: variant=?npu
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: title=test WebNN API constant with shared array buffer
// META: global=window,dedicatedworker
// META: global=window,dedicatedworker,serviceworker
// META: variant=?cpu
// META: variant=?gpu
// META: variant=?npu
Expand Down
2 changes: 1 addition & 1 deletion webnn/conformance_tests/subgraph.https.any.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: title=test WebNN API subgraph with multiple operations
// META: global=window,dedicatedworker
// META: global=window,worker
// META: variant=?cpu
// META: variant=?gpu
// META: variant=?npu
Expand Down
80 changes: 41 additions & 39 deletions webnn/conformance_tests/tensor.https.any.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: title=test WebNN API tensor operations
// META: global=window,dedicatedworker
// META: global=window,worker
// META: variant=?cpu
// META: variant=?gpu
// META: variant=?npu
Expand Down Expand Up @@ -175,44 +175,46 @@ const testWriteTensor = (testName) => {
}
});

promise_test(async () => {
const tensorDescriptor = {
dataType: 'int32',
shape: [4],
readable: true,
writable: true,
};
const tensorByteLength = sizeOfDescriptor(tensorDescriptor);

// Required to use SharedArrayBuffer.
assert_true(
self.crossOriginIsolated,
'The page is served with COOP and COEP, it should be cross-origin-isolated.');

let arrayBuffer = new ArrayBuffer(tensorByteLength);
let arrayBufferView = new Int32Array(arrayBuffer);
arrayBufferView.fill(7);

let sharedArrayBuffer = new SharedArrayBuffer(tensorByteLength);
let sharedArrayBufferView = new Int32Array(sharedArrayBuffer);
sharedArrayBufferView.fill(7);

const tensors = await Promise.all([
mlContext.createTensor(tensorDescriptor),
mlContext.createTensor(tensorDescriptor),
mlContext.createTensor(tensorDescriptor),
mlContext.createTensor(tensorDescriptor)
]);

mlContext.writeTensor(tensors[0], arrayBuffer);
mlContext.writeTensor(tensors[2], arrayBufferView);
mlContext.writeTensor(tensors[1], sharedArrayBuffer);
mlContext.writeTensor(tensors[3], sharedArrayBufferView);

await Promise.all(tensors.map(async (tensor) => {
assert_tensor_data_equals(mlContext, tensor, arrayBufferView);
}));
}, `${testName} / write with different kinds of buffers`);
if ('SharedArrayBuffer' in globalThis) {
promise_test(async () => {
const tensorDescriptor = {
dataType: 'int32',
shape: [4],
readable: true,
writable: true,
};
const tensorByteLength = sizeOfDescriptor(tensorDescriptor);

// Required to use SharedArrayBuffer.
assert_true(
self.crossOriginIsolated,
'The page is served with COOP and COEP, it should be cross-origin-isolated.');

let arrayBuffer = new ArrayBuffer(tensorByteLength);
let arrayBufferView = new Int32Array(arrayBuffer);
arrayBufferView.fill(7);

let sharedArrayBuffer = new SharedArrayBuffer(tensorByteLength);
let sharedArrayBufferView = new Int32Array(sharedArrayBuffer);
sharedArrayBufferView.fill(7);

const tensors = await Promise.all([
mlContext.createTensor(tensorDescriptor),
mlContext.createTensor(tensorDescriptor),
mlContext.createTensor(tensorDescriptor),
mlContext.createTensor(tensorDescriptor)
]);

mlContext.writeTensor(tensors[0], arrayBuffer);
mlContext.writeTensor(tensors[2], arrayBufferView);
mlContext.writeTensor(tensors[1], sharedArrayBuffer);
mlContext.writeTensor(tensors[3], sharedArrayBufferView);

await Promise.all(tensors.map(async (tensor) => {
assert_tensor_data_equals(mlContext, tensor, arrayBufferView);
}));
}, `${testName} / write with different kinds of buffers`);
}

promise_test(async () => {
const tensorDescriptor = {
Expand Down
2 changes: 1 addition & 1 deletion webnn/idlharness.https.any.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// META: global=window,dedicatedworker
// META: global=window,worker
// META: script=/resources/WebIDLParser.js
// META: script=/resources/idlharness.js
// META: script=./resources/utils.js
Expand Down
2 changes: 1 addition & 1 deletion webnn/validation_tests/build-more-than-once.https.any.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: title=ensure MLMLGraphBuilder may build at most one MLGraph
// META: global=window,dedicatedworker
// META: global=window,worker
// META: variant=?cpu
// META: variant=?gpu
// META: variant=?npu
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: title=ensure MLGraphBuilder.constant() handles buffers which change
// META: global=window,dedicatedworker
// META: global=window,worker
// META: variant=?cpu
// META: variant=?gpu
// META: variant=?npu
Expand Down
50 changes: 28 additions & 22 deletions webnn/validation_tests/constant.https.any.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: title=validation tests for WebNN API constant interface
// META: global=window,dedicatedworker
// META: global=window,worker
// META: variant=?cpu
// META: variant=?gpu
// META: variant=?npu
Expand Down Expand Up @@ -128,8 +128,6 @@ tests.forEach(
const builder = new MLGraphBuilder(context);
const buffer = new ArrayBuffer(test.buffer.byteLength);
const bufferView = new test.buffer.type(buffer);
const sharedBuffer = new SharedArrayBuffer(test.buffer.byteLength);
const sharedBufferView = new test.buffer.type(sharedBuffer);

if (test.viewTestOnly === undefined || test.viewTestOnly === false) {
// Test building constant from ArrayBuffer.
Expand All @@ -141,15 +139,19 @@ tests.forEach(
assert_throws_js(
TypeError, () => builder.constant(test.descriptor, buffer));
}
// Test building constant from SharedArrayBuffer.
if (test.output) {
const constantOperand =
builder.constant(test.descriptor, sharedBuffer);
assert_equals(constantOperand.dataType, test.output.dataType);
assert_array_equals(constantOperand.shape, test.output.shape);
} else {
assert_throws_js(
TypeError, () => builder.constant(test.descriptor, sharedBuffer));
if ('SharedArrayBuffer' in globalThis) {
// Test building constant from SharedArrayBuffer.
const sharedBuffer = new SharedArrayBuffer(test.buffer.byteLength);
if (test.output) {
const constantOperand =
builder.constant(test.descriptor, sharedBuffer);
assert_equals(constantOperand.dataType, test.output.dataType);
assert_array_equals(constantOperand.shape, test.output.shape);
} else {
assert_throws_js(
TypeError,
() => builder.constant(test.descriptor, sharedBuffer));
}
}
}

Expand All @@ -162,15 +164,19 @@ tests.forEach(
assert_throws_js(
TypeError, () => builder.constant(test.descriptor, bufferView));
}
// Test building constant from shared ArrayBufferView.
if (test.output) {
const constantOperand =
builder.constant(test.descriptor, sharedBufferView);
assert_equals(constantOperand.dataType, test.output.dataType);
assert_array_equals(constantOperand.shape, test.output.shape);
} else {
assert_throws_js(
TypeError,
() => builder.constant(test.descriptor, sharedBufferView));
if ('SharedArrayBuffer' in globalThis) {
// Test building constant from shared ArrayBufferView.
const sharedBuffer = new SharedArrayBuffer(test.buffer.byteLength);
const sharedBufferView = new test.buffer.type(sharedBuffer);
if (test.output) {
const constantOperand =
builder.constant(test.descriptor, sharedBufferView);
assert_equals(constantOperand.dataType, test.output.dataType);
assert_array_equals(constantOperand.shape, test.output.shape);
} else {
assert_throws_js(
TypeError,
() => builder.constant(test.descriptor, sharedBufferView));
}
}
}, test.name));
2 changes: 1 addition & 1 deletion webnn/validation_tests/createContext.https.any.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: title=validation tests for WebNN API createContext()
// META: global=window,dedicatedworker
// META: global=window,worker
// META: variant=?cpu
// META: variant=?gpu
// META: variant=?npu
Expand Down
2 changes: 1 addition & 1 deletion webnn/validation_tests/destroyContext.https.any.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// META: timeout=long
// META: title=validation tests for WebNN API MLContext::destroy()
// META: global=window,dedicatedworker
// META: global=window,worker
// META: variant=?cpu
// META: variant=?gpu
// META: variant=?npu
Expand Down
2 changes: 1 addition & 1 deletion webnn/validation_tests/destroyGraph.https.any.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// META: timeout=long
// META: title=validation tests for WebNN API MLContext::destroy()
// META: global=window,dedicatedworker
// META: global=window,worker
// META: variant=?cpu
// META: variant=?gpu
// META: variant=?npu
Expand Down
2 changes: 1 addition & 1 deletion webnn/validation_tests/input.https.any.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: title=validation tests for WebNN API input interface
// META: global=window,dedicatedworker
// META: global=window,worker
// META: variant=?cpu
// META: variant=?gpu
// META: variant=?npu
Expand Down
2 changes: 1 addition & 1 deletion webnn/validation_tests/invalid-rank.https.any.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: title=ensure an MLOperand cannot be created with an invalid rank
// META: global=window,dedicatedworker
// META: global=window,worker
// META: variant=?cpu
// META: variant=?gpu
// META: variant=?npu
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: title=validation tests for pooling and reduction operators keep dimensions
// META: global=window,dedicatedworker
// META: global=window,worker
// META: variant=?cpu
// META: variant=?gpu
// META: variant=?npu
Expand Down
2 changes: 1 addition & 1 deletion webnn/validation_tests/unprintableNames.https.any.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// META: title=test graph inputs/outputs with unprintable names
// META: global=window,dedicatedworker
// META: global=window,worker
// META: variant=?cpu
// META: variant=?gpu
// META: variant=?npu
Expand Down
Loading